/*
* Botan 1.10.2 Amalgamation
* (C) 1999-2011 Jack Lloyd and others
*
* Distributed under the terms of the Botan license
*/

#include "botan.h"
#include <deque>

#ifdef Q_OS_WIN
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif


namespace Botan {

/**
* Represents a DLL or shared object
*/
class Dynamically_Loaded_Library
   {
   public:
      /**
      * Load a DLL (or fail with an exception)
      * @param lib_name name or path to a library
      *
      * If you don't use a full path, the search order will be defined
      * by whatever the system linker does by default. Always using fully
      * qualified pathnames can help prevent code injection attacks (eg
      * via manipulation of LD_LIBRARY_PATH on Linux)
      */
      Dynamically_Loaded_Library(const std::string& lib_name);

      /**
      * Unload the DLL
      * @warning Any pointers returned by resolve()/resolve_symbol()
      * should not be used after this destructor runs.
      */
      ~Dynamically_Loaded_Library();

      /**
      * Load a symbol (or fail with an exception)
      * @param symbol names the symbol to load
      * @return address of the loaded symbol
      */
      void* resolve_symbol(const std::string& symbol);

      /**
      * Convenience function for casting symbol to the right type
      * @param symbol names the symbol to load
      * @return address of the loaded symbol
      */
      template<typename T>
      T resolve(const std::string& symbol)
         {
#if defined(__GNUC__) && __GNUC__ < 4
         return (T)(resolve_symbol(symbol));
#else
         return reinterpret_cast<T>(resolve_symbol(symbol));
#endif
         }

   private:
      Dynamically_Loaded_Library(const Dynamically_Loaded_Library&);
      Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&);

      std::string lib_name;
      void* lib;
   };

}

#ifdef Q_OS_WIN
namespace Botan {

/**
* Win32 Entropy Source
*/
class Win32_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "Win32 Statistics"; }
      void poll(Entropy_Accumulator& accum);
   };

}
#endif

namespace Botan {

/**
* Fake SIMD, using plain scalar operations
* Often still faster than iterative on superscalar machines
*/
class SIMD_Scalar
   {
   public:
      static bool enabled() { return true; }

      SIMD_Scalar(const u32bit B[4])
         {
         R0 = B[0];
         R1 = B[1];
         R2 = B[2];
         R3 = B[3];
         }

      SIMD_Scalar(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
         {
         R0 = B0;
         R1 = B1;
         R2 = B2;
         R3 = B3;
         }

      SIMD_Scalar(u32bit B)
         {
         R0 = B;
         R1 = B;
         R2 = B;
         R3 = B;
         }

      static SIMD_Scalar load_le(const void* in)
         {
         const byte* in_b = static_cast<const byte*>(in);
         return SIMD_Scalar(Botan::load_le<u32bit>(in_b, 0),
                            Botan::load_le<u32bit>(in_b, 1),
                            Botan::load_le<u32bit>(in_b, 2),
                            Botan::load_le<u32bit>(in_b, 3));
         }

      static SIMD_Scalar load_be(const void* in)
         {
         const byte* in_b = static_cast<const byte*>(in);
         return SIMD_Scalar(Botan::load_be<u32bit>(in_b, 0),
                            Botan::load_be<u32bit>(in_b, 1),
                            Botan::load_be<u32bit>(in_b, 2),
                            Botan::load_be<u32bit>(in_b, 3));
         }

      void store_le(byte out[]) const
         {
         Botan::store_le(out, R0, R1, R2, R3);
         }

      void store_be(byte out[]) const
         {
         Botan::store_be(out, R0, R1, R2, R3);
         }

      void rotate_left(size_t rot)
         {
         R0 = Botan::rotate_left(R0, rot);
         R1 = Botan::rotate_left(R1, rot);
         R2 = Botan::rotate_left(R2, rot);
         R3 = Botan::rotate_left(R3, rot);
         }

      void rotate_right(size_t rot)
         {
         R0 = Botan::rotate_right(R0, rot);
         R1 = Botan::rotate_right(R1, rot);
         R2 = Botan::rotate_right(R2, rot);
         R3 = Botan::rotate_right(R3, rot);
         }

      void operator+=(const SIMD_Scalar& other)
         {
         R0 += other.R0;
         R1 += other.R1;
         R2 += other.R2;
         R3 += other.R3;
         }

      SIMD_Scalar operator+(const SIMD_Scalar& other) const
         {
         return SIMD_Scalar(R0 + other.R0,
                            R1 + other.R1,
                            R2 + other.R2,
                            R3 + other.R3);
         }

      void operator-=(const SIMD_Scalar& other)
         {
         R0 -= other.R0;
         R1 -= other.R1;
         R2 -= other.R2;
         R3 -= other.R3;
         }

      SIMD_Scalar operator-(const SIMD_Scalar& other) const
         {
         return SIMD_Scalar(R0 - other.R0,
                            R1 - other.R1,
                            R2 - other.R2,
                            R3 - other.R3);
         }

      void operator^=(const SIMD_Scalar& other)
         {
         R0 ^= other.R0;
         R1 ^= other.R1;
         R2 ^= other.R2;
         R3 ^= other.R3;
         }

      SIMD_Scalar operator^(const SIMD_Scalar& other) const
         {
         return SIMD_Scalar(R0 ^ other.R0,
                            R1 ^ other.R1,
                            R2 ^ other.R2,
                            R3 ^ other.R3);
         }

      void operator|=(const SIMD_Scalar& other)
         {
         R0 |= other.R0;
         R1 |= other.R1;
         R2 |= other.R2;
         R3 |= other.R3;
         }

      SIMD_Scalar operator&(const SIMD_Scalar& other)
         {
         return SIMD_Scalar(R0 & other.R0,
                            R1 & other.R1,
                            R2 & other.R2,
                            R3 & other.R3);
         }

      void operator&=(const SIMD_Scalar& other)
         {
         R0 &= other.R0;
         R1 &= other.R1;
         R2 &= other.R2;
         R3 &= other.R3;
         }

      SIMD_Scalar operator<<(size_t shift) const
         {
         return SIMD_Scalar(R0 << shift,
                            R1 << shift,
                            R2 << shift,
                            R3 << shift);
         }

      SIMD_Scalar operator>>(size_t shift) const
         {
         return SIMD_Scalar(R0 >> shift,
                            R1 >> shift,
                            R2 >> shift,
                            R3 >> shift);
         }

      SIMD_Scalar operator~() const
         {
         return SIMD_Scalar(~R0, ~R1, ~R2, ~R3);
         }

      // (~reg) & other
      SIMD_Scalar andc(const SIMD_Scalar& other)
         {
         return SIMD_Scalar(~R0 & other.R0,
                            ~R1 & other.R1,
                            ~R2 & other.R2,
                            ~R3 & other.R3);
         }

      SIMD_Scalar bswap() const
         {
         return SIMD_Scalar(reverse_bytes(R0),
                            reverse_bytes(R1),
                            reverse_bytes(R2),
                            reverse_bytes(R3));
         }

      static void transpose(SIMD_Scalar& B0, SIMD_Scalar& B1,
                            SIMD_Scalar& B2, SIMD_Scalar& B3)
         {
         SIMD_Scalar T0(B0.R0, B1.R0, B2.R0, B3.R0);
         SIMD_Scalar T1(B0.R1, B1.R1, B2.R1, B3.R1);
         SIMD_Scalar T2(B0.R2, B1.R2, B2.R2, B3.R2);
         SIMD_Scalar T3(B0.R3, B1.R3, B2.R3, B3.R3);

         B0 = T0;
         B1 = T1;
         B2 = T2;
         B3 = T3;
         }

   private:
      u32bit R0, R1, R2, R3;
   };

}


namespace Botan {

/**
* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length
* @param out the input/output buffer
* @param in the read-only input buffer
* @param length the length of the buffers
*/
inline void xor_buf(byte out[], const byte in[], size_t length)
   {
   while(length >= 8)
      {
#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
      *reinterpret_cast<u64bit*>(out) ^= *reinterpret_cast<const u64bit*>(in);
#else
      out[0] ^= in[0]; out[1] ^= in[1];
      out[2] ^= in[2]; out[3] ^= in[3];
      out[4] ^= in[4]; out[5] ^= in[5];
      out[6] ^= in[6]; out[7] ^= in[7];
#endif

      out += 8; in += 8; length -= 8;
      }

   for(size_t i = 0; i != length; ++i)
      out[i] ^= in[i];
   }

/**
* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length
* @param out the output buffer
* @param in the first input buffer
* @param in2 the second output buffer
* @param length the length of the three buffers
*/
inline void xor_buf(byte out[],
                    const byte in[],
                    const byte in2[],
                    size_t length)
   {
   while(length >= 8)
      {
#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
      *reinterpret_cast<u64bit*>(out) =
         *reinterpret_cast<const u64bit*>(in) ^
         *reinterpret_cast<const u64bit*>(in2);
#else
      out[0] = in[0] ^ in2[0]; out[1] = in[1] ^ in2[1];
      out[2] = in[2] ^ in2[2]; out[3] = in[3] ^ in2[3];
      out[4] = in[4] ^ in2[4]; out[5] = in[5] ^ in2[5];
      out[6] = in[6] ^ in2[6]; out[7] = in[7] ^ in2[7];
#endif

      in += 8; in2 += 8; out += 8; length -= 8;
      }

   for(size_t i = 0; i != length; ++i)
      out[i] = in[i] ^ in2[i];
   }

}


namespace Botan {

/**
* Mutex Base Class
*/
class Mutex
   {
   public:
      /**
      * Lock the mutex
      */
      virtual void lock() = 0;

      /**
      * Unlock the mutex
      */
      virtual void unlock() = 0;
      virtual ~Mutex() {}
   };

/**
* Mutex Factory
*/
class Mutex_Factory
   {
   public:
      /**
      * @return newly allocated mutex
      */
      virtual Mutex* make() = 0;

      virtual ~Mutex_Factory() {}
   };

/**
* Mutex Holding Class for RAII
*/
class Mutex_Holder
   {
   public:
      /**
      * Hold onto a mutex until we leave scope
      * @param m the mutex to lock
      */
      Mutex_Holder(Mutex* m) : mux(m)
         {
         if(!mux)
            throw Invalid_Argument("Mutex_Holder: Argument was NULL");
         mux->lock();
         }

      ~Mutex_Holder() { mux->unlock(); }
   private:
      Mutex* mux;
   };

}


namespace Botan {

/**
* Copy-on-Predicate Algorithm
* @param current the first iterator value
* @param end the final iterator value
* @param dest an output iterator
* @param copy_p the predicate
*/
template<typename InputIterator, typename OutputIterator, typename Predicate>
OutputIterator copy_if(InputIterator current, InputIterator end,
                       OutputIterator dest, Predicate copy_p)
   {
   while(current != end)
      {
      if(copy_p(*current))
         *dest++ = *current;
      ++current;
      }
   return dest;
   }

/**
* Searching through a std::map
* @param mapping the map to search
* @param key is what to look for
* @param null_result is the value to return if key is not in mapping
* @return mapping[key] or null_result
*/
template<typename K, typename V>
inline V search_map(const std::map<K, V>& mapping,
                    const K& key,
                    const V& null_result = V())
   {
   typename std::map<K, V>::const_iterator i = mapping.find(key);
   if(i == mapping.end())
      return null_result;
   return i->second;
   }

/**
* Function adaptor for delete operation
*/
template<class T>
class del_fun : public std::unary_function<T, void>
   {
   public:
      void operator()(T* ptr) { delete ptr; }
   };

/**
* Delete the second half of a pair of objects
*/
template<typename Pair>
void delete2nd(Pair& pair)
   {
   delete pair.second;
   }

/**
* Insert a key/value pair into a multimap
*/
template<typename K, typename V>
void multimap_insert(std::multimap<K, V>& multimap,
                     const K& key, const V& value)
   {
#if defined(BOTAN_BUILD_COMPILER_IS_SUN_STUDIO)
   // Work around a strange bug in Sun Studio
   multimap.insert(std::make_pair<const K, V>(key, value));
#else
   multimap.insert(std::make_pair(key, value));
#endif
   }

}


namespace Botan {

/**
* @param prov_name a provider name
* @return weight for this provider
*/
size_t static_provider_weight(const std::string& prov_name);

/**
* Algorithm_Cache (used by Algorithm_Factory)
*/
template<typename T>
class Algorithm_Cache
   {
   public:
      /**
      * @param algo_spec names the requested algorithm
      * @param pref_provider suggests a preferred provider
      * @return prototype object, or NULL
      */
      const T* get(const std::string& algo_spec,
                   const std::string& pref_provider);

      /**
      * Add a new algorithm implementation to the cache
      * @param algo the algorithm prototype object
      * @param requested_name how this name will be requested
      * @param provider_name is the name of the provider of this prototype
      */
      void add(T* algo,
               const std::string& requested_name,
               const std::string& provider_name);

      /**
      * Set the preferred provider
      * @param algo_spec names the algorithm
      * @param provider names the preferred provider
      */
      void set_preferred_provider(const std::string& algo_spec,
                                  const std::string& provider);

      /**
      * Return the list of providers of this algorithm
      * @param algo_name names the algorithm
      * @return list of providers of this algorithm
      */
      std::vector<std::string> providers_of(const std::string& algo_name);

      /**
      * Clear the cache
      */
      void clear_cache();

      /**
      * Constructor
      * @param m a mutex to serialize internal access
      */
      Algorithm_Cache(Mutex* m) : mutex(m) {}
      ~Algorithm_Cache() { clear_cache(); delete mutex; }
   private:
      typedef typename std::map<std::string, std::map<std::string, T*> >::iterator
         algorithms_iterator;

      typedef typename std::map<std::string, T*>::iterator provider_iterator;

      algorithms_iterator find_algorithm(const std::string& algo_spec);

      Mutex* mutex;
      std::map<std::string, std::string> aliases;
      std::map<std::string, std::string> pref_providers;
      std::map<std::string, std::map<std::string, T*> > algorithms;
   };

/*
* Look for an algorithm implementation in the cache, also checking aliases
* Assumes object lock is held
*/
template<typename T>
typename Algorithm_Cache<T>::algorithms_iterator
Algorithm_Cache<T>::find_algorithm(const std::string& algo_spec)
   {
   algorithms_iterator algo = algorithms.find(algo_spec);

   // Not found? Check if a known alias
   if(algo == algorithms.end())
      {
      std::map<std::string, std::string>::const_iterator alias =
         aliases.find(algo_spec);

      if(alias != aliases.end())
         algo = algorithms.find(alias->second);
      }

   return algo;
   }

/*
* Look for an algorithm implementation by a particular provider
*/
template<typename T>
const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
                                 const std::string& requested_provider)
   {
   Mutex_Holder lock(mutex);

   algorithms_iterator algo = find_algorithm(algo_spec);
   if(algo == algorithms.end()) // algo not found at all (no providers)
      return 0;

   // If a provider is requested specifically, return it or fail entirely
   if(requested_provider != "")
      {
      provider_iterator prov = algo->second.find(requested_provider);
      if(prov != algo->second.end())
         return prov->second;
      return 0;
      }

   const T* prototype = 0;
   std::string prototype_provider;
   size_t prototype_prov_weight = 0;

   const std::string pref_provider = search_map(pref_providers, algo_spec);

   for(provider_iterator i = algo->second.begin(); i != algo->second.end(); ++i)
      {
      const std::string prov_name = i->first;
      const size_t prov_weight = static_provider_weight(prov_name);

      // preferred prov exists, return immediately
      if(prov_name == pref_provider)
         return i->second;

      if(prototype == 0 || prov_weight > prototype_prov_weight)
         {
         prototype = i->second;
         prototype_provider = i->first;
         prototype_prov_weight = prov_weight;
         }
      }

   return prototype;
   }

/*
* Add an implementation to the cache
*/
template<typename T>
void Algorithm_Cache<T>::add(T* algo,
                             const std::string& requested_name,
                             const std::string& provider)
   {
   if(!algo)
      return;

   Mutex_Holder lock(mutex);

   if(algo->name() != requested_name &&
      aliases.find(requested_name) == aliases.end())
      {
      aliases[requested_name] = algo->name();
      }

   if(!algorithms[algo->name()][provider])
      algorithms[algo->name()][provider] = algo;
   else
      delete algo;
   }

/*
* Find the providers of this algo (if any)
*/
template<typename T> std::vector<std::string>
Algorithm_Cache<T>::providers_of(const std::string& algo_name)
   {
   Mutex_Holder lock(mutex);

   std::vector<std::string> providers;

   algorithms_iterator algo = find_algorithm(algo_name);

   if(algo != algorithms.end())
      {
      provider_iterator provider = algo->second.begin();

      while(provider != algo->second.end())
         {
         providers.push_back(provider->first);
         ++provider;
         }
      }

   return providers;
   }

/*
* Set the preferred provider for an algorithm
*/
template<typename T>
void Algorithm_Cache<T>::set_preferred_provider(const std::string& algo_spec,
                                                const std::string& provider)
   {
   Mutex_Holder lock(mutex);

   pref_providers[algo_spec] = provider;
   }

/*
* Clear out the cache
*/
template<typename T>
void Algorithm_Cache<T>::clear_cache()
   {
   algorithms_iterator algo = algorithms.begin();

   while(algo != algorithms.end())
      {
      provider_iterator provider = algo->second.begin();

      while(provider != algo->second.end())
         {
         delete provider->second;
         ++provider;
         }

      ++algo;
      }

   algorithms.clear();
   }

}


namespace Botan {

/**
* Round up
* @param n an integer
* @param align_to the alignment boundary
* @return n rounded up to a multiple of align_to
*/
template<typename T>
inline T round_up(T n, T align_to)
   {
   if(n % align_to || n == 0)
      n += align_to - (n % align_to);
   return n;
   }

/**
* Round down
* @param n an integer
* @param align_to the alignment boundary
* @return n rounded down to a multiple of align_to
*/
template<typename T>
inline T round_down(T n, T align_to)
   {
   return (n - (n % align_to));
   }

}


namespace Botan {

/**
* Engine for implementations that use some kind of SIMD
*/
class SIMD_Engine : public Engine
   {
   public:
      std::string provider_name() const { return "simd"; }

      BlockCipher* find_block_cipher(const SCAN_Name&,
                                     Algorithm_Factory&) const;

      HashFunction* find_hash(const SCAN_Name& request,
                              Algorithm_Factory&) const;
   };

}


namespace Botan {

/**
* File Tree Walking Entropy Source
*/
class FTW_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "Proc Walker"; }

      void poll(Entropy_Accumulator& accum);

      FTW_EntropySource(const std::string& root_dir);
      ~FTW_EntropySource();
   private:
      std::string path;
      class File_Descriptor_Source* dir;
   };

}


namespace Botan {

/**
* Entropy source using high resolution timers
*
* @note Any results from timers are marked as not contributing entropy
* to the poll, as a local attacker could observe them directly.
*/
class High_Resolution_Timestamp : public EntropySource
   {
   public:
      std::string name() const { return "High Resolution Timestamp"; }
      void poll(Entropy_Accumulator& accum);
   };

}

#ifdef Q_OS_WIN
namespace Botan {

/**
* Win32 Mutex Factory
*/
class Win32_Mutex_Factory : public Mutex_Factory
   {
   public:
      Mutex* make();
   };
}
#endif


namespace Botan {

/**
* Power of 2 test. T should be an unsigned integer type
* @param arg an integer value
* @return true iff arg is 2^n for some n > 0
*/
template<typename T>
inline bool power_of_2(T arg)
   {
   return ((arg != 0 && arg != 1) && ((arg & (arg-1)) == 0));
   }

/**
* Return the index of the highest set bit
* T is an unsigned integer type
* @param n an integer value
* @return index of the highest set bit in n
*/
template<typename T>
inline size_t high_bit(T n)
   {
   for(size_t i = 8*sizeof(T); i > 0; --i)
      if((n >> (i - 1)) & 0x01)
         return i;
   return 0;
   }

/**
* Return the index of the lowest set bit
* T is an unsigned integer type
* @param n an integer value
* @return index of the lowest set bit in n
*/
template<typename T>
inline size_t low_bit(T n)
   {
   for(size_t i = 0; i != 8*sizeof(T); ++i)
      if((n >> i) & 0x01)
         return (i + 1);
   return 0;
   }

/**
* Return the number of significant bytes in n
* @param n an integer value
* @return number of significant bytes in n
*/
template<typename T>
inline size_t significant_bytes(T n)
   {
   for(size_t i = 0; i != sizeof(T); ++i)
      if(get_byte(i, n))
         return sizeof(T)-i;
   return 0;
   }

/**
* Compute Hamming weights
* @param n an integer value
* @return number of bits in n set to 1
*/
template<typename T>
inline size_t hamming_weight(T n)
   {
   const byte NIBBLE_WEIGHTS[] = {
      0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };

   size_t weight = 0;
   for(size_t i = 0; i != 2*sizeof(T); ++i)
      weight += NIBBLE_WEIGHTS[(n >> (4*i)) & 0x0F];
   return weight;
   }

/**
* Count the trailing zero bits in n
* @param n an integer value
* @return maximum x st 2^x divides n
*/
template<typename T>
inline size_t ctz(T n)
   {
   for(size_t i = 0; i != 8*sizeof(T); ++i)
      if((n >> i) & 0x01)
         return i;
   return 8*sizeof(T);
   }

}


namespace Botan {

/**
* Estimate work factor for discrete logarithm
* @param prime_group_size size of the group in bits
* @return estimated security level for this group
*/
size_t dl_work_factor(size_t prime_group_size);

}


namespace Botan {

/**
* No-Op Mutex Factory
*/
class Noop_Mutex_Factory : public Mutex_Factory
   {
   public:
      Mutex* make();
   };

}


namespace Botan {

/**
* Pooling Allocator
*/
class Pooling_Allocator : public Allocator
   {
   public:
      void* allocate(size_t);
      void deallocate(void*, size_t);

      void destroy();

      /**
      * @param mutex used for internal locking
      */
      Pooling_Allocator(Mutex* mutex);
      ~Pooling_Allocator();
   private:
      void get_more_core(size_t);
      byte* allocate_blocks(size_t);

      virtual void* alloc_block(size_t) = 0;
      virtual void dealloc_block(void*, size_t) = 0;

      class Memory_Block
         {
         public:
            Memory_Block(void*);

            static size_t bitmap_size() { return BITMAP_SIZE; }
            static size_t block_size() { return BLOCK_SIZE; }

            bool contains(void*, size_t) const;
            byte* alloc(size_t);
            void free(void*, size_t);

            bool operator<(const Memory_Block& other) const
               {
               if(buffer < other.buffer && other.buffer < buffer_end)
                  return false;
               return (buffer < other.buffer);
               }
         private:
            typedef u64bit bitmap_type;
            static const size_t BITMAP_SIZE = 8 * sizeof(bitmap_type);
            static const size_t BLOCK_SIZE = 64;

            bitmap_type bitmap;
            byte* buffer, *buffer_end;
         };

      std::vector<Memory_Block> blocks;
      std::vector<Memory_Block>::iterator last_used;
      std::vector<std::pair<void*, size_t> > allocated;
      Mutex* mutex;
   };

}


namespace Botan {

/**
* Allocator using malloc
*/
class Malloc_Allocator : public Allocator
   {
   public:
      void* allocate(size_t);
      void deallocate(void*, size_t);

      std::string type() const { return "malloc"; }
   };

/**
* Allocator using malloc plus locking
*/
class Locking_Allocator : public Pooling_Allocator
   {
   public:
      /**
      * @param mutex used for internal locking
      */
      Locking_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}

      std::string type() const { return "locking"; }
   private:
      void* alloc_block(size_t);
      void dealloc_block(void*, size_t);
   };

}


namespace Botan {

/**
* Fixed Window Exponentiator
*/
class Fixed_Window_Exponentiator : public Modular_Exponentiator
   {
   public:
      void set_exponent(const BigInt&);
      void set_base(const BigInt&);
      BigInt execute() const;

      Modular_Exponentiator* copy() const
         { return new Fixed_Window_Exponentiator(*this); }

      Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints);
   private:
      Modular_Reducer reducer;
      BigInt exp;
      size_t window_bits;
      std::vector<BigInt> g;
      Power_Mod::Usage_Hints hints;
   };

/**
* Montgomery Exponentiator
*/
class Montgomery_Exponentiator : public Modular_Exponentiator
   {
   public:
      void set_exponent(const BigInt&);
      void set_base(const BigInt&);
      BigInt execute() const;

      Modular_Exponentiator* copy() const
         { return new Montgomery_Exponentiator(*this); }

      Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints);
   private:
      BigInt exp, modulus;
      BigInt R2, R_mod;
      std::vector<BigInt> g;
      word mod_prime;
      size_t mod_words, exp_bits, window_bits;
      Power_Mod::Usage_Hints hints;
   };

}


#if (BOTAN_MP_WORD_BITS != 32)
   #error The mp_x86_32 module requires that BOTAN_MP_WORD_BITS == 32
#endif

#ifdef Q_OS_UNIX
namespace Botan {

extern "C" {

/*
* Helper Macros for x86 Assembly
*/
#define ASM(x) x "\n\t"

/*
* Word Multiply
*/
inline word word_madd2(word a, word b, word* c)
   {
   asm(
      ASM("mull %[b]")
      ASM("addl %[c],%[a]")
      ASM("adcl $0,%[carry]")

      : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c)
      : "0"(a), "1"(b), [c]"g"(*c) : "cc");

   return a;
   }

/*
* Word Multiply/Add
*/
inline word word_madd3(word a, word b, word c, word* d)
   {
   asm(
      ASM("mull %[b]")

      ASM("addl %[c],%[a]")
      ASM("adcl $0,%[carry]")

      ASM("addl %[d],%[a]")
      ASM("adcl $0,%[carry]")

      : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d)
      : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc");

   return a;
   }

}

}
#endif



namespace Botan {

/**
* Unix Program Info
*/
struct Unix_Program
   {
   /**
   * @param n is the name and arguments of what we are going run
   * @param p is the priority level (lower prio numbers get polled first)
   */
   Unix_Program(const char* n, size_t p)
      { name_and_args = n; priority = p; working = true; }

   /**
   * The name and arguments for this command
   */
   std::string name_and_args;

   /**
   * Priority: we scan from low to high
   */
   size_t priority;

   /**
   * Does this source seem to be working?
   */
   bool working;
   };

/**
* Command Output DataSource
*/
class DataSource_Command : public DataSource
   {
   public:
      size_t read(byte[], size_t);
      size_t peek(byte[], size_t, size_t) const;
      bool end_of_data() const;
      std::string id() const;

      int fd() const;

      DataSource_Command(const std::string&,
                         const std::vector<std::string>& paths);
      ~DataSource_Command();
   private:
      void create_pipe(const std::vector<std::string>&);
      void shutdown_pipe();

      const size_t MAX_BLOCK_USECS, KILL_WAIT;

      std::vector<std::string> arg_list;
      struct pipe_wrapper* pipe;
   };

}


namespace Botan {

/**
* Allocator that uses memory maps backed by disk. We zeroize the map
* upon deallocation. If swap occurs, the VM will swap to the shared
* file backing rather than to a swap device, which means we know where
* it is and can zap it later.
*/
class MemoryMapping_Allocator : public Pooling_Allocator
   {
   public:
      /**
      * @param mutex used for internal locking
      */
      MemoryMapping_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}
      std::string type() const { return "mmap"; }
   private:
      void* alloc_block(size_t);
      void dealloc_block(void*, size_t);
   };

}


#if defined(BOTAN_HAS_SIMD_SSE2)
  namespace Botan { typedef SIMD_SSE2 SIMD_32; }

#elif defined(BOTAN_HAS_SIMD_ALTIVEC)
  namespace Botan { typedef SIMD_Altivec SIMD_32; }

#elif defined(BOTAN_HAS_SIMD_SCALAR)
  namespace Botan { typedef SIMD_Scalar SIMD_32; }

#else
  #error "No SIMD module defined"

#endif


namespace Botan {

/**
* Entropy source reading from kernel devices like /dev/random
*/
class Device_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "RNG Device Reader"; }

      void poll(Entropy_Accumulator& accum);

      Device_EntropySource(const std::vector<std::string>& fsnames);
      ~Device_EntropySource();
   private:

      /**
      A class handling reading from a Unix character device
      */
      class Device_Reader
         {
         public:
            typedef int fd_type;

            // Does not own fd, a transient class
            Device_Reader(fd_type device_fd) : fd(device_fd) {}

            void close();

            size_t get(byte out[], size_t length, size_t ms_wait_time);

            static fd_type open(const std::string& pathname);
         private:
            fd_type fd;
         };

      std::vector<Device_Reader> devices;
   };

}

namespace Botan {

void assertion_failure(const char* expr_str,
                       const char* msg,
                       const char* func,
                       const char* file,
                       int line);

#define BOTAN_ASSERT(expr, msg)                           \
   do {                                                   \
      if(!(expr))                                         \
         Botan::assertion_failure(#expr,                  \
                                  msg,                    \
                                  BOTAN_ASSERT_FUNCTION,  \
                                  __FILE__,               \
                                  __LINE__);              \
   } while(0)

#define BOTAN_ASSERT_EQUAL(value1, value2, msg)           \
   do {                                                   \
     if(value1 != value2)                                 \
         Botan::assertion_failure(#value1 " == " #value2, \
                                  msg,                    \
                                  BOTAN_ASSERT_FUNCTION,  \
                                  __FILE__,               \
                                  __LINE__);              \
   } while(0)

/*
* Unfortunately getting the function name from the preprocessor
* isn't standard in C++98 (C++0x uses C99's __func__)
*/
#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || \
    defined(BOTAN_BUILD_COMPILER_IS_CLANG) || \
    defined(BOTAN_BUILD_COMPILER_IS_INTEL)

  #define BOTAN_ASSERT_FUNCTION __PRETTY_FUNCTION__

#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)

  #define BOTAN_ASSERT_FUNCTION __FUNCTION__

#else
  #define BOTAN_ASSERT_FUNCTION ((const char*)0)
#endif

}


namespace Botan {

/*
* The size of the word type, in bits
*/
const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS;

extern "C" {

/*
* Addition/Subtraction Operations
*/
void bigint_add2(word x[], size_t x_size,
                 const word y[], size_t y_size);

void bigint_add3(word z[],
                 const word x[], size_t x_size,
                 const word y[], size_t y_size);

word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size);

word bigint_add3_nc(word z[],
                    const word x[], size_t x_size,
                    const word y[], size_t y_size);

word bigint_sub2(word x[], size_t x_size,
                 const word y[], size_t y_size);

/**
* x = y - x; assumes y >= x
*/
void bigint_sub2_rev(word x[], const word y[], size_t y_size);

word bigint_sub3(word z[],
                 const word x[], size_t x_size,
                 const word y[], size_t y_size);

/*
* Shift Operations
*/
void bigint_shl1(word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift);

void bigint_shr1(word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift);

void bigint_shl2(word y[], const word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift);

void bigint_shr2(word y[], const word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift);

/*
* Simple O(N^2) Multiplication and Squaring
*/
void bigint_simple_mul(word z[],
                       const word x[], size_t x_size,
                       const word y[], size_t y_size);

void bigint_simple_sqr(word z[], const word x[], size_t x_size);

/*
* Linear Multiply
*/
void bigint_linmul2(word x[], size_t x_size, word y);
void bigint_linmul3(word z[], const word x[], size_t x_size, word y);

/**
* Montgomery Reduction
* @param z integer to reduce (also output in first p_size+1 words)
* @param z_size size of z (should be >= 2*p_size+1)
* @param p modulus
* @param p_size size of p
* @param p_dash Montgomery value
* @param workspace array of at least 2*(p_size+1) words
*/
void bigint_monty_redc(word z[], size_t z_size,
                       const word p[], size_t p_size, word p_dash,
                       word workspace[]);

/*
* Montgomery Multiplication
*/
void bigint_monty_mul(word z[], size_t z_size,
                      const word x[], size_t x_size, size_t x_sw,
                      const word y[], size_t y_size, size_t y_sw,
                      const word p[], size_t p_size, word p_dash,
                      word workspace[]);

/*
* Montgomery Squaring
*/
void bigint_monty_sqr(word z[], size_t z_size,
                      const word x[], size_t x_size, size_t x_sw,
                      const word p[], size_t p_size, word p_dash,
                      word workspace[]);

/*
* Division operation
*/
size_t bigint_divcore(word q, word y2, word y1,
                      word x3, word x2, word x1);

/**
* Compare x and y
*/
s32bit bigint_cmp(const word x[], size_t x_size,
                  const word y[], size_t y_size);

/**
* Compute ((n1<<bits) + n0) / d
*/
word bigint_divop(word n1, word n0, word d);

/**
* Compute ((n1<<bits) + n0) % d
*/
word bigint_modop(word n1, word n0, word d);

/*
* Comba Multiplication / Squaring
*/
void bigint_comba_mul4(word z[8], const word x[4], const word y[4]);
void bigint_comba_mul6(word z[12], const word x[6], const word y[6]);
void bigint_comba_mul8(word z[16], const word x[8], const word y[8]);
void bigint_comba_mul16(word z[32], const word x[16], const word y[16]);

void bigint_comba_sqr4(word out[8], const word in[4]);
void bigint_comba_sqr6(word out[12], const word in[6]);
void bigint_comba_sqr8(word out[16], const word in[8]);
void bigint_comba_sqr16(word out[32], const word in[16]);

}

/*
* High Level Multiplication/Squaring Interfaces
*/
void bigint_mul(word z[], size_t z_size, word workspace[],
                const word x[], size_t x_size, size_t x_sw,
                const word y[], size_t y_size, size_t y_sw);

void bigint_sqr(word z[], size_t z_size, word workspace[],
                const word x[], size_t x_size, size_t x_sw);

}


namespace Botan {

/**
* Pthread Mutex Factory
*/
class Pthread_Mutex_Factory : public Mutex_Factory
   {
   public:
      Mutex* make();
   };

}


namespace Botan {

/**
* Core Engine
*/
class Core_Engine : public Engine
   {
   public:
      std::string provider_name() const { return "core"; }

      PK_Ops::Key_Agreement*
         get_key_agreement_op(const Private_Key& key) const;

      PK_Ops::Signature*
         get_signature_op(const Private_Key& key) const;

      PK_Ops::Verification* get_verify_op(const Public_Key& key) const;

      PK_Ops::Encryption* get_encryption_op(const Public_Key& key) const;

      PK_Ops::Decryption* get_decryption_op(const Private_Key& key) const;

      Modular_Exponentiator* mod_exp(const BigInt& n,
                                     Power_Mod::Usage_Hints) const;

      Keyed_Filter* get_cipher(const std::string&, Cipher_Dir,
                               Algorithm_Factory&);

      BlockCipher* find_block_cipher(const SCAN_Name&,
                                     Algorithm_Factory&) const;

      StreamCipher* find_stream_cipher(const SCAN_Name&,
                                       Algorithm_Factory&) const;

      HashFunction* find_hash(const SCAN_Name& request,
                              Algorithm_Factory&) const;

      MessageAuthenticationCode* find_mac(const SCAN_Name& request,
                                          Algorithm_Factory&) const;

      PBKDF* find_pbkdf(const SCAN_Name& algo_spec,
                        Algorithm_Factory& af) const;
   };

/**
* Create a cipher mode filter object
* @param block_cipher a block cipher object
* @param direction are we encrypting or decrypting?
* @param mode the name of the cipher mode to use
* @param padding the mode padding to use (only used for ECB, CBC)
*/
Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher,
                              Cipher_Dir direction,
                              const std::string& mode,
                              const std::string& padding);

}


#ifdef Q_OS_UNIX
namespace Botan {

/**
* Unix Entropy Source
*/
class Unix_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "Unix Entropy Source"; }

      void poll(Entropy_Accumulator& accum);

      void add_sources(const Unix_Program[], size_t);
      Unix_EntropySource(const std::vector<std::string>& path);
   private:
      static std::vector<Unix_Program> get_default_sources();
      void fast_poll(Entropy_Accumulator& accum);

      const std::vector<std::string> PATH;
      std::vector<Unix_Program> sources;
   };

}

namespace Botan {

/**
* EGD Entropy Source
*/
class EGD_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "EGD/PRNGD"; }

      void poll(Entropy_Accumulator& accum);

      EGD_EntropySource(const std::vector<std::string>&);
      ~EGD_EntropySource();
   private:
      class EGD_Socket
         {
         public:
            EGD_Socket(const std::string& path);

            void close();
            size_t read(byte outbuf[], size_t length);
         private:
            static int open_socket(const std::string& path);

            std::string socket_path;
            int m_fd; // cached fd
         };

      std::vector<EGD_Socket> sockets;
   };

}
#endif

namespace Botan {

Public_Key* make_public_key(const AlgorithmIdentifier& alg_id,
                            const MemoryRegion<byte>& key_bits);

Private_Key* make_private_key(const AlgorithmIdentifier& alg_id,
                              const MemoryRegion<byte>& key_bits,
                              RandomNumberGenerator& rng);

}


namespace Botan {

/**
* Container of output buffers for Pipe
*/
class Output_Buffers
   {
   public:
      size_t read(byte[], size_t, Pipe::message_id);
      size_t peek(byte[], size_t, size_t, Pipe::message_id) const;
      size_t remaining(Pipe::message_id) const;

      void add(class SecureQueue*);
      void retire();

      Pipe::message_id message_count() const;

      Output_Buffers();
      ~Output_Buffers();
   private:
      class SecureQueue* get(Pipe::message_id) const;

      std::deque<SecureQueue*> buffers;
      Pipe::message_id offset;
   };

}


namespace Botan {

/**
* Check if we can at least potentially lock memory
*/
bool has_mlock();

/**
* Lock memory into RAM if possible
* @param addr the start of the memory block
* @param length the length of the memory block in bytes
* @returns true if successful, false otherwise
*/
bool lock_mem(void* addr, size_t length);

/**
* Unlock memory locked with lock_mem()
* @param addr the start of the memory block
* @param length the length of the memory block in bytes
*/
void unlock_mem(void* addr, size_t length);

}

#ifdef Q_OS_WIN
#if (BOTAN_MP_WORD_BITS == 8)
  typedef Botan::u16bit dword;
#elif (BOTAN_MP_WORD_BITS == 16)
  typedef Botan::u32bit dword;
#elif (BOTAN_MP_WORD_BITS == 32)
  typedef Botan::u64bit dword;
#elif (BOTAN_MP_WORD_BITS == 64)
  #error BOTAN_MP_WORD_BITS can be 64 only with assembly support
#else
  #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64
#endif

namespace Botan {

extern "C" {

/*
* Word Multiply/Add
*/
inline word word_madd2(word a, word b, word* c)
   {
   dword z = (dword)a * b + *c;
   *c = (word)(z >> BOTAN_MP_WORD_BITS);
   return (word)z;
   }

/*
* Word Multiply/Add
*/
inline word word_madd3(word a, word b, word c, word* d)
   {
   dword z = (dword)a * b + c + *d;
   *d = (word)(z >> BOTAN_MP_WORD_BITS);
   return (word)z;
   }

}

/**
* Win32 CAPI Entropy Source
*/
class Win32_CAPI_EntropySource : public EntropySource
   {
   public:
      std::string name() const { return "Win32 CryptoGenRandom"; }

      void poll(Entropy_Accumulator& accum);

     /**
     * Win32_Capi_Entropysource Constructor
     * @param provs list of providers, separated by ':'
     */
      Win32_CAPI_EntropySource(const std::string& provs = "");
   private:
      std::vector<u64bit> prov_types;
   };

}
#endif


namespace Botan {

template<typename T>
inline void prefetch_readonly(const T* addr, size_t length)
   {
#if defined(__GNUG__)
   const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T);

   for(size_t i = 0; i <= length; i += Ts_per_cache_line)
      __builtin_prefetch(addr + i, 0);
#endif
   }

template<typename T>
inline void prefetch_readwrite(const T* addr, size_t length)
   {
#if defined(__GNUG__)
   const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T);

   for(size_t i = 0; i <= length; i += Ts_per_cache_line)
      __builtin_prefetch(addr + i, 1);
#endif
   }

}


namespace Botan {

const u64bit Camellia_SBOX1[256] = {
0x7070700070000070ULL, 0x8282820082000082ULL, 0x2C2C2C002C00002CULL, 0xECECEC00EC0000ECULL,
0xB3B3B300B30000B3ULL, 0x2727270027000027ULL, 0xC0C0C000C00000C0ULL, 0xE5E5E500E50000E5ULL,
0xE4E4E400E40000E4ULL, 0x8585850085000085ULL, 0x5757570057000057ULL, 0x3535350035000035ULL,
0xEAEAEA00EA0000EAULL, 0x0C0C0C000C00000CULL, 0xAEAEAE00AE0000AEULL, 0x4141410041000041ULL,
0x2323230023000023ULL, 0xEFEFEF00EF0000EFULL, 0x6B6B6B006B00006BULL, 0x9393930093000093ULL,
0x4545450045000045ULL, 0x1919190019000019ULL, 0xA5A5A500A50000A5ULL, 0x2121210021000021ULL,
0xEDEDED00ED0000EDULL, 0x0E0E0E000E00000EULL, 0x4F4F4F004F00004FULL, 0x4E4E4E004E00004EULL,
0x1D1D1D001D00001DULL, 0x6565650065000065ULL, 0x9292920092000092ULL, 0xBDBDBD00BD0000BDULL,
0x8686860086000086ULL, 0xB8B8B800B80000B8ULL, 0xAFAFAF00AF0000AFULL, 0x8F8F8F008F00008FULL,
0x7C7C7C007C00007CULL, 0xEBEBEB00EB0000EBULL, 0x1F1F1F001F00001FULL, 0xCECECE00CE0000CEULL,
0x3E3E3E003E00003EULL, 0x3030300030000030ULL, 0xDCDCDC00DC0000DCULL, 0x5F5F5F005F00005FULL,
0x5E5E5E005E00005EULL, 0xC5C5C500C50000C5ULL, 0x0B0B0B000B00000BULL, 0x1A1A1A001A00001AULL,
0xA6A6A600A60000A6ULL, 0xE1E1E100E10000E1ULL, 0x3939390039000039ULL, 0xCACACA00CA0000CAULL,
0xD5D5D500D50000D5ULL, 0x4747470047000047ULL, 0x5D5D5D005D00005DULL, 0x3D3D3D003D00003DULL,
0xD9D9D900D90000D9ULL, 0x0101010001000001ULL, 0x5A5A5A005A00005AULL, 0xD6D6D600D60000D6ULL,
0x5151510051000051ULL, 0x5656560056000056ULL, 0x6C6C6C006C00006CULL, 0x4D4D4D004D00004DULL,
0x8B8B8B008B00008BULL, 0x0D0D0D000D00000DULL, 0x9A9A9A009A00009AULL, 0x6666660066000066ULL,
0xFBFBFB00FB0000FBULL, 0xCCCCCC00CC0000CCULL, 0xB0B0B000B00000B0ULL, 0x2D2D2D002D00002DULL,
0x7474740074000074ULL, 0x1212120012000012ULL, 0x2B2B2B002B00002BULL, 0x2020200020000020ULL,
0xF0F0F000F00000F0ULL, 0xB1B1B100B10000B1ULL, 0x8484840084000084ULL, 0x9999990099000099ULL,
0xDFDFDF00DF0000DFULL, 0x4C4C4C004C00004CULL, 0xCBCBCB00CB0000CBULL, 0xC2C2C200C20000C2ULL,
0x3434340034000034ULL, 0x7E7E7E007E00007EULL, 0x7676760076000076ULL, 0x0505050005000005ULL,
0x6D6D6D006D00006DULL, 0xB7B7B700B70000B7ULL, 0xA9A9A900A90000A9ULL, 0x3131310031000031ULL,
0xD1D1D100D10000D1ULL, 0x1717170017000017ULL, 0x0404040004000004ULL, 0xD7D7D700D70000D7ULL,
0x1414140014000014ULL, 0x5858580058000058ULL, 0x3A3A3A003A00003AULL, 0x6161610061000061ULL,
0xDEDEDE00DE0000DEULL, 0x1B1B1B001B00001BULL, 0x1111110011000011ULL, 0x1C1C1C001C00001CULL,
0x3232320032000032ULL, 0x0F0F0F000F00000FULL, 0x9C9C9C009C00009CULL, 0x1616160016000016ULL,
0x5353530053000053ULL, 0x1818180018000018ULL, 0xF2F2F200F20000F2ULL, 0x2222220022000022ULL,
0xFEFEFE00FE0000FEULL, 0x4444440044000044ULL, 0xCFCFCF00CF0000CFULL, 0xB2B2B200B20000B2ULL,
0xC3C3C300C30000C3ULL, 0xB5B5B500B50000B5ULL, 0x7A7A7A007A00007AULL, 0x9191910091000091ULL,
0x2424240024000024ULL, 0x0808080008000008ULL, 0xE8E8E800E80000E8ULL, 0xA8A8A800A80000A8ULL,
0x6060600060000060ULL, 0xFCFCFC00FC0000FCULL, 0x6969690069000069ULL, 0x5050500050000050ULL,
0xAAAAAA00AA0000AAULL, 0xD0D0D000D00000D0ULL, 0xA0A0A000A00000A0ULL, 0x7D7D7D007D00007DULL,
0xA1A1A100A10000A1ULL, 0x8989890089000089ULL, 0x6262620062000062ULL, 0x9797970097000097ULL,
0x5454540054000054ULL, 0x5B5B5B005B00005BULL, 0x1E1E1E001E00001EULL, 0x9595950095000095ULL,
0xE0E0E000E00000E0ULL, 0xFFFFFF00FF0000FFULL, 0x6464640064000064ULL, 0xD2D2D200D20000D2ULL,
0x1010100010000010ULL, 0xC4C4C400C40000C4ULL, 0x0000000000000000ULL, 0x4848480048000048ULL,
0xA3A3A300A30000A3ULL, 0xF7F7F700F70000F7ULL, 0x7575750075000075ULL, 0xDBDBDB00DB0000DBULL,
0x8A8A8A008A00008AULL, 0x0303030003000003ULL, 0xE6E6E600E60000E6ULL, 0xDADADA00DA0000DAULL,
0x0909090009000009ULL, 0x3F3F3F003F00003FULL, 0xDDDDDD00DD0000DDULL, 0x9494940094000094ULL,
0x8787870087000087ULL, 0x5C5C5C005C00005CULL, 0x8383830083000083ULL, 0x0202020002000002ULL,
0xCDCDCD00CD0000CDULL, 0x4A4A4A004A00004AULL, 0x9090900090000090ULL, 0x3333330033000033ULL,
0x7373730073000073ULL, 0x6767670067000067ULL, 0xF6F6F600F60000F6ULL, 0xF3F3F300F30000F3ULL,
0x9D9D9D009D00009DULL, 0x7F7F7F007F00007FULL, 0xBFBFBF00BF0000BFULL, 0xE2E2E200E20000E2ULL,
0x5252520052000052ULL, 0x9B9B9B009B00009BULL, 0xD8D8D800D80000D8ULL, 0x2626260026000026ULL,
0xC8C8C800C80000C8ULL, 0x3737370037000037ULL, 0xC6C6C600C60000C6ULL, 0x3B3B3B003B00003BULL,
0x8181810081000081ULL, 0x9696960096000096ULL, 0x6F6F6F006F00006FULL, 0x4B4B4B004B00004BULL,
0x1313130013000013ULL, 0xBEBEBE00BE0000BEULL, 0x6363630063000063ULL, 0x2E2E2E002E00002EULL,
0xE9E9E900E90000E9ULL, 0x7979790079000079ULL, 0xA7A7A700A70000A7ULL, 0x8C8C8C008C00008CULL,
0x9F9F9F009F00009FULL, 0x6E6E6E006E00006EULL, 0xBCBCBC00BC0000BCULL, 0x8E8E8E008E00008EULL,
0x2929290029000029ULL, 0xF5F5F500F50000F5ULL, 0xF9F9F900F90000F9ULL, 0xB6B6B600B60000B6ULL,
0x2F2F2F002F00002FULL, 0xFDFDFD00FD0000FDULL, 0xB4B4B400B40000B4ULL, 0x5959590059000059ULL,
0x7878780078000078ULL, 0x9898980098000098ULL, 0x0606060006000006ULL, 0x6A6A6A006A00006AULL,
0xE7E7E700E70000E7ULL, 0x4646460046000046ULL, 0x7171710071000071ULL, 0xBABABA00BA0000BAULL,
0xD4D4D400D40000D4ULL, 0x2525250025000025ULL, 0xABABAB00AB0000ABULL, 0x4242420042000042ULL,
0x8888880088000088ULL, 0xA2A2A200A20000A2ULL, 0x8D8D8D008D00008DULL, 0xFAFAFA00FA0000FAULL,
0x7272720072000072ULL, 0x0707070007000007ULL, 0xB9B9B900B90000B9ULL, 0x5555550055000055ULL,
0xF8F8F800F80000F8ULL, 0xEEEEEE00EE0000EEULL, 0xACACAC00AC0000ACULL, 0x0A0A0A000A00000AULL,
0x3636360036000036ULL, 0x4949490049000049ULL, 0x2A2A2A002A00002AULL, 0x6868680068000068ULL,
0x3C3C3C003C00003CULL, 0x3838380038000038ULL, 0xF1F1F100F10000F1ULL, 0xA4A4A400A40000A4ULL,
0x4040400040000040ULL, 0x2828280028000028ULL, 0xD3D3D300D30000D3ULL, 0x7B7B7B007B00007BULL,
0xBBBBBB00BB0000BBULL, 0xC9C9C900C90000C9ULL, 0x4343430043000043ULL, 0xC1C1C100C10000C1ULL,
0x1515150015000015ULL, 0xE3E3E300E30000E3ULL, 0xADADAD00AD0000ADULL, 0xF4F4F400F40000F4ULL,
0x7777770077000077ULL, 0xC7C7C700C70000C7ULL, 0x8080800080000080ULL, 0x9E9E9E009E00009EULL };

const u64bit Camellia_SBOX2[256] = {
0x00E0E0E0E0E00000ULL, 0x0005050505050000ULL, 0x0058585858580000ULL, 0x00D9D9D9D9D90000ULL,
0x0067676767670000ULL, 0x004E4E4E4E4E0000ULL, 0x0081818181810000ULL, 0x00CBCBCBCBCB0000ULL,
0x00C9C9C9C9C90000ULL, 0x000B0B0B0B0B0000ULL, 0x00AEAEAEAEAE0000ULL, 0x006A6A6A6A6A0000ULL,
0x00D5D5D5D5D50000ULL, 0x0018181818180000ULL, 0x005D5D5D5D5D0000ULL, 0x0082828282820000ULL,
0x0046464646460000ULL, 0x00DFDFDFDFDF0000ULL, 0x00D6D6D6D6D60000ULL, 0x0027272727270000ULL,
0x008A8A8A8A8A0000ULL, 0x0032323232320000ULL, 0x004B4B4B4B4B0000ULL, 0x0042424242420000ULL,
0x00DBDBDBDBDB0000ULL, 0x001C1C1C1C1C0000ULL, 0x009E9E9E9E9E0000ULL, 0x009C9C9C9C9C0000ULL,
0x003A3A3A3A3A0000ULL, 0x00CACACACACA0000ULL, 0x0025252525250000ULL, 0x007B7B7B7B7B0000ULL,
0x000D0D0D0D0D0000ULL, 0x0071717171710000ULL, 0x005F5F5F5F5F0000ULL, 0x001F1F1F1F1F0000ULL,
0x00F8F8F8F8F80000ULL, 0x00D7D7D7D7D70000ULL, 0x003E3E3E3E3E0000ULL, 0x009D9D9D9D9D0000ULL,
0x007C7C7C7C7C0000ULL, 0x0060606060600000ULL, 0x00B9B9B9B9B90000ULL, 0x00BEBEBEBEBE0000ULL,
0x00BCBCBCBCBC0000ULL, 0x008B8B8B8B8B0000ULL, 0x0016161616160000ULL, 0x0034343434340000ULL,
0x004D4D4D4D4D0000ULL, 0x00C3C3C3C3C30000ULL, 0x0072727272720000ULL, 0x0095959595950000ULL,
0x00ABABABABAB0000ULL, 0x008E8E8E8E8E0000ULL, 0x00BABABABABA0000ULL, 0x007A7A7A7A7A0000ULL,
0x00B3B3B3B3B30000ULL, 0x0002020202020000ULL, 0x00B4B4B4B4B40000ULL, 0x00ADADADADAD0000ULL,
0x00A2A2A2A2A20000ULL, 0x00ACACACACAC0000ULL, 0x00D8D8D8D8D80000ULL, 0x009A9A9A9A9A0000ULL,
0x0017171717170000ULL, 0x001A1A1A1A1A0000ULL, 0x0035353535350000ULL, 0x00CCCCCCCCCC0000ULL,
0x00F7F7F7F7F70000ULL, 0x0099999999990000ULL, 0x0061616161610000ULL, 0x005A5A5A5A5A0000ULL,
0x00E8E8E8E8E80000ULL, 0x0024242424240000ULL, 0x0056565656560000ULL, 0x0040404040400000ULL,
0x00E1E1E1E1E10000ULL, 0x0063636363630000ULL, 0x0009090909090000ULL, 0x0033333333330000ULL,
0x00BFBFBFBFBF0000ULL, 0x0098989898980000ULL, 0x0097979797970000ULL, 0x0085858585850000ULL,
0x0068686868680000ULL, 0x00FCFCFCFCFC0000ULL, 0x00ECECECECEC0000ULL, 0x000A0A0A0A0A0000ULL,
0x00DADADADADA0000ULL, 0x006F6F6F6F6F0000ULL, 0x0053535353530000ULL, 0x0062626262620000ULL,
0x00A3A3A3A3A30000ULL, 0x002E2E2E2E2E0000ULL, 0x0008080808080000ULL, 0x00AFAFAFAFAF0000ULL,
0x0028282828280000ULL, 0x00B0B0B0B0B00000ULL, 0x0074747474740000ULL, 0x00C2C2C2C2C20000ULL,
0x00BDBDBDBDBD0000ULL, 0x0036363636360000ULL, 0x0022222222220000ULL, 0x0038383838380000ULL,
0x0064646464640000ULL, 0x001E1E1E1E1E0000ULL, 0x0039393939390000ULL, 0x002C2C2C2C2C0000ULL,
0x00A6A6A6A6A60000ULL, 0x0030303030300000ULL, 0x00E5E5E5E5E50000ULL, 0x0044444444440000ULL,
0x00FDFDFDFDFD0000ULL, 0x0088888888880000ULL, 0x009F9F9F9F9F0000ULL, 0x0065656565650000ULL,
0x0087878787870000ULL, 0x006B6B6B6B6B0000ULL, 0x00F4F4F4F4F40000ULL, 0x0023232323230000ULL,
0x0048484848480000ULL, 0x0010101010100000ULL, 0x00D1D1D1D1D10000ULL, 0x0051515151510000ULL,
0x00C0C0C0C0C00000ULL, 0x00F9F9F9F9F90000ULL, 0x00D2D2D2D2D20000ULL, 0x00A0A0A0A0A00000ULL,
0x0055555555550000ULL, 0x00A1A1A1A1A10000ULL, 0x0041414141410000ULL, 0x00FAFAFAFAFA0000ULL,
0x0043434343430000ULL, 0x0013131313130000ULL, 0x00C4C4C4C4C40000ULL, 0x002F2F2F2F2F0000ULL,
0x00A8A8A8A8A80000ULL, 0x00B6B6B6B6B60000ULL, 0x003C3C3C3C3C0000ULL, 0x002B2B2B2B2B0000ULL,
0x00C1C1C1C1C10000ULL, 0x00FFFFFFFFFF0000ULL, 0x00C8C8C8C8C80000ULL, 0x00A5A5A5A5A50000ULL,
0x0020202020200000ULL, 0x0089898989890000ULL, 0x0000000000000000ULL, 0x0090909090900000ULL,
0x0047474747470000ULL, 0x00EFEFEFEFEF0000ULL, 0x00EAEAEAEAEA0000ULL, 0x00B7B7B7B7B70000ULL,
0x0015151515150000ULL, 0x0006060606060000ULL, 0x00CDCDCDCDCD0000ULL, 0x00B5B5B5B5B50000ULL,
0x0012121212120000ULL, 0x007E7E7E7E7E0000ULL, 0x00BBBBBBBBBB0000ULL, 0x0029292929290000ULL,
0x000F0F0F0F0F0000ULL, 0x00B8B8B8B8B80000ULL, 0x0007070707070000ULL, 0x0004040404040000ULL,
0x009B9B9B9B9B0000ULL, 0x0094949494940000ULL, 0x0021212121210000ULL, 0x0066666666660000ULL,
0x00E6E6E6E6E60000ULL, 0x00CECECECECE0000ULL, 0x00EDEDEDEDED0000ULL, 0x00E7E7E7E7E70000ULL,
0x003B3B3B3B3B0000ULL, 0x00FEFEFEFEFE0000ULL, 0x007F7F7F7F7F0000ULL, 0x00C5C5C5C5C50000ULL,
0x00A4A4A4A4A40000ULL, 0x0037373737370000ULL, 0x00B1B1B1B1B10000ULL, 0x004C4C4C4C4C0000ULL,
0x0091919191910000ULL, 0x006E6E6E6E6E0000ULL, 0x008D8D8D8D8D0000ULL, 0x0076767676760000ULL,
0x0003030303030000ULL, 0x002D2D2D2D2D0000ULL, 0x00DEDEDEDEDE0000ULL, 0x0096969696960000ULL,
0x0026262626260000ULL, 0x007D7D7D7D7D0000ULL, 0x00C6C6C6C6C60000ULL, 0x005C5C5C5C5C0000ULL,
0x00D3D3D3D3D30000ULL, 0x00F2F2F2F2F20000ULL, 0x004F4F4F4F4F0000ULL, 0x0019191919190000ULL,
0x003F3F3F3F3F0000ULL, 0x00DCDCDCDCDC0000ULL, 0x0079797979790000ULL, 0x001D1D1D1D1D0000ULL,
0x0052525252520000ULL, 0x00EBEBEBEBEB0000ULL, 0x00F3F3F3F3F30000ULL, 0x006D6D6D6D6D0000ULL,
0x005E5E5E5E5E0000ULL, 0x00FBFBFBFBFB0000ULL, 0x0069696969690000ULL, 0x00B2B2B2B2B20000ULL,
0x00F0F0F0F0F00000ULL, 0x0031313131310000ULL, 0x000C0C0C0C0C0000ULL, 0x00D4D4D4D4D40000ULL,
0x00CFCFCFCFCF0000ULL, 0x008C8C8C8C8C0000ULL, 0x00E2E2E2E2E20000ULL, 0x0075757575750000ULL,
0x00A9A9A9A9A90000ULL, 0x004A4A4A4A4A0000ULL, 0x0057575757570000ULL, 0x0084848484840000ULL,
0x0011111111110000ULL, 0x0045454545450000ULL, 0x001B1B1B1B1B0000ULL, 0x00F5F5F5F5F50000ULL,
0x00E4E4E4E4E40000ULL, 0x000E0E0E0E0E0000ULL, 0x0073737373730000ULL, 0x00AAAAAAAAAA0000ULL,
0x00F1F1F1F1F10000ULL, 0x00DDDDDDDDDD0000ULL, 0x0059595959590000ULL, 0x0014141414140000ULL,
0x006C6C6C6C6C0000ULL, 0x0092929292920000ULL, 0x0054545454540000ULL, 0x00D0D0D0D0D00000ULL,
0x0078787878780000ULL, 0x0070707070700000ULL, 0x00E3E3E3E3E30000ULL, 0x0049494949490000ULL,
0x0080808080800000ULL, 0x0050505050500000ULL, 0x00A7A7A7A7A70000ULL, 0x00F6F6F6F6F60000ULL,
0x0077777777770000ULL, 0x0093939393930000ULL, 0x0086868686860000ULL, 0x0083838383830000ULL,
0x002A2A2A2A2A0000ULL, 0x00C7C7C7C7C70000ULL, 0x005B5B5B5B5B0000ULL, 0x00E9E9E9E9E90000ULL,
0x00EEEEEEEEEE0000ULL, 0x008F8F8F8F8F0000ULL, 0x0001010101010000ULL, 0x003D3D3D3D3D0000ULL };

const u64bit Camellia_SBOX3[256] = {
0x3800383800383800ULL, 0x4100414100414100ULL, 0x1600161600161600ULL, 0x7600767600767600ULL,
0xD900D9D900D9D900ULL, 0x9300939300939300ULL, 0x6000606000606000ULL, 0xF200F2F200F2F200ULL,
0x7200727200727200ULL, 0xC200C2C200C2C200ULL, 0xAB00ABAB00ABAB00ULL, 0x9A009A9A009A9A00ULL,
0x7500757500757500ULL, 0x0600060600060600ULL, 0x5700575700575700ULL, 0xA000A0A000A0A000ULL,
0x9100919100919100ULL, 0xF700F7F700F7F700ULL, 0xB500B5B500B5B500ULL, 0xC900C9C900C9C900ULL,
0xA200A2A200A2A200ULL, 0x8C008C8C008C8C00ULL, 0xD200D2D200D2D200ULL, 0x9000909000909000ULL,
0xF600F6F600F6F600ULL, 0x0700070700070700ULL, 0xA700A7A700A7A700ULL, 0x2700272700272700ULL,
0x8E008E8E008E8E00ULL, 0xB200B2B200B2B200ULL, 0x4900494900494900ULL, 0xDE00DEDE00DEDE00ULL,
0x4300434300434300ULL, 0x5C005C5C005C5C00ULL, 0xD700D7D700D7D700ULL, 0xC700C7C700C7C700ULL,
0x3E003E3E003E3E00ULL, 0xF500F5F500F5F500ULL, 0x8F008F8F008F8F00ULL, 0x6700676700676700ULL,
0x1F001F1F001F1F00ULL, 0x1800181800181800ULL, 0x6E006E6E006E6E00ULL, 0xAF00AFAF00AFAF00ULL,
0x2F002F2F002F2F00ULL, 0xE200E2E200E2E200ULL, 0x8500858500858500ULL, 0x0D000D0D000D0D00ULL,
0x5300535300535300ULL, 0xF000F0F000F0F000ULL, 0x9C009C9C009C9C00ULL, 0x6500656500656500ULL,
0xEA00EAEA00EAEA00ULL, 0xA300A3A300A3A300ULL, 0xAE00AEAE00AEAE00ULL, 0x9E009E9E009E9E00ULL,
0xEC00ECEC00ECEC00ULL, 0x8000808000808000ULL, 0x2D002D2D002D2D00ULL, 0x6B006B6B006B6B00ULL,
0xA800A8A800A8A800ULL, 0x2B002B2B002B2B00ULL, 0x3600363600363600ULL, 0xA600A6A600A6A600ULL,
0xC500C5C500C5C500ULL, 0x8600868600868600ULL, 0x4D004D4D004D4D00ULL, 0x3300333300333300ULL,
0xFD00FDFD00FDFD00ULL, 0x6600666600666600ULL, 0x5800585800585800ULL, 0x9600969600969600ULL,
0x3A003A3A003A3A00ULL, 0x0900090900090900ULL, 0x9500959500959500ULL, 0x1000101000101000ULL,
0x7800787800787800ULL, 0xD800D8D800D8D800ULL, 0x4200424200424200ULL, 0xCC00CCCC00CCCC00ULL,
0xEF00EFEF00EFEF00ULL, 0x2600262600262600ULL, 0xE500E5E500E5E500ULL, 0x6100616100616100ULL,
0x1A001A1A001A1A00ULL, 0x3F003F3F003F3F00ULL, 0x3B003B3B003B3B00ULL, 0x8200828200828200ULL,
0xB600B6B600B6B600ULL, 0xDB00DBDB00DBDB00ULL, 0xD400D4D400D4D400ULL, 0x9800989800989800ULL,
0xE800E8E800E8E800ULL, 0x8B008B8B008B8B00ULL, 0x0200020200020200ULL, 0xEB00EBEB00EBEB00ULL,
0x0A000A0A000A0A00ULL, 0x2C002C2C002C2C00ULL, 0x1D001D1D001D1D00ULL, 0xB000B0B000B0B000ULL,
0x6F006F6F006F6F00ULL, 0x8D008D8D008D8D00ULL, 0x8800888800888800ULL, 0x0E000E0E000E0E00ULL,
0x1900191900191900ULL, 0x8700878700878700ULL, 0x4E004E4E004E4E00ULL, 0x0B000B0B000B0B00ULL,
0xA900A9A900A9A900ULL, 0x0C000C0C000C0C00ULL, 0x7900797900797900ULL, 0x1100111100111100ULL,
0x7F007F7F007F7F00ULL, 0x2200222200222200ULL, 0xE700E7E700E7E700ULL, 0x5900595900595900ULL,
0xE100E1E100E1E100ULL, 0xDA00DADA00DADA00ULL, 0x3D003D3D003D3D00ULL, 0xC800C8C800C8C800ULL,
0x1200121200121200ULL, 0x0400040400040400ULL, 0x7400747400747400ULL, 0x5400545400545400ULL,
0x3000303000303000ULL, 0x7E007E7E007E7E00ULL, 0xB400B4B400B4B400ULL, 0x2800282800282800ULL,
0x5500555500555500ULL, 0x6800686800686800ULL, 0x5000505000505000ULL, 0xBE00BEBE00BEBE00ULL,
0xD000D0D000D0D000ULL, 0xC400C4C400C4C400ULL, 0x3100313100313100ULL, 0xCB00CBCB00CBCB00ULL,
0x2A002A2A002A2A00ULL, 0xAD00ADAD00ADAD00ULL, 0x0F000F0F000F0F00ULL, 0xCA00CACA00CACA00ULL,
0x7000707000707000ULL, 0xFF00FFFF00FFFF00ULL, 0x3200323200323200ULL, 0x6900696900696900ULL,
0x0800080800080800ULL, 0x6200626200626200ULL, 0x0000000000000000ULL, 0x2400242400242400ULL,
0xD100D1D100D1D100ULL, 0xFB00FBFB00FBFB00ULL, 0xBA00BABA00BABA00ULL, 0xED00EDED00EDED00ULL,
0x4500454500454500ULL, 0x8100818100818100ULL, 0x7300737300737300ULL, 0x6D006D6D006D6D00ULL,
0x8400848400848400ULL, 0x9F009F9F009F9F00ULL, 0xEE00EEEE00EEEE00ULL, 0x4A004A4A004A4A00ULL,
0xC300C3C300C3C300ULL, 0x2E002E2E002E2E00ULL, 0xC100C1C100C1C100ULL, 0x0100010100010100ULL,
0xE600E6E600E6E600ULL, 0x2500252500252500ULL, 0x4800484800484800ULL, 0x9900999900999900ULL,
0xB900B9B900B9B900ULL, 0xB300B3B300B3B300ULL, 0x7B007B7B007B7B00ULL, 0xF900F9F900F9F900ULL,
0xCE00CECE00CECE00ULL, 0xBF00BFBF00BFBF00ULL, 0xDF00DFDF00DFDF00ULL, 0x7100717100717100ULL,
0x2900292900292900ULL, 0xCD00CDCD00CDCD00ULL, 0x6C006C6C006C6C00ULL, 0x1300131300131300ULL,
0x6400646400646400ULL, 0x9B009B9B009B9B00ULL, 0x6300636300636300ULL, 0x9D009D9D009D9D00ULL,
0xC000C0C000C0C000ULL, 0x4B004B4B004B4B00ULL, 0xB700B7B700B7B700ULL, 0xA500A5A500A5A500ULL,
0x8900898900898900ULL, 0x5F005F5F005F5F00ULL, 0xB100B1B100B1B100ULL, 0x1700171700171700ULL,
0xF400F4F400F4F400ULL, 0xBC00BCBC00BCBC00ULL, 0xD300D3D300D3D300ULL, 0x4600464600464600ULL,
0xCF00CFCF00CFCF00ULL, 0x3700373700373700ULL, 0x5E005E5E005E5E00ULL, 0x4700474700474700ULL,
0x9400949400949400ULL, 0xFA00FAFA00FAFA00ULL, 0xFC00FCFC00FCFC00ULL, 0x5B005B5B005B5B00ULL,
0x9700979700979700ULL, 0xFE00FEFE00FEFE00ULL, 0x5A005A5A005A5A00ULL, 0xAC00ACAC00ACAC00ULL,
0x3C003C3C003C3C00ULL, 0x4C004C4C004C4C00ULL, 0x0300030300030300ULL, 0x3500353500353500ULL,
0xF300F3F300F3F300ULL, 0x2300232300232300ULL, 0xB800B8B800B8B800ULL, 0x5D005D5D005D5D00ULL,
0x6A006A6A006A6A00ULL, 0x9200929200929200ULL, 0xD500D5D500D5D500ULL, 0x2100212100212100ULL,
0x4400444400444400ULL, 0x5100515100515100ULL, 0xC600C6C600C6C600ULL, 0x7D007D7D007D7D00ULL,
0x3900393900393900ULL, 0x8300838300838300ULL, 0xDC00DCDC00DCDC00ULL, 0xAA00AAAA00AAAA00ULL,
0x7C007C7C007C7C00ULL, 0x7700777700777700ULL, 0x5600565600565600ULL, 0x0500050500050500ULL,
0x1B001B1B001B1B00ULL, 0xA400A4A400A4A400ULL, 0x1500151500151500ULL, 0x3400343400343400ULL,
0x1E001E1E001E1E00ULL, 0x1C001C1C001C1C00ULL, 0xF800F8F800F8F800ULL, 0x5200525200525200ULL,
0x2000202000202000ULL, 0x1400141400141400ULL, 0xE900E9E900E9E900ULL, 0xBD00BDBD00BDBD00ULL,
0xDD00DDDD00DDDD00ULL, 0xE400E4E400E4E400ULL, 0xA100A1A100A1A100ULL, 0xE000E0E000E0E000ULL,
0x8A008A8A008A8A00ULL, 0xF100F1F100F1F100ULL, 0xD600D6D600D6D600ULL, 0x7A007A7A007A7A00ULL,
0xBB00BBBB00BBBB00ULL, 0xE300E3E300E3E300ULL, 0x4000404000404000ULL, 0x4F004F4F004F4F00ULL };

const u64bit Camellia_SBOX4[256] = {
0x7070007000007070ULL, 0x2C2C002C00002C2CULL, 0xB3B300B30000B3B3ULL, 0xC0C000C00000C0C0ULL,
0xE4E400E40000E4E4ULL, 0x5757005700005757ULL, 0xEAEA00EA0000EAEAULL, 0xAEAE00AE0000AEAEULL,
0x2323002300002323ULL, 0x6B6B006B00006B6BULL, 0x4545004500004545ULL, 0xA5A500A50000A5A5ULL,
0xEDED00ED0000EDEDULL, 0x4F4F004F00004F4FULL, 0x1D1D001D00001D1DULL, 0x9292009200009292ULL,
0x8686008600008686ULL, 0xAFAF00AF0000AFAFULL, 0x7C7C007C00007C7CULL, 0x1F1F001F00001F1FULL,
0x3E3E003E00003E3EULL, 0xDCDC00DC0000DCDCULL, 0x5E5E005E00005E5EULL, 0x0B0B000B00000B0BULL,
0xA6A600A60000A6A6ULL, 0x3939003900003939ULL, 0xD5D500D50000D5D5ULL, 0x5D5D005D00005D5DULL,
0xD9D900D90000D9D9ULL, 0x5A5A005A00005A5AULL, 0x5151005100005151ULL, 0x6C6C006C00006C6CULL,
0x8B8B008B00008B8BULL, 0x9A9A009A00009A9AULL, 0xFBFB00FB0000FBFBULL, 0xB0B000B00000B0B0ULL,
0x7474007400007474ULL, 0x2B2B002B00002B2BULL, 0xF0F000F00000F0F0ULL, 0x8484008400008484ULL,
0xDFDF00DF0000DFDFULL, 0xCBCB00CB0000CBCBULL, 0x3434003400003434ULL, 0x7676007600007676ULL,
0x6D6D006D00006D6DULL, 0xA9A900A90000A9A9ULL, 0xD1D100D10000D1D1ULL, 0x0404000400000404ULL,
0x1414001400001414ULL, 0x3A3A003A00003A3AULL, 0xDEDE00DE0000DEDEULL, 0x1111001100001111ULL,
0x3232003200003232ULL, 0x9C9C009C00009C9CULL, 0x5353005300005353ULL, 0xF2F200F20000F2F2ULL,
0xFEFE00FE0000FEFEULL, 0xCFCF00CF0000CFCFULL, 0xC3C300C30000C3C3ULL, 0x7A7A007A00007A7AULL,
0x2424002400002424ULL, 0xE8E800E80000E8E8ULL, 0x6060006000006060ULL, 0x6969006900006969ULL,
0xAAAA00AA0000AAAAULL, 0xA0A000A00000A0A0ULL, 0xA1A100A10000A1A1ULL, 0x6262006200006262ULL,
0x5454005400005454ULL, 0x1E1E001E00001E1EULL, 0xE0E000E00000E0E0ULL, 0x6464006400006464ULL,
0x1010001000001010ULL, 0x0000000000000000ULL, 0xA3A300A30000A3A3ULL, 0x7575007500007575ULL,
0x8A8A008A00008A8AULL, 0xE6E600E60000E6E6ULL, 0x0909000900000909ULL, 0xDDDD00DD0000DDDDULL,
0x8787008700008787ULL, 0x8383008300008383ULL, 0xCDCD00CD0000CDCDULL, 0x9090009000009090ULL,
0x7373007300007373ULL, 0xF6F600F60000F6F6ULL, 0x9D9D009D00009D9DULL, 0xBFBF00BF0000BFBFULL,
0x5252005200005252ULL, 0xD8D800D80000D8D8ULL, 0xC8C800C80000C8C8ULL, 0xC6C600C60000C6C6ULL,
0x8181008100008181ULL, 0x6F6F006F00006F6FULL, 0x1313001300001313ULL, 0x6363006300006363ULL,
0xE9E900E90000E9E9ULL, 0xA7A700A70000A7A7ULL, 0x9F9F009F00009F9FULL, 0xBCBC00BC0000BCBCULL,
0x2929002900002929ULL, 0xF9F900F90000F9F9ULL, 0x2F2F002F00002F2FULL, 0xB4B400B40000B4B4ULL,
0x7878007800007878ULL, 0x0606000600000606ULL, 0xE7E700E70000E7E7ULL, 0x7171007100007171ULL,
0xD4D400D40000D4D4ULL, 0xABAB00AB0000ABABULL, 0x8888008800008888ULL, 0x8D8D008D00008D8DULL,
0x7272007200007272ULL, 0xB9B900B90000B9B9ULL, 0xF8F800F80000F8F8ULL, 0xACAC00AC0000ACACULL,
0x3636003600003636ULL, 0x2A2A002A00002A2AULL, 0x3C3C003C00003C3CULL, 0xF1F100F10000F1F1ULL,
0x4040004000004040ULL, 0xD3D300D30000D3D3ULL, 0xBBBB00BB0000BBBBULL, 0x4343004300004343ULL,
0x1515001500001515ULL, 0xADAD00AD0000ADADULL, 0x7777007700007777ULL, 0x8080008000008080ULL,
0x8282008200008282ULL, 0xECEC00EC0000ECECULL, 0x2727002700002727ULL, 0xE5E500E50000E5E5ULL,
0x8585008500008585ULL, 0x3535003500003535ULL, 0x0C0C000C00000C0CULL, 0x4141004100004141ULL,
0xEFEF00EF0000EFEFULL, 0x9393009300009393ULL, 0x1919001900001919ULL, 0x2121002100002121ULL,
0x0E0E000E00000E0EULL, 0x4E4E004E00004E4EULL, 0x6565006500006565ULL, 0xBDBD00BD0000BDBDULL,
0xB8B800B80000B8B8ULL, 0x8F8F008F00008F8FULL, 0xEBEB00EB0000EBEBULL, 0xCECE00CE0000CECEULL,
0x3030003000003030ULL, 0x5F5F005F00005F5FULL, 0xC5C500C50000C5C5ULL, 0x1A1A001A00001A1AULL,
0xE1E100E10000E1E1ULL, 0xCACA00CA0000CACAULL, 0x4747004700004747ULL, 0x3D3D003D00003D3DULL,
0x0101000100000101ULL, 0xD6D600D60000D6D6ULL, 0x5656005600005656ULL, 0x4D4D004D00004D4DULL,
0x0D0D000D00000D0DULL, 0x6666006600006666ULL, 0xCCCC00CC0000CCCCULL, 0x2D2D002D00002D2DULL,
0x1212001200001212ULL, 0x2020002000002020ULL, 0xB1B100B10000B1B1ULL, 0x9999009900009999ULL,
0x4C4C004C00004C4CULL, 0xC2C200C20000C2C2ULL, 0x7E7E007E00007E7EULL, 0x0505000500000505ULL,
0xB7B700B70000B7B7ULL, 0x3131003100003131ULL, 0x1717001700001717ULL, 0xD7D700D70000D7D7ULL,
0x5858005800005858ULL, 0x6161006100006161ULL, 0x1B1B001B00001B1BULL, 0x1C1C001C00001C1CULL,
0x0F0F000F00000F0FULL, 0x1616001600001616ULL, 0x1818001800001818ULL, 0x2222002200002222ULL,
0x4444004400004444ULL, 0xB2B200B20000B2B2ULL, 0xB5B500B50000B5B5ULL, 0x9191009100009191ULL,
0x0808000800000808ULL, 0xA8A800A80000A8A8ULL, 0xFCFC00FC0000FCFCULL, 0x5050005000005050ULL,
0xD0D000D00000D0D0ULL, 0x7D7D007D00007D7DULL, 0x8989008900008989ULL, 0x9797009700009797ULL,
0x5B5B005B00005B5BULL, 0x9595009500009595ULL, 0xFFFF00FF0000FFFFULL, 0xD2D200D20000D2D2ULL,
0xC4C400C40000C4C4ULL, 0x4848004800004848ULL, 0xF7F700F70000F7F7ULL, 0xDBDB00DB0000DBDBULL,
0x0303000300000303ULL, 0xDADA00DA0000DADAULL, 0x3F3F003F00003F3FULL, 0x9494009400009494ULL,
0x5C5C005C00005C5CULL, 0x0202000200000202ULL, 0x4A4A004A00004A4AULL, 0x3333003300003333ULL,
0x6767006700006767ULL, 0xF3F300F30000F3F3ULL, 0x7F7F007F00007F7FULL, 0xE2E200E20000E2E2ULL,
0x9B9B009B00009B9BULL, 0x2626002600002626ULL, 0x3737003700003737ULL, 0x3B3B003B00003B3BULL,
0x9696009600009696ULL, 0x4B4B004B00004B4BULL, 0xBEBE00BE0000BEBEULL, 0x2E2E002E00002E2EULL,
0x7979007900007979ULL, 0x8C8C008C00008C8CULL, 0x6E6E006E00006E6EULL, 0x8E8E008E00008E8EULL,
0xF5F500F50000F5F5ULL, 0xB6B600B60000B6B6ULL, 0xFDFD00FD0000FDFDULL, 0x5959005900005959ULL,
0x9898009800009898ULL, 0x6A6A006A00006A6AULL, 0x4646004600004646ULL, 0xBABA00BA0000BABAULL,
0x2525002500002525ULL, 0x4242004200004242ULL, 0xA2A200A20000A2A2ULL, 0xFAFA00FA0000FAFAULL,
0x0707000700000707ULL, 0x5555005500005555ULL, 0xEEEE00EE0000EEEEULL, 0x0A0A000A00000A0AULL,
0x4949004900004949ULL, 0x6868006800006868ULL, 0x3838003800003838ULL, 0xA4A400A40000A4A4ULL,
0x2828002800002828ULL, 0x7B7B007B00007B7BULL, 0xC9C900C90000C9C9ULL, 0xC1C100C10000C1C1ULL,
0xE3E300E30000E3E3ULL, 0xF4F400F40000F4F4ULL, 0xC7C700C70000C7C7ULL, 0x9E9E009E00009E9EULL };

const u64bit Camellia_SBOX5[256] = {
0x00E0E0E000E0E0E0ULL, 0x0005050500050505ULL, 0x0058585800585858ULL, 0x00D9D9D900D9D9D9ULL,
0x0067676700676767ULL, 0x004E4E4E004E4E4EULL, 0x0081818100818181ULL, 0x00CBCBCB00CBCBCBULL,
0x00C9C9C900C9C9C9ULL, 0x000B0B0B000B0B0BULL, 0x00AEAEAE00AEAEAEULL, 0x006A6A6A006A6A6AULL,
0x00D5D5D500D5D5D5ULL, 0x0018181800181818ULL, 0x005D5D5D005D5D5DULL, 0x0082828200828282ULL,
0x0046464600464646ULL, 0x00DFDFDF00DFDFDFULL, 0x00D6D6D600D6D6D6ULL, 0x0027272700272727ULL,
0x008A8A8A008A8A8AULL, 0x0032323200323232ULL, 0x004B4B4B004B4B4BULL, 0x0042424200424242ULL,
0x00DBDBDB00DBDBDBULL, 0x001C1C1C001C1C1CULL, 0x009E9E9E009E9E9EULL, 0x009C9C9C009C9C9CULL,
0x003A3A3A003A3A3AULL, 0x00CACACA00CACACAULL, 0x0025252500252525ULL, 0x007B7B7B007B7B7BULL,
0x000D0D0D000D0D0DULL, 0x0071717100717171ULL, 0x005F5F5F005F5F5FULL, 0x001F1F1F001F1F1FULL,
0x00F8F8F800F8F8F8ULL, 0x00D7D7D700D7D7D7ULL, 0x003E3E3E003E3E3EULL, 0x009D9D9D009D9D9DULL,
0x007C7C7C007C7C7CULL, 0x0060606000606060ULL, 0x00B9B9B900B9B9B9ULL, 0x00BEBEBE00BEBEBEULL,
0x00BCBCBC00BCBCBCULL, 0x008B8B8B008B8B8BULL, 0x0016161600161616ULL, 0x0034343400343434ULL,
0x004D4D4D004D4D4DULL, 0x00C3C3C300C3C3C3ULL, 0x0072727200727272ULL, 0x0095959500959595ULL,
0x00ABABAB00ABABABULL, 0x008E8E8E008E8E8EULL, 0x00BABABA00BABABAULL, 0x007A7A7A007A7A7AULL,
0x00B3B3B300B3B3B3ULL, 0x0002020200020202ULL, 0x00B4B4B400B4B4B4ULL, 0x00ADADAD00ADADADULL,
0x00A2A2A200A2A2A2ULL, 0x00ACACAC00ACACACULL, 0x00D8D8D800D8D8D8ULL, 0x009A9A9A009A9A9AULL,
0x0017171700171717ULL, 0x001A1A1A001A1A1AULL, 0x0035353500353535ULL, 0x00CCCCCC00CCCCCCULL,
0x00F7F7F700F7F7F7ULL, 0x0099999900999999ULL, 0x0061616100616161ULL, 0x005A5A5A005A5A5AULL,
0x00E8E8E800E8E8E8ULL, 0x0024242400242424ULL, 0x0056565600565656ULL, 0x0040404000404040ULL,
0x00E1E1E100E1E1E1ULL, 0x0063636300636363ULL, 0x0009090900090909ULL, 0x0033333300333333ULL,
0x00BFBFBF00BFBFBFULL, 0x0098989800989898ULL, 0x0097979700979797ULL, 0x0085858500858585ULL,
0x0068686800686868ULL, 0x00FCFCFC00FCFCFCULL, 0x00ECECEC00ECECECULL, 0x000A0A0A000A0A0AULL,
0x00DADADA00DADADAULL, 0x006F6F6F006F6F6FULL, 0x0053535300535353ULL, 0x0062626200626262ULL,
0x00A3A3A300A3A3A3ULL, 0x002E2E2E002E2E2EULL, 0x0008080800080808ULL, 0x00AFAFAF00AFAFAFULL,
0x0028282800282828ULL, 0x00B0B0B000B0B0B0ULL, 0x0074747400747474ULL, 0x00C2C2C200C2C2C2ULL,
0x00BDBDBD00BDBDBDULL, 0x0036363600363636ULL, 0x0022222200222222ULL, 0x0038383800383838ULL,
0x0064646400646464ULL, 0x001E1E1E001E1E1EULL, 0x0039393900393939ULL, 0x002C2C2C002C2C2CULL,
0x00A6A6A600A6A6A6ULL, 0x0030303000303030ULL, 0x00E5E5E500E5E5E5ULL, 0x0044444400444444ULL,
0x00FDFDFD00FDFDFDULL, 0x0088888800888888ULL, 0x009F9F9F009F9F9FULL, 0x0065656500656565ULL,
0x0087878700878787ULL, 0x006B6B6B006B6B6BULL, 0x00F4F4F400F4F4F4ULL, 0x0023232300232323ULL,
0x0048484800484848ULL, 0x0010101000101010ULL, 0x00D1D1D100D1D1D1ULL, 0x0051515100515151ULL,
0x00C0C0C000C0C0C0ULL, 0x00F9F9F900F9F9F9ULL, 0x00D2D2D200D2D2D2ULL, 0x00A0A0A000A0A0A0ULL,
0x0055555500555555ULL, 0x00A1A1A100A1A1A1ULL, 0x0041414100414141ULL, 0x00FAFAFA00FAFAFAULL,
0x0043434300434343ULL, 0x0013131300131313ULL, 0x00C4C4C400C4C4C4ULL, 0x002F2F2F002F2F2FULL,
0x00A8A8A800A8A8A8ULL, 0x00B6B6B600B6B6B6ULL, 0x003C3C3C003C3C3CULL, 0x002B2B2B002B2B2BULL,
0x00C1C1C100C1C1C1ULL, 0x00FFFFFF00FFFFFFULL, 0x00C8C8C800C8C8C8ULL, 0x00A5A5A500A5A5A5ULL,
0x0020202000202020ULL, 0x0089898900898989ULL, 0x0000000000000000ULL, 0x0090909000909090ULL,
0x0047474700474747ULL, 0x00EFEFEF00EFEFEFULL, 0x00EAEAEA00EAEAEAULL, 0x00B7B7B700B7B7B7ULL,
0x0015151500151515ULL, 0x0006060600060606ULL, 0x00CDCDCD00CDCDCDULL, 0x00B5B5B500B5B5B5ULL,
0x0012121200121212ULL, 0x007E7E7E007E7E7EULL, 0x00BBBBBB00BBBBBBULL, 0x0029292900292929ULL,
0x000F0F0F000F0F0FULL, 0x00B8B8B800B8B8B8ULL, 0x0007070700070707ULL, 0x0004040400040404ULL,
0x009B9B9B009B9B9BULL, 0x0094949400949494ULL, 0x0021212100212121ULL, 0x0066666600666666ULL,
0x00E6E6E600E6E6E6ULL, 0x00CECECE00CECECEULL, 0x00EDEDED00EDEDEDULL, 0x00E7E7E700E7E7E7ULL,
0x003B3B3B003B3B3BULL, 0x00FEFEFE00FEFEFEULL, 0x007F7F7F007F7F7FULL, 0x00C5C5C500C5C5C5ULL,
0x00A4A4A400A4A4A4ULL, 0x0037373700373737ULL, 0x00B1B1B100B1B1B1ULL, 0x004C4C4C004C4C4CULL,
0x0091919100919191ULL, 0x006E6E6E006E6E6EULL, 0x008D8D8D008D8D8DULL, 0x0076767600767676ULL,
0x0003030300030303ULL, 0x002D2D2D002D2D2DULL, 0x00DEDEDE00DEDEDEULL, 0x0096969600969696ULL,
0x0026262600262626ULL, 0x007D7D7D007D7D7DULL, 0x00C6C6C600C6C6C6ULL, 0x005C5C5C005C5C5CULL,
0x00D3D3D300D3D3D3ULL, 0x00F2F2F200F2F2F2ULL, 0x004F4F4F004F4F4FULL, 0x0019191900191919ULL,
0x003F3F3F003F3F3FULL, 0x00DCDCDC00DCDCDCULL, 0x0079797900797979ULL, 0x001D1D1D001D1D1DULL,
0x0052525200525252ULL, 0x00EBEBEB00EBEBEBULL, 0x00F3F3F300F3F3F3ULL, 0x006D6D6D006D6D6DULL,
0x005E5E5E005E5E5EULL, 0x00FBFBFB00FBFBFBULL, 0x0069696900696969ULL, 0x00B2B2B200B2B2B2ULL,
0x00F0F0F000F0F0F0ULL, 0x0031313100313131ULL, 0x000C0C0C000C0C0CULL, 0x00D4D4D400D4D4D4ULL,
0x00CFCFCF00CFCFCFULL, 0x008C8C8C008C8C8CULL, 0x00E2E2E200E2E2E2ULL, 0x0075757500757575ULL,
0x00A9A9A900A9A9A9ULL, 0x004A4A4A004A4A4AULL, 0x0057575700575757ULL, 0x0084848400848484ULL,
0x0011111100111111ULL, 0x0045454500454545ULL, 0x001B1B1B001B1B1BULL, 0x00F5F5F500F5F5F5ULL,
0x00E4E4E400E4E4E4ULL, 0x000E0E0E000E0E0EULL, 0x0073737300737373ULL, 0x00AAAAAA00AAAAAAULL,
0x00F1F1F100F1F1F1ULL, 0x00DDDDDD00DDDDDDULL, 0x0059595900595959ULL, 0x0014141400141414ULL,
0x006C6C6C006C6C6CULL, 0x0092929200929292ULL, 0x0054545400545454ULL, 0x00D0D0D000D0D0D0ULL,
0x0078787800787878ULL, 0x0070707000707070ULL, 0x00E3E3E300E3E3E3ULL, 0x0049494900494949ULL,
0x0080808000808080ULL, 0x0050505000505050ULL, 0x00A7A7A700A7A7A7ULL, 0x00F6F6F600F6F6F6ULL,
0x0077777700777777ULL, 0x0093939300939393ULL, 0x0086868600868686ULL, 0x0083838300838383ULL,
0x002A2A2A002A2A2AULL, 0x00C7C7C700C7C7C7ULL, 0x005B5B5B005B5B5BULL, 0x00E9E9E900E9E9E9ULL,
0x00EEEEEE00EEEEEEULL, 0x008F8F8F008F8F8FULL, 0x0001010100010101ULL, 0x003D3D3D003D3D3DULL };

const u64bit Camellia_SBOX6[256] = {
0x3800383838003838ULL, 0x4100414141004141ULL, 0x1600161616001616ULL, 0x7600767676007676ULL,
0xD900D9D9D900D9D9ULL, 0x9300939393009393ULL, 0x6000606060006060ULL, 0xF200F2F2F200F2F2ULL,
0x7200727272007272ULL, 0xC200C2C2C200C2C2ULL, 0xAB00ABABAB00ABABULL, 0x9A009A9A9A009A9AULL,
0x7500757575007575ULL, 0x0600060606000606ULL, 0x5700575757005757ULL, 0xA000A0A0A000A0A0ULL,
0x9100919191009191ULL, 0xF700F7F7F700F7F7ULL, 0xB500B5B5B500B5B5ULL, 0xC900C9C9C900C9C9ULL,
0xA200A2A2A200A2A2ULL, 0x8C008C8C8C008C8CULL, 0xD200D2D2D200D2D2ULL, 0x9000909090009090ULL,
0xF600F6F6F600F6F6ULL, 0x0700070707000707ULL, 0xA700A7A7A700A7A7ULL, 0x2700272727002727ULL,
0x8E008E8E8E008E8EULL, 0xB200B2B2B200B2B2ULL, 0x4900494949004949ULL, 0xDE00DEDEDE00DEDEULL,
0x4300434343004343ULL, 0x5C005C5C5C005C5CULL, 0xD700D7D7D700D7D7ULL, 0xC700C7C7C700C7C7ULL,
0x3E003E3E3E003E3EULL, 0xF500F5F5F500F5F5ULL, 0x8F008F8F8F008F8FULL, 0x6700676767006767ULL,
0x1F001F1F1F001F1FULL, 0x1800181818001818ULL, 0x6E006E6E6E006E6EULL, 0xAF00AFAFAF00AFAFULL,
0x2F002F2F2F002F2FULL, 0xE200E2E2E200E2E2ULL, 0x8500858585008585ULL, 0x0D000D0D0D000D0DULL,
0x5300535353005353ULL, 0xF000F0F0F000F0F0ULL, 0x9C009C9C9C009C9CULL, 0x6500656565006565ULL,
0xEA00EAEAEA00EAEAULL, 0xA300A3A3A300A3A3ULL, 0xAE00AEAEAE00AEAEULL, 0x9E009E9E9E009E9EULL,
0xEC00ECECEC00ECECULL, 0x8000808080008080ULL, 0x2D002D2D2D002D2DULL, 0x6B006B6B6B006B6BULL,
0xA800A8A8A800A8A8ULL, 0x2B002B2B2B002B2BULL, 0x3600363636003636ULL, 0xA600A6A6A600A6A6ULL,
0xC500C5C5C500C5C5ULL, 0x8600868686008686ULL, 0x4D004D4D4D004D4DULL, 0x3300333333003333ULL,
0xFD00FDFDFD00FDFDULL, 0x6600666666006666ULL, 0x5800585858005858ULL, 0x9600969696009696ULL,
0x3A003A3A3A003A3AULL, 0x0900090909000909ULL, 0x9500959595009595ULL, 0x1000101010001010ULL,
0x7800787878007878ULL, 0xD800D8D8D800D8D8ULL, 0x4200424242004242ULL, 0xCC00CCCCCC00CCCCULL,
0xEF00EFEFEF00EFEFULL, 0x2600262626002626ULL, 0xE500E5E5E500E5E5ULL, 0x6100616161006161ULL,
0x1A001A1A1A001A1AULL, 0x3F003F3F3F003F3FULL, 0x3B003B3B3B003B3BULL, 0x8200828282008282ULL,
0xB600B6B6B600B6B6ULL, 0xDB00DBDBDB00DBDBULL, 0xD400D4D4D400D4D4ULL, 0x9800989898009898ULL,
0xE800E8E8E800E8E8ULL, 0x8B008B8B8B008B8BULL, 0x0200020202000202ULL, 0xEB00EBEBEB00EBEBULL,
0x0A000A0A0A000A0AULL, 0x2C002C2C2C002C2CULL, 0x1D001D1D1D001D1DULL, 0xB000B0B0B000B0B0ULL,
0x6F006F6F6F006F6FULL, 0x8D008D8D8D008D8DULL, 0x8800888888008888ULL, 0x0E000E0E0E000E0EULL,
0x1900191919001919ULL, 0x8700878787008787ULL, 0x4E004E4E4E004E4EULL, 0x0B000B0B0B000B0BULL,
0xA900A9A9A900A9A9ULL, 0x0C000C0C0C000C0CULL, 0x7900797979007979ULL, 0x1100111111001111ULL,
0x7F007F7F7F007F7FULL, 0x2200222222002222ULL, 0xE700E7E7E700E7E7ULL, 0x5900595959005959ULL,
0xE100E1E1E100E1E1ULL, 0xDA00DADADA00DADAULL, 0x3D003D3D3D003D3DULL, 0xC800C8C8C800C8C8ULL,
0x1200121212001212ULL, 0x0400040404000404ULL, 0x7400747474007474ULL, 0x5400545454005454ULL,
0x3000303030003030ULL, 0x7E007E7E7E007E7EULL, 0xB400B4B4B400B4B4ULL, 0x2800282828002828ULL,
0x5500555555005555ULL, 0x6800686868006868ULL, 0x5000505050005050ULL, 0xBE00BEBEBE00BEBEULL,
0xD000D0D0D000D0D0ULL, 0xC400C4C4C400C4C4ULL, 0x3100313131003131ULL, 0xCB00CBCBCB00CBCBULL,
0x2A002A2A2A002A2AULL, 0xAD00ADADAD00ADADULL, 0x0F000F0F0F000F0FULL, 0xCA00CACACA00CACAULL,
0x7000707070007070ULL, 0xFF00FFFFFF00FFFFULL, 0x3200323232003232ULL, 0x6900696969006969ULL,
0x0800080808000808ULL, 0x6200626262006262ULL, 0x0000000000000000ULL, 0x2400242424002424ULL,
0xD100D1D1D100D1D1ULL, 0xFB00FBFBFB00FBFBULL, 0xBA00BABABA00BABAULL, 0xED00EDEDED00EDEDULL,
0x4500454545004545ULL, 0x8100818181008181ULL, 0x7300737373007373ULL, 0x6D006D6D6D006D6DULL,
0x8400848484008484ULL, 0x9F009F9F9F009F9FULL, 0xEE00EEEEEE00EEEEULL, 0x4A004A4A4A004A4AULL,
0xC300C3C3C300C3C3ULL, 0x2E002E2E2E002E2EULL, 0xC100C1C1C100C1C1ULL, 0x0100010101000101ULL,
0xE600E6E6E600E6E6ULL, 0x2500252525002525ULL, 0x4800484848004848ULL, 0x9900999999009999ULL,
0xB900B9B9B900B9B9ULL, 0xB300B3B3B300B3B3ULL, 0x7B007B7B7B007B7BULL, 0xF900F9F9F900F9F9ULL,
0xCE00CECECE00CECEULL, 0xBF00BFBFBF00BFBFULL, 0xDF00DFDFDF00DFDFULL, 0x7100717171007171ULL,
0x2900292929002929ULL, 0xCD00CDCDCD00CDCDULL, 0x6C006C6C6C006C6CULL, 0x1300131313001313ULL,
0x6400646464006464ULL, 0x9B009B9B9B009B9BULL, 0x6300636363006363ULL, 0x9D009D9D9D009D9DULL,
0xC000C0C0C000C0C0ULL, 0x4B004B4B4B004B4BULL, 0xB700B7B7B700B7B7ULL, 0xA500A5A5A500A5A5ULL,
0x8900898989008989ULL, 0x5F005F5F5F005F5FULL, 0xB100B1B1B100B1B1ULL, 0x1700171717001717ULL,
0xF400F4F4F400F4F4ULL, 0xBC00BCBCBC00BCBCULL, 0xD300D3D3D300D3D3ULL, 0x4600464646004646ULL,
0xCF00CFCFCF00CFCFULL, 0x3700373737003737ULL, 0x5E005E5E5E005E5EULL, 0x4700474747004747ULL,
0x9400949494009494ULL, 0xFA00FAFAFA00FAFAULL, 0xFC00FCFCFC00FCFCULL, 0x5B005B5B5B005B5BULL,
0x9700979797009797ULL, 0xFE00FEFEFE00FEFEULL, 0x5A005A5A5A005A5AULL, 0xAC00ACACAC00ACACULL,
0x3C003C3C3C003C3CULL, 0x4C004C4C4C004C4CULL, 0x0300030303000303ULL, 0x3500353535003535ULL,
0xF300F3F3F300F3F3ULL, 0x2300232323002323ULL, 0xB800B8B8B800B8B8ULL, 0x5D005D5D5D005D5DULL,
0x6A006A6A6A006A6AULL, 0x9200929292009292ULL, 0xD500D5D5D500D5D5ULL, 0x2100212121002121ULL,
0x4400444444004444ULL, 0x5100515151005151ULL, 0xC600C6C6C600C6C6ULL, 0x7D007D7D7D007D7DULL,
0x3900393939003939ULL, 0x8300838383008383ULL, 0xDC00DCDCDC00DCDCULL, 0xAA00AAAAAA00AAAAULL,
0x7C007C7C7C007C7CULL, 0x7700777777007777ULL, 0x5600565656005656ULL, 0x0500050505000505ULL,
0x1B001B1B1B001B1BULL, 0xA400A4A4A400A4A4ULL, 0x1500151515001515ULL, 0x3400343434003434ULL,
0x1E001E1E1E001E1EULL, 0x1C001C1C1C001C1CULL, 0xF800F8F8F800F8F8ULL, 0x5200525252005252ULL,
0x2000202020002020ULL, 0x1400141414001414ULL, 0xE900E9E9E900E9E9ULL, 0xBD00BDBDBD00BDBDULL,
0xDD00DDDDDD00DDDDULL, 0xE400E4E4E400E4E4ULL, 0xA100A1A1A100A1A1ULL, 0xE000E0E0E000E0E0ULL,
0x8A008A8A8A008A8AULL, 0xF100F1F1F100F1F1ULL, 0xD600D6D6D600D6D6ULL, 0x7A007A7A7A007A7AULL,
0xBB00BBBBBB00BBBBULL, 0xE300E3E3E300E3E3ULL, 0x4000404040004040ULL, 0x4F004F4F4F004F4FULL };

const u64bit Camellia_SBOX7[256] = {
0x7070007070700070ULL, 0x2C2C002C2C2C002CULL, 0xB3B300B3B3B300B3ULL, 0xC0C000C0C0C000C0ULL,
0xE4E400E4E4E400E4ULL, 0x5757005757570057ULL, 0xEAEA00EAEAEA00EAULL, 0xAEAE00AEAEAE00AEULL,
0x2323002323230023ULL, 0x6B6B006B6B6B006BULL, 0x4545004545450045ULL, 0xA5A500A5A5A500A5ULL,
0xEDED00EDEDED00EDULL, 0x4F4F004F4F4F004FULL, 0x1D1D001D1D1D001DULL, 0x9292009292920092ULL,
0x8686008686860086ULL, 0xAFAF00AFAFAF00AFULL, 0x7C7C007C7C7C007CULL, 0x1F1F001F1F1F001FULL,
0x3E3E003E3E3E003EULL, 0xDCDC00DCDCDC00DCULL, 0x5E5E005E5E5E005EULL, 0x0B0B000B0B0B000BULL,
0xA6A600A6A6A600A6ULL, 0x3939003939390039ULL, 0xD5D500D5D5D500D5ULL, 0x5D5D005D5D5D005DULL,
0xD9D900D9D9D900D9ULL, 0x5A5A005A5A5A005AULL, 0x5151005151510051ULL, 0x6C6C006C6C6C006CULL,
0x8B8B008B8B8B008BULL, 0x9A9A009A9A9A009AULL, 0xFBFB00FBFBFB00FBULL, 0xB0B000B0B0B000B0ULL,
0x7474007474740074ULL, 0x2B2B002B2B2B002BULL, 0xF0F000F0F0F000F0ULL, 0x8484008484840084ULL,
0xDFDF00DFDFDF00DFULL, 0xCBCB00CBCBCB00CBULL, 0x3434003434340034ULL, 0x7676007676760076ULL,
0x6D6D006D6D6D006DULL, 0xA9A900A9A9A900A9ULL, 0xD1D100D1D1D100D1ULL, 0x0404000404040004ULL,
0x1414001414140014ULL, 0x3A3A003A3A3A003AULL, 0xDEDE00DEDEDE00DEULL, 0x1111001111110011ULL,
0x3232003232320032ULL, 0x9C9C009C9C9C009CULL, 0x5353005353530053ULL, 0xF2F200F2F2F200F2ULL,
0xFEFE00FEFEFE00FEULL, 0xCFCF00CFCFCF00CFULL, 0xC3C300C3C3C300C3ULL, 0x7A7A007A7A7A007AULL,
0x2424002424240024ULL, 0xE8E800E8E8E800E8ULL, 0x6060006060600060ULL, 0x6969006969690069ULL,
0xAAAA00AAAAAA00AAULL, 0xA0A000A0A0A000A0ULL, 0xA1A100A1A1A100A1ULL, 0x6262006262620062ULL,
0x5454005454540054ULL, 0x1E1E001E1E1E001EULL, 0xE0E000E0E0E000E0ULL, 0x6464006464640064ULL,
0x1010001010100010ULL, 0x0000000000000000ULL, 0xA3A300A3A3A300A3ULL, 0x7575007575750075ULL,
0x8A8A008A8A8A008AULL, 0xE6E600E6E6E600E6ULL, 0x0909000909090009ULL, 0xDDDD00DDDDDD00DDULL,
0x8787008787870087ULL, 0x8383008383830083ULL, 0xCDCD00CDCDCD00CDULL, 0x9090009090900090ULL,
0x7373007373730073ULL, 0xF6F600F6F6F600F6ULL, 0x9D9D009D9D9D009DULL, 0xBFBF00BFBFBF00BFULL,
0x5252005252520052ULL, 0xD8D800D8D8D800D8ULL, 0xC8C800C8C8C800C8ULL, 0xC6C600C6C6C600C6ULL,
0x8181008181810081ULL, 0x6F6F006F6F6F006FULL, 0x1313001313130013ULL, 0x6363006363630063ULL,
0xE9E900E9E9E900E9ULL, 0xA7A700A7A7A700A7ULL, 0x9F9F009F9F9F009FULL, 0xBCBC00BCBCBC00BCULL,
0x2929002929290029ULL, 0xF9F900F9F9F900F9ULL, 0x2F2F002F2F2F002FULL, 0xB4B400B4B4B400B4ULL,
0x7878007878780078ULL, 0x0606000606060006ULL, 0xE7E700E7E7E700E7ULL, 0x7171007171710071ULL,
0xD4D400D4D4D400D4ULL, 0xABAB00ABABAB00ABULL, 0x8888008888880088ULL, 0x8D8D008D8D8D008DULL,
0x7272007272720072ULL, 0xB9B900B9B9B900B9ULL, 0xF8F800F8F8F800F8ULL, 0xACAC00ACACAC00ACULL,
0x3636003636360036ULL, 0x2A2A002A2A2A002AULL, 0x3C3C003C3C3C003CULL, 0xF1F100F1F1F100F1ULL,
0x4040004040400040ULL, 0xD3D300D3D3D300D3ULL, 0xBBBB00BBBBBB00BBULL, 0x4343004343430043ULL,
0x1515001515150015ULL, 0xADAD00ADADAD00ADULL, 0x7777007777770077ULL, 0x8080008080800080ULL,
0x8282008282820082ULL, 0xECEC00ECECEC00ECULL, 0x2727002727270027ULL, 0xE5E500E5E5E500E5ULL,
0x8585008585850085ULL, 0x3535003535350035ULL, 0x0C0C000C0C0C000CULL, 0x4141004141410041ULL,
0xEFEF00EFEFEF00EFULL, 0x9393009393930093ULL, 0x1919001919190019ULL, 0x2121002121210021ULL,
0x0E0E000E0E0E000EULL, 0x4E4E004E4E4E004EULL, 0x6565006565650065ULL, 0xBDBD00BDBDBD00BDULL,
0xB8B800B8B8B800B8ULL, 0x8F8F008F8F8F008FULL, 0xEBEB00EBEBEB00EBULL, 0xCECE00CECECE00CEULL,
0x3030003030300030ULL, 0x5F5F005F5F5F005FULL, 0xC5C500C5C5C500C5ULL, 0x1A1A001A1A1A001AULL,
0xE1E100E1E1E100E1ULL, 0xCACA00CACACA00CAULL, 0x4747004747470047ULL, 0x3D3D003D3D3D003DULL,
0x0101000101010001ULL, 0xD6D600D6D6D600D6ULL, 0x5656005656560056ULL, 0x4D4D004D4D4D004DULL,
0x0D0D000D0D0D000DULL, 0x6666006666660066ULL, 0xCCCC00CCCCCC00CCULL, 0x2D2D002D2D2D002DULL,
0x1212001212120012ULL, 0x2020002020200020ULL, 0xB1B100B1B1B100B1ULL, 0x9999009999990099ULL,
0x4C4C004C4C4C004CULL, 0xC2C200C2C2C200C2ULL, 0x7E7E007E7E7E007EULL, 0x0505000505050005ULL,
0xB7B700B7B7B700B7ULL, 0x3131003131310031ULL, 0x1717001717170017ULL, 0xD7D700D7D7D700D7ULL,
0x5858005858580058ULL, 0x6161006161610061ULL, 0x1B1B001B1B1B001BULL, 0x1C1C001C1C1C001CULL,
0x0F0F000F0F0F000FULL, 0x1616001616160016ULL, 0x1818001818180018ULL, 0x2222002222220022ULL,
0x4444004444440044ULL, 0xB2B200B2B2B200B2ULL, 0xB5B500B5B5B500B5ULL, 0x9191009191910091ULL,
0x0808000808080008ULL, 0xA8A800A8A8A800A8ULL, 0xFCFC00FCFCFC00FCULL, 0x5050005050500050ULL,
0xD0D000D0D0D000D0ULL, 0x7D7D007D7D7D007DULL, 0x8989008989890089ULL, 0x9797009797970097ULL,
0x5B5B005B5B5B005BULL, 0x9595009595950095ULL, 0xFFFF00FFFFFF00FFULL, 0xD2D200D2D2D200D2ULL,
0xC4C400C4C4C400C4ULL, 0x4848004848480048ULL, 0xF7F700F7F7F700F7ULL, 0xDBDB00DBDBDB00DBULL,
0x0303000303030003ULL, 0xDADA00DADADA00DAULL, 0x3F3F003F3F3F003FULL, 0x9494009494940094ULL,
0x5C5C005C5C5C005CULL, 0x0202000202020002ULL, 0x4A4A004A4A4A004AULL, 0x3333003333330033ULL,
0x6767006767670067ULL, 0xF3F300F3F3F300F3ULL, 0x7F7F007F7F7F007FULL, 0xE2E200E2E2E200E2ULL,
0x9B9B009B9B9B009BULL, 0x2626002626260026ULL, 0x3737003737370037ULL, 0x3B3B003B3B3B003BULL,
0x9696009696960096ULL, 0x4B4B004B4B4B004BULL, 0xBEBE00BEBEBE00BEULL, 0x2E2E002E2E2E002EULL,
0x7979007979790079ULL, 0x8C8C008C8C8C008CULL, 0x6E6E006E6E6E006EULL, 0x8E8E008E8E8E008EULL,
0xF5F500F5F5F500F5ULL, 0xB6B600B6B6B600B6ULL, 0xFDFD00FDFDFD00FDULL, 0x5959005959590059ULL,
0x9898009898980098ULL, 0x6A6A006A6A6A006AULL, 0x4646004646460046ULL, 0xBABA00BABABA00BAULL,
0x2525002525250025ULL, 0x4242004242420042ULL, 0xA2A200A2A2A200A2ULL, 0xFAFA00FAFAFA00FAULL,
0x0707000707070007ULL, 0x5555005555550055ULL, 0xEEEE00EEEEEE00EEULL, 0x0A0A000A0A0A000AULL,
0x4949004949490049ULL, 0x6868006868680068ULL, 0x3838003838380038ULL, 0xA4A400A4A4A400A4ULL,
0x2828002828280028ULL, 0x7B7B007B7B7B007BULL, 0xC9C900C9C9C900C9ULL, 0xC1C100C1C1C100C1ULL,
0xE3E300E3E3E300E3ULL, 0xF4F400F4F4F400F4ULL, 0xC7C700C7C7C700C7ULL, 0x9E9E009E9E9E009EULL };

const u64bit Camellia_SBOX8[256] = {
0x7070700070707000ULL, 0x8282820082828200ULL, 0x2C2C2C002C2C2C00ULL, 0xECECEC00ECECEC00ULL,
0xB3B3B300B3B3B300ULL, 0x2727270027272700ULL, 0xC0C0C000C0C0C000ULL, 0xE5E5E500E5E5E500ULL,
0xE4E4E400E4E4E400ULL, 0x8585850085858500ULL, 0x5757570057575700ULL, 0x3535350035353500ULL,
0xEAEAEA00EAEAEA00ULL, 0x0C0C0C000C0C0C00ULL, 0xAEAEAE00AEAEAE00ULL, 0x4141410041414100ULL,
0x2323230023232300ULL, 0xEFEFEF00EFEFEF00ULL, 0x6B6B6B006B6B6B00ULL, 0x9393930093939300ULL,
0x4545450045454500ULL, 0x1919190019191900ULL, 0xA5A5A500A5A5A500ULL, 0x2121210021212100ULL,
0xEDEDED00EDEDED00ULL, 0x0E0E0E000E0E0E00ULL, 0x4F4F4F004F4F4F00ULL, 0x4E4E4E004E4E4E00ULL,
0x1D1D1D001D1D1D00ULL, 0x6565650065656500ULL, 0x9292920092929200ULL, 0xBDBDBD00BDBDBD00ULL,
0x8686860086868600ULL, 0xB8B8B800B8B8B800ULL, 0xAFAFAF00AFAFAF00ULL, 0x8F8F8F008F8F8F00ULL,
0x7C7C7C007C7C7C00ULL, 0xEBEBEB00EBEBEB00ULL, 0x1F1F1F001F1F1F00ULL, 0xCECECE00CECECE00ULL,
0x3E3E3E003E3E3E00ULL, 0x3030300030303000ULL, 0xDCDCDC00DCDCDC00ULL, 0x5F5F5F005F5F5F00ULL,
0x5E5E5E005E5E5E00ULL, 0xC5C5C500C5C5C500ULL, 0x0B0B0B000B0B0B00ULL, 0x1A1A1A001A1A1A00ULL,
0xA6A6A600A6A6A600ULL, 0xE1E1E100E1E1E100ULL, 0x3939390039393900ULL, 0xCACACA00CACACA00ULL,
0xD5D5D500D5D5D500ULL, 0x4747470047474700ULL, 0x5D5D5D005D5D5D00ULL, 0x3D3D3D003D3D3D00ULL,
0xD9D9D900D9D9D900ULL, 0x0101010001010100ULL, 0x5A5A5A005A5A5A00ULL, 0xD6D6D600D6D6D600ULL,
0x5151510051515100ULL, 0x5656560056565600ULL, 0x6C6C6C006C6C6C00ULL, 0x4D4D4D004D4D4D00ULL,
0x8B8B8B008B8B8B00ULL, 0x0D0D0D000D0D0D00ULL, 0x9A9A9A009A9A9A00ULL, 0x6666660066666600ULL,
0xFBFBFB00FBFBFB00ULL, 0xCCCCCC00CCCCCC00ULL, 0xB0B0B000B0B0B000ULL, 0x2D2D2D002D2D2D00ULL,
0x7474740074747400ULL, 0x1212120012121200ULL, 0x2B2B2B002B2B2B00ULL, 0x2020200020202000ULL,
0xF0F0F000F0F0F000ULL, 0xB1B1B100B1B1B100ULL, 0x8484840084848400ULL, 0x9999990099999900ULL,
0xDFDFDF00DFDFDF00ULL, 0x4C4C4C004C4C4C00ULL, 0xCBCBCB00CBCBCB00ULL, 0xC2C2C200C2C2C200ULL,
0x3434340034343400ULL, 0x7E7E7E007E7E7E00ULL, 0x7676760076767600ULL, 0x0505050005050500ULL,
0x6D6D6D006D6D6D00ULL, 0xB7B7B700B7B7B700ULL, 0xA9A9A900A9A9A900ULL, 0x3131310031313100ULL,
0xD1D1D100D1D1D100ULL, 0x1717170017171700ULL, 0x0404040004040400ULL, 0xD7D7D700D7D7D700ULL,
0x1414140014141400ULL, 0x5858580058585800ULL, 0x3A3A3A003A3A3A00ULL, 0x6161610061616100ULL,
0xDEDEDE00DEDEDE00ULL, 0x1B1B1B001B1B1B00ULL, 0x1111110011111100ULL, 0x1C1C1C001C1C1C00ULL,
0x3232320032323200ULL, 0x0F0F0F000F0F0F00ULL, 0x9C9C9C009C9C9C00ULL, 0x1616160016161600ULL,
0x5353530053535300ULL, 0x1818180018181800ULL, 0xF2F2F200F2F2F200ULL, 0x2222220022222200ULL,
0xFEFEFE00FEFEFE00ULL, 0x4444440044444400ULL, 0xCFCFCF00CFCFCF00ULL, 0xB2B2B200B2B2B200ULL,
0xC3C3C300C3C3C300ULL, 0xB5B5B500B5B5B500ULL, 0x7A7A7A007A7A7A00ULL, 0x9191910091919100ULL,
0x2424240024242400ULL, 0x0808080008080800ULL, 0xE8E8E800E8E8E800ULL, 0xA8A8A800A8A8A800ULL,
0x6060600060606000ULL, 0xFCFCFC00FCFCFC00ULL, 0x6969690069696900ULL, 0x5050500050505000ULL,
0xAAAAAA00AAAAAA00ULL, 0xD0D0D000D0D0D000ULL, 0xA0A0A000A0A0A000ULL, 0x7D7D7D007D7D7D00ULL,
0xA1A1A100A1A1A100ULL, 0x8989890089898900ULL, 0x6262620062626200ULL, 0x9797970097979700ULL,
0x5454540054545400ULL, 0x5B5B5B005B5B5B00ULL, 0x1E1E1E001E1E1E00ULL, 0x9595950095959500ULL,
0xE0E0E000E0E0E000ULL, 0xFFFFFF00FFFFFF00ULL, 0x6464640064646400ULL, 0xD2D2D200D2D2D200ULL,
0x1010100010101000ULL, 0xC4C4C400C4C4C400ULL, 0x0000000000000000ULL, 0x4848480048484800ULL,
0xA3A3A300A3A3A300ULL, 0xF7F7F700F7F7F700ULL, 0x7575750075757500ULL, 0xDBDBDB00DBDBDB00ULL,
0x8A8A8A008A8A8A00ULL, 0x0303030003030300ULL, 0xE6E6E600E6E6E600ULL, 0xDADADA00DADADA00ULL,
0x0909090009090900ULL, 0x3F3F3F003F3F3F00ULL, 0xDDDDDD00DDDDDD00ULL, 0x9494940094949400ULL,
0x8787870087878700ULL, 0x5C5C5C005C5C5C00ULL, 0x8383830083838300ULL, 0x0202020002020200ULL,
0xCDCDCD00CDCDCD00ULL, 0x4A4A4A004A4A4A00ULL, 0x9090900090909000ULL, 0x3333330033333300ULL,
0x7373730073737300ULL, 0x6767670067676700ULL, 0xF6F6F600F6F6F600ULL, 0xF3F3F300F3F3F300ULL,
0x9D9D9D009D9D9D00ULL, 0x7F7F7F007F7F7F00ULL, 0xBFBFBF00BFBFBF00ULL, 0xE2E2E200E2E2E200ULL,
0x5252520052525200ULL, 0x9B9B9B009B9B9B00ULL, 0xD8D8D800D8D8D800ULL, 0x2626260026262600ULL,
0xC8C8C800C8C8C800ULL, 0x3737370037373700ULL, 0xC6C6C600C6C6C600ULL, 0x3B3B3B003B3B3B00ULL,
0x8181810081818100ULL, 0x9696960096969600ULL, 0x6F6F6F006F6F6F00ULL, 0x4B4B4B004B4B4B00ULL,
0x1313130013131300ULL, 0xBEBEBE00BEBEBE00ULL, 0x6363630063636300ULL, 0x2E2E2E002E2E2E00ULL,
0xE9E9E900E9E9E900ULL, 0x7979790079797900ULL, 0xA7A7A700A7A7A700ULL, 0x8C8C8C008C8C8C00ULL,
0x9F9F9F009F9F9F00ULL, 0x6E6E6E006E6E6E00ULL, 0xBCBCBC00BCBCBC00ULL, 0x8E8E8E008E8E8E00ULL,
0x2929290029292900ULL, 0xF5F5F500F5F5F500ULL, 0xF9F9F900F9F9F900ULL, 0xB6B6B600B6B6B600ULL,
0x2F2F2F002F2F2F00ULL, 0xFDFDFD00FDFDFD00ULL, 0xB4B4B400B4B4B400ULL, 0x5959590059595900ULL,
0x7878780078787800ULL, 0x9898980098989800ULL, 0x0606060006060600ULL, 0x6A6A6A006A6A6A00ULL,
0xE7E7E700E7E7E700ULL, 0x4646460046464600ULL, 0x7171710071717100ULL, 0xBABABA00BABABA00ULL,
0xD4D4D400D4D4D400ULL, 0x2525250025252500ULL, 0xABABAB00ABABAB00ULL, 0x4242420042424200ULL,
0x8888880088888800ULL, 0xA2A2A200A2A2A200ULL, 0x8D8D8D008D8D8D00ULL, 0xFAFAFA00FAFAFA00ULL,
0x7272720072727200ULL, 0x0707070007070700ULL, 0xB9B9B900B9B9B900ULL, 0x5555550055555500ULL,
0xF8F8F800F8F8F800ULL, 0xEEEEEE00EEEEEE00ULL, 0xACACAC00ACACAC00ULL, 0x0A0A0A000A0A0A00ULL,
0x3636360036363600ULL, 0x4949490049494900ULL, 0x2A2A2A002A2A2A00ULL, 0x6868680068686800ULL,
0x3C3C3C003C3C3C00ULL, 0x3838380038383800ULL, 0xF1F1F100F1F1F100ULL, 0xA4A4A400A4A4A400ULL,
0x4040400040404000ULL, 0x2828280028282800ULL, 0xD3D3D300D3D3D300ULL, 0x7B7B7B007B7B7B00ULL,
0xBBBBBB00BBBBBB00ULL, 0xC9C9C900C9C9C900ULL, 0x4343430043434300ULL, 0xC1C1C100C1C1C100ULL,
0x1515150015151500ULL, 0xE3E3E300E3E3E300ULL, 0xADADAD00ADADAD00ULL, 0xF4F4F400F4F4F400ULL,
0x7777770077777700ULL, 0xC7C7C700C7C7C700ULL, 0x8080800080808000ULL, 0x9E9E9E009E9E9E00ULL };

}


namespace Botan {

extern "C" {

#ifdef Q_OS_UNIX
/*
* Helper Macros for x86 Assembly
*/
#ifndef ASM
  #define ASM(x) x "\n\t"
#endif

#define ADDSUB2_OP(OPERATION, INDEX)                     \
        ASM("movl 4*" #INDEX "(%[y]), %[carry]")         \
        ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])")   \

#define ADDSUB3_OP(OPERATION, INDEX)                     \
        ASM("movl 4*" #INDEX "(%[x]), %[carry]")         \
        ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]")   \
        ASM("movl %[carry], 4*" #INDEX "(%[z])")         \

#define LINMUL_OP(WRITE_TO, INDEX)                       \
        ASM("movl 4*" #INDEX "(%[x]),%%eax")             \
        ASM("mull %[y]")                                 \
        ASM("addl %[carry],%%eax")                       \
        ASM("adcl $0,%%edx")                             \
        ASM("movl %%edx,%[carry]")                       \
        ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])")

#define MULADD_OP(IGNORED, INDEX)                        \
        ASM("movl 4*" #INDEX "(%[x]),%%eax")             \
        ASM("mull %[y]")                                 \
        ASM("addl %[carry],%%eax")                       \
        ASM("adcl $0,%%edx")                             \
        ASM("addl 4*" #INDEX "(%[z]),%%eax")             \
        ASM("adcl $0,%%edx")                             \
        ASM("movl %%edx,%[carry]")                       \
        ASM("movl %%eax, 4*" #INDEX " (%[z])")

#define DO_8_TIMES(MACRO, ARG) \
        MACRO(ARG, 0) \
        MACRO(ARG, 1) \
        MACRO(ARG, 2) \
        MACRO(ARG, 3) \
        MACRO(ARG, 4) \
        MACRO(ARG, 5) \
        MACRO(ARG, 6) \
        MACRO(ARG, 7)

#define ADD_OR_SUBTRACT(CORE_CODE)     \
        ASM("rorl %[carry]")           \
        CORE_CODE                      \
        ASM("sbbl %[carry],%[carry]")  \
        ASM("negl %[carry]")

/*
* Word Addition
*/
inline word word_add(word x, word y, word* carry)
   {
   asm(
      ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]"))
      : [x]"=r"(x), [carry]"=r"(*carry)
      : "0"(x), [y]"rm"(y), "1"(*carry)
      : "cc");
   return x;
   }

/*
* Eight Word Block Addition, Two Argument
*/
inline word word8_add2(word x[8], const word y[8], word carry)
   {
   asm(
      ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl"))
      : [carry]"=r"(carry)
      : [x]"r"(x), [y]"r"(y), "0"(carry)
      : "cc", "memory");
   return carry;
   }

/*
* Eight Word Block Addition, Three Argument
*/
inline word word8_add3(word z[8], const word x[8], const word y[8], word carry)
   {
   asm(
      ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl"))
      : [carry]"=r"(carry)
      : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
      : "cc", "memory");
   return carry;
   }

/*
* Word Subtraction
*/
inline word word_sub(word x, word y, word* carry)
   {
   asm(
      ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]"))
      : [x]"=r"(x), [carry]"=r"(*carry)
      : "0"(x), [y]"rm"(y), "1"(*carry)
      : "cc");
   return x;
   }

/*
* Eight Word Block Subtraction, Two Argument
*/
inline word word8_sub2(word x[8], const word y[8], word carry)
   {
   asm(
      ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl"))
      : [carry]"=r"(carry)
      : [x]"r"(x), [y]"r"(y), "0"(carry)
      : "cc", "memory");
   return carry;
   }

/*
* Eight Word Block Subtraction, Two Argument
*/
inline word word8_sub2_rev(word x[8], const word y[8], word carry)
   {
   asm(
      ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
      : [carry]"=r"(carry)
      : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry)
      : "cc", "memory");
   return carry;
   }

/*
* Eight Word Block Subtraction, Three Argument
*/
inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry)
   {
   asm(
      ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
      : [carry]"=r"(carry)
      : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
      : "cc", "memory");
   return carry;
   }

/*
* Eight Word Block Linear Multiplication
*/
inline word word8_linmul2(word x[8], word y, word carry)
   {
   asm(
      DO_8_TIMES(LINMUL_OP, "x")
      : [carry]"=r"(carry)
      : [x]"r"(x), [y]"rm"(y), "0"(carry)
      : "cc", "%eax", "%edx");
   return carry;
   }

/*
* Eight Word Block Linear Multiplication
*/
inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
   {
   asm(
      DO_8_TIMES(LINMUL_OP, "z")
      : [carry]"=r"(carry)
      : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
      : "cc", "%eax", "%edx");
   return carry;
   }

/*
* Eight Word Block Multiply/Add
*/
inline word word8_madd3(word z[8], const word x[8], word y, word carry)
   {
   asm(
      DO_8_TIMES(MULADD_OP, "")
      : [carry]"=r"(carry)
      : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
      : "cc", "%eax", "%edx");
   return carry;
   }

/*
* Multiply-Add Accumulator
*/
inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y)
   {
   asm(
      ASM("mull %[y]")

      ASM("addl %[x],%[w0]")
      ASM("adcl %[y],%[w1]")
      ASM("adcl $0,%[w2]")

      : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
      : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
      : "cc");
   }

/*
* Multiply-Add Accumulator
*/
inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
   {
   asm(
      ASM("mull %[y]")

      ASM("addl %[x],%[w0]")
      ASM("adcl %[y],%[w1]")
      ASM("adcl $0,%[w2]")

      ASM("addl %[x],%[w0]")
      ASM("adcl %[y],%[w1]")
      ASM("adcl $0,%[w2]")

      : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
      : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
      : "cc");
   }
#else
/*
* Word Addition
*/
inline word word_add(word x, word y, word* carry)
   {
   word z = x + y;
   word c1 = (z < x);
   z += *carry;
   *carry = c1 | (z < *carry);
   return z;
   }

/*
* Eight Word Block Addition, Two Argument
*/
inline word word8_add2(word x[8], const word y[8], word carry)
   {
   x[0] = word_add(x[0], y[0], &carry);
   x[1] = word_add(x[1], y[1], &carry);
   x[2] = word_add(x[2], y[2], &carry);
   x[3] = word_add(x[3], y[3], &carry);
   x[4] = word_add(x[4], y[4], &carry);
   x[5] = word_add(x[5], y[5], &carry);
   x[6] = word_add(x[6], y[6], &carry);
   x[7] = word_add(x[7], y[7], &carry);
   return carry;
   }

/*
* Eight Word Block Addition, Three Argument
*/
inline word word8_add3(word z[8], const word x[8],
                       const word y[8], word carry)
   {
   z[0] = word_add(x[0], y[0], &carry);
   z[1] = word_add(x[1], y[1], &carry);
   z[2] = word_add(x[2], y[2], &carry);
   z[3] = word_add(x[3], y[3], &carry);
   z[4] = word_add(x[4], y[4], &carry);
   z[5] = word_add(x[5], y[5], &carry);
   z[6] = word_add(x[6], y[6], &carry);
   z[7] = word_add(x[7], y[7], &carry);
   return carry;
   }

/*
* Word Subtraction
*/
inline word word_sub(word x, word y, word* carry)
   {
   word t0 = x - y;
   word c1 = (t0 > x);
   word z = t0 - *carry;
   *carry = c1 | (z > t0);
   return z;
   }

/*
* Eight Word Block Subtraction, Two Argument
*/
inline word word8_sub2(word x[8], const word y[8], word carry)
   {
   x[0] = word_sub(x[0], y[0], &carry);
   x[1] = word_sub(x[1], y[1], &carry);
   x[2] = word_sub(x[2], y[2], &carry);
   x[3] = word_sub(x[3], y[3], &carry);
   x[4] = word_sub(x[4], y[4], &carry);
   x[5] = word_sub(x[5], y[5], &carry);
   x[6] = word_sub(x[6], y[6], &carry);
   x[7] = word_sub(x[7], y[7], &carry);
   return carry;
   }

/*
* Eight Word Block Subtraction, Two Argument
*/
inline word word8_sub2_rev(word x[8], const word y[8], word carry)
   {
   x[0] = word_sub(y[0], x[0], &carry);
   x[1] = word_sub(y[1], x[1], &carry);
   x[2] = word_sub(y[2], x[2], &carry);
   x[3] = word_sub(y[3], x[3], &carry);
   x[4] = word_sub(y[4], x[4], &carry);
   x[5] = word_sub(y[5], x[5], &carry);
   x[6] = word_sub(y[6], x[6], &carry);
   x[7] = word_sub(y[7], x[7], &carry);
   return carry;
   }

/*
* Eight Word Block Subtraction, Three Argument
*/
inline word word8_sub3(word z[8], const word x[8],
                       const word y[8], word carry)
   {
   z[0] = word_sub(x[0], y[0], &carry);
   z[1] = word_sub(x[1], y[1], &carry);
   z[2] = word_sub(x[2], y[2], &carry);
   z[3] = word_sub(x[3], y[3], &carry);
   z[4] = word_sub(x[4], y[4], &carry);
   z[5] = word_sub(x[5], y[5], &carry);
   z[6] = word_sub(x[6], y[6], &carry);
   z[7] = word_sub(x[7], y[7], &carry);
   return carry;
   }

/*
* Eight Word Block Linear Multiplication
*/
inline word word8_linmul2(word x[8], word y, word carry)
   {
   x[0] = word_madd2(x[0], y, &carry);
   x[1] = word_madd2(x[1], y, &carry);
   x[2] = word_madd2(x[2], y, &carry);
   x[3] = word_madd2(x[3], y, &carry);
   x[4] = word_madd2(x[4], y, &carry);
   x[5] = word_madd2(x[5], y, &carry);
   x[6] = word_madd2(x[6], y, &carry);
   x[7] = word_madd2(x[7], y, &carry);
   return carry;
   }

/*
* Eight Word Block Linear Multiplication
*/
inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
   {
   z[0] = word_madd2(x[0], y, &carry);
   z[1] = word_madd2(x[1], y, &carry);
   z[2] = word_madd2(x[2], y, &carry);
   z[3] = word_madd2(x[3], y, &carry);
   z[4] = word_madd2(x[4], y, &carry);
   z[5] = word_madd2(x[5], y, &carry);
   z[6] = word_madd2(x[6], y, &carry);
   z[7] = word_madd2(x[7], y, &carry);
   return carry;
   }

/*
* Eight Word Block Multiply/Add
*/
inline word word8_madd3(word z[8], const word x[8], word y, word carry)
   {
   z[0] = word_madd3(x[0], y, z[0], &carry);
   z[1] = word_madd3(x[1], y, z[1], &carry);
   z[2] = word_madd3(x[2], y, z[2], &carry);
   z[3] = word_madd3(x[3], y, z[3], &carry);
   z[4] = word_madd3(x[4], y, z[4], &carry);
   z[5] = word_madd3(x[5], y, z[5], &carry);
   z[6] = word_madd3(x[6], y, z[6], &carry);
   z[7] = word_madd3(x[7], y, z[7], &carry);
   return carry;
   }

/*
* Multiply-Add Accumulator
*/
inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b)
   {
   word carry = *w0;
   *w0 = word_madd2(a, b, &carry);
   *w1 += carry;
   *w2 += (*w1 < carry) ? 1 : 0;
   }

/*
* Multiply-Add Accumulator
*/
inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b)
   {
   word carry = 0;
   a = word_madd2(a, b, &carry);
   b = carry;

   word top = (b >> (BOTAN_MP_WORD_BITS-1));
   b <<= 1;
   b |= (a >> (BOTAN_MP_WORD_BITS-1));
   a <<= 1;

   carry = 0;
   *w0 = word_add(*w0, a, &carry);
   *w1 = word_add(*w1, b, &carry);
   *w2 = word_add(*w2, top, &carry);
   }

#endif

}

}

/*
* OctetString
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Create an OctetString from RNG output
*/
OctetString::OctetString(RandomNumberGenerator& rng,
                         size_t length)
   {
   bits = rng.random_vec(length);
   }

/*
* Create an OctetString from a hex string
*/
void OctetString::change(const std::string& hex_string)
   {
   bits.resize(1 + hex_string.length() / 2);
   bits.resize(hex_decode(&bits[0], hex_string));
   }

/*
* Create an OctetString from a byte string
*/
void OctetString::change(const byte in[], size_t n)
   {
   bits.resize(n);
   bits.copy(in, n);
   }

/*
* Set the parity of each key byte to odd
*/
void OctetString::set_odd_parity()
   {
   const byte ODD_PARITY[256] = {
      0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B,
      0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16,
      0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23,
      0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F,
      0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B,
      0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46,
      0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52,
      0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E,
      0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B,
      0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76,
      0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83,
      0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F,
      0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B,
      0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7,
      0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3,
      0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF,
      0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB,
      0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6,
      0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3,
      0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF,
      0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB,
      0xFD, 0xFD, 0xFE, 0xFE };

   for(size_t j = 0; j != bits.size(); ++j)
      bits[j] = ODD_PARITY[bits[j]];
   }

/*
* Hex encode an OctetString
*/
std::string OctetString::as_string() const
   {
   return hex_encode(&bits[0], bits.size());
   }

/*
* XOR Operation for OctetStrings
*/
OctetString& OctetString::operator^=(const OctetString& k)
   {
   if(&k == this) { zeroise(bits); return (*this); }
   xor_buf(&bits[0], k.begin(), std::min(length(), k.length()));
   return (*this);
   }

/*
* Equality Operation for OctetStrings
*/
bool operator==(const OctetString& s1, const OctetString& s2)
   {
   return (s1.bits_of() == s2.bits_of());
   }

/*
* Unequality Operation for OctetStrings
*/
bool operator!=(const OctetString& s1, const OctetString& s2)
   {
   return !(s1 == s2);
   }

/*
* Append Operation for OctetStrings
*/
OctetString operator+(const OctetString& k1, const OctetString& k2)
   {
   SecureVector<byte> out;
   out += k1.bits_of();
   out += k2.bits_of();
   return OctetString(out);
   }

/*
* XOR Operation for OctetStrings
*/
OctetString operator^(const OctetString& k1, const OctetString& k2)
   {
   SecureVector<byte> ret(std::max(k1.length(), k2.length()));
   ret.copy(k1.begin(), k1.length());
   xor_buf(ret, k2.begin(), k2.length());
   return OctetString(ret);
   }

}
/*
* Algorithm Factory
* (C) 2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/



#include <algorithm>

namespace Botan {

namespace {

/*
* Template functions for the factory prototype/search algorithm
*/
template<typename T>
T* engine_get_algo(Engine*,
                   const SCAN_Name&,
                   Algorithm_Factory&)
   { return 0; }

template<>
BlockCipher* engine_get_algo(Engine* engine,
                             const SCAN_Name& request,
                             Algorithm_Factory& af)
   { return engine->find_block_cipher(request, af); }

template<>
StreamCipher* engine_get_algo(Engine* engine,
                              const SCAN_Name& request,
                              Algorithm_Factory& af)
   { return engine->find_stream_cipher(request, af); }

template<>
HashFunction* engine_get_algo(Engine* engine,
                              const SCAN_Name& request,
                              Algorithm_Factory& af)
   { return engine->find_hash(request, af); }

template<>
MessageAuthenticationCode* engine_get_algo(Engine* engine,
                                           const SCAN_Name& request,
                                           Algorithm_Factory& af)
   { return engine->find_mac(request, af); }

template<>
PBKDF* engine_get_algo(Engine* engine,
                       const SCAN_Name& request,
                       Algorithm_Factory& af)
   { return engine->find_pbkdf(request, af); }

template<typename T>
const T* factory_prototype(const std::string& algo_spec,
                           const std::string& provider,
                           const std::vector<Engine*>& engines,
                           Algorithm_Factory& af,
                           Algorithm_Cache<T>* cache)
   {
   if(const T* cache_hit = cache->get(algo_spec, provider))
      return cache_hit;

   SCAN_Name scan_name(algo_spec);

   if(scan_name.cipher_mode() != "")
      return 0;

   for(size_t i = 0; i != engines.size(); ++i)
      {
      if(provider == "" || engines[i]->provider_name() == provider)
         {
         if(T* impl = engine_get_algo<T>(engines[i], scan_name, af))
            cache->add(impl, algo_spec, engines[i]->provider_name());
         }
      }

   return cache->get(algo_spec, provider);
   }

}

/*
* Setup caches
*/
Algorithm_Factory::Algorithm_Factory(Mutex_Factory& mf)
   {
   block_cipher_cache = new Algorithm_Cache<BlockCipher>(mf.make());
   stream_cipher_cache = new Algorithm_Cache<StreamCipher>(mf.make());
   hash_cache = new Algorithm_Cache<HashFunction>(mf.make());
   mac_cache = new Algorithm_Cache<MessageAuthenticationCode>(mf.make());
   pbkdf_cache = new Algorithm_Cache<PBKDF>(mf.make());
   }

/*
* Delete all engines
*/
Algorithm_Factory::~Algorithm_Factory()
   {
   delete block_cipher_cache;
   delete stream_cipher_cache;
   delete hash_cache;
   delete mac_cache;
   delete pbkdf_cache;

   std::for_each(engines.begin(), engines.end(), del_fun<Engine>());
   }

void Algorithm_Factory::clear_caches()
   {
   block_cipher_cache->clear_cache();
   stream_cipher_cache->clear_cache();
   hash_cache->clear_cache();
   mac_cache->clear_cache();
   pbkdf_cache->clear_cache();
   }

void Algorithm_Factory::add_engine(Engine* engine)
   {
   clear_caches();
   engines.push_back(engine);
   }

/*
* Set the preferred provider for an algorithm
*/
void Algorithm_Factory::set_preferred_provider(const std::string& algo_spec,
                                               const std::string& provider)
   {
   if(prototype_block_cipher(algo_spec))
      block_cipher_cache->set_preferred_provider(algo_spec, provider);
   else if(prototype_stream_cipher(algo_spec))
      stream_cipher_cache->set_preferred_provider(algo_spec, provider);
   else if(prototype_hash_function(algo_spec))
      hash_cache->set_preferred_provider(algo_spec, provider);
   else if(prototype_mac(algo_spec))
      mac_cache->set_preferred_provider(algo_spec, provider);
   else if(prototype_pbkdf(algo_spec))
      pbkdf_cache->set_preferred_provider(algo_spec, provider);
   }

/*
* Get an engine out of the list
*/
Engine* Algorithm_Factory::get_engine_n(size_t n) const
   {
   if(n >= engines.size())
      return 0;
   return engines[n];
   }

/*
* Return the possible providers of a request
* Note: assumes you don't have different types by the same name
*/
std::vector<std::string>
Algorithm_Factory::providers_of(const std::string& algo_spec)
   {
   /* The checks with if(prototype_X(algo_spec)) have the effect of
      forcing a full search, since otherwise there might not be any
      providers at all in the cache.
   */

   if(prototype_block_cipher(algo_spec))
      return block_cipher_cache->providers_of(algo_spec);
   else if(prototype_stream_cipher(algo_spec))
      return stream_cipher_cache->providers_of(algo_spec);
   else if(prototype_hash_function(algo_spec))
      return hash_cache->providers_of(algo_spec);
   else if(prototype_mac(algo_spec))
      return mac_cache->providers_of(algo_spec);
   else if(prototype_pbkdf(algo_spec))
      return pbkdf_cache->providers_of(algo_spec);
   else
      return std::vector<std::string>();
   }

/*
* Return the prototypical block cipher corresponding to this request
*/
const BlockCipher*
Algorithm_Factory::prototype_block_cipher(const std::string& algo_spec,
                                          const std::string& provider)
   {
   return factory_prototype<BlockCipher>(algo_spec, provider, engines,
                                          *this, block_cipher_cache);
   }

/*
* Return the prototypical stream cipher corresponding to this request
*/
const StreamCipher*
Algorithm_Factory::prototype_stream_cipher(const std::string& algo_spec,
                                           const std::string& provider)
   {
   return factory_prototype<StreamCipher>(algo_spec, provider, engines,
                                          *this, stream_cipher_cache);
   }

/*
* Return the prototypical object corresponding to this request (if found)
*/
const HashFunction*
Algorithm_Factory::prototype_hash_function(const std::string& algo_spec,
                                           const std::string& provider)
   {
   return factory_prototype<HashFunction>(algo_spec, provider, engines,
                                          *this, hash_cache);
   }

/*
* Return the prototypical object corresponding to this request
*/
const MessageAuthenticationCode*
Algorithm_Factory::prototype_mac(const std::string& algo_spec,
                                 const std::string& provider)
   {
   return factory_prototype<MessageAuthenticationCode>(algo_spec, provider,
                                                       engines,
                                                       *this, mac_cache);
   }

/*
* Return the prototypical object corresponding to this request
*/
const PBKDF*
Algorithm_Factory::prototype_pbkdf(const std::string& algo_spec,
                                   const std::string& provider)
   {
   return factory_prototype<PBKDF>(algo_spec, provider,
                                   engines,
                                   *this, pbkdf_cache);
   }

/*
* Return a new block cipher corresponding to this request
*/
BlockCipher*
Algorithm_Factory::make_block_cipher(const std::string& algo_spec,
                                     const std::string& provider)
   {
   if(const BlockCipher* proto = prototype_block_cipher(algo_spec, provider))
      return proto->clone();
   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Return a new stream cipher corresponding to this request
*/
StreamCipher*
Algorithm_Factory::make_stream_cipher(const std::string& algo_spec,
                                      const std::string& provider)
   {
   if(const StreamCipher* proto = prototype_stream_cipher(algo_spec, provider))
      return proto->clone();
   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Return a new object corresponding to this request
*/
HashFunction*
Algorithm_Factory::make_hash_function(const std::string& algo_spec,
                                      const std::string& provider)
   {
   if(const HashFunction* proto = prototype_hash_function(algo_spec, provider))
      return proto->clone();
   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Return a new object corresponding to this request
*/
MessageAuthenticationCode*
Algorithm_Factory::make_mac(const std::string& algo_spec,
                            const std::string& provider)
   {
   if(const MessageAuthenticationCode* proto = prototype_mac(algo_spec, provider))
      return proto->clone();
   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Return a new object corresponding to this request
*/
PBKDF*
Algorithm_Factory::make_pbkdf(const std::string& algo_spec,
                              const std::string& provider)
   {
   if(const PBKDF* proto = prototype_pbkdf(algo_spec, provider))
      return proto->clone();
   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Add a new block cipher
*/
void Algorithm_Factory::add_block_cipher(BlockCipher* block_cipher,
                                         const std::string& provider)
   {
   block_cipher_cache->add(block_cipher, block_cipher->name(), provider);
   }

/*
* Add a new stream cipher
*/
void Algorithm_Factory::add_stream_cipher(StreamCipher* stream_cipher,
                                         const std::string& provider)
   {
   stream_cipher_cache->add(stream_cipher, stream_cipher->name(), provider);
   }

/*
* Add a new hash
*/
void Algorithm_Factory::add_hash_function(HashFunction* hash,
                                          const std::string& provider)
   {
   hash_cache->add(hash, hash->name(), provider);
   }

/*
* Add a new mac
*/
void Algorithm_Factory::add_mac(MessageAuthenticationCode* mac,
                                const std::string& provider)
   {
   mac_cache->add(mac, mac->name(), provider);
   }

/*
* Add a new PBKDF
*/
void Algorithm_Factory::add_pbkdf(PBKDF* pbkdf,
                                  const std::string& provider)
   {
   pbkdf_cache->add(pbkdf, pbkdf->name(), provider);
   }

}
/*
* Default provider weights for Algorithm_Cache
* (C) 2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/**
* Return a static provider weighing
*/
size_t static_provider_weight(const std::string& prov_name)
   {
   /*
   * Prefer asm over C++, but prefer anything over OpenSSL or GNU MP; to use
   * them, set the provider explicitly for the algorithms you want
   */

   if(prov_name == "aes_isa") return 9;
   if(prov_name == "simd") return 8;
   if(prov_name == "asm") return 7;

   if(prov_name == "core") return 5;

   if(prov_name == "openssl") return 2;
   if(prov_name == "gmp") return 1;

   return 0; // other/unknown
   }

}

#ifdef Q_OS_UNIX
/*
* Memory Mapping Allocator
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <vector>
#include <cstring>

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

#ifndef MAP_FAILED
   #define MAP_FAILED -1
#endif

namespace Botan {

namespace {

/*
* MemoryMapping_Allocator Exception
*/
class BOTAN_DLL MemoryMapping_Failed : public Exception
   {
   public:
      MemoryMapping_Failed(const std::string& msg) :
         Exception("MemoryMapping_Allocator: " + msg) {}
   };

}

/*
* Memory Map a File into Memory
*/
void* MemoryMapping_Allocator::alloc_block(size_t n)
   {
   class TemporaryFile
      {
      public:
         int get_fd() const { return fd; }

         TemporaryFile(const std::string& base)
            {
            const std::string mkstemp_template = base + "XXXXXX";

            std::vector<char> filepath(mkstemp_template.begin(),
                                       mkstemp_template.end());
            filepath.push_back(0); // add terminating NULL

            mode_t old_umask = ::umask(077);
            fd = ::mkstemp(&filepath[0]);
            ::umask(old_umask);

            if(fd == -1)
               throw MemoryMapping_Failed("Temporary file allocation failed");

            if(::unlink(&filepath[0]) != 0)
               throw MemoryMapping_Failed("Could not unlink temporary file");
            }

         ~TemporaryFile()
            {
            /*
            * We can safely close here, because post-mmap the file
            * will continue to exist until the mmap is unmapped from
            * our address space upon deallocation (or process exit).
            */
            if(fd != -1 && ::close(fd) == -1)
               throw MemoryMapping_Failed("Could not close file");
            }
      private:
         int fd;
      };

   TemporaryFile file("/tmp/botan_");

   if(file.get_fd() == -1)
      throw MemoryMapping_Failed("Could not create file");

   std::vector<byte> zeros(4096);

   size_t remaining = n;

   while(remaining)
      {
      const size_t write_try = std::min(zeros.size(), remaining);

      ssize_t wrote_got = ::write(file.get_fd(),
                                  &zeros[0],
                                  write_try);

      if(wrote_got == -1 && errno != EINTR)
         throw MemoryMapping_Failed("Could not write to file");

      remaining -= wrote_got;
      }

#ifndef MAP_NOSYNC
   #define MAP_NOSYNC 0
#endif

   void* ptr = ::mmap(0, n,
                      PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_NOSYNC,
                      file.get_fd(), 0);

   if(ptr == static_cast<void*>(MAP_FAILED))
      throw MemoryMapping_Failed("Could not map file");

   return ptr;
   }

/*
* Remove a Memory Mapping
*/
void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n)
   {
   if(ptr == 0)
      return;

   const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 };

   // The char* casts are for Solaris, args are void* on most other systems

   for(size_t i = 0; i != sizeof(PATTERNS); ++i)
      {
      std::memset(ptr, PATTERNS[i], n);

      if(::msync(static_cast<char*>(ptr), n, MS_SYNC))
         throw MemoryMapping_Failed("Sync operation failed");
      }

   if(::munmap(static_cast<char*>(ptr), n))
      throw MemoryMapping_Failed("Could not unmap file");
   }

}
#endif

/*
* Pooling Allocator
* (C) 1999-2008 Jack Lloyd
*     2005 Matthew Gregan
*     2005-2006 Matt Johnston
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <exception>

namespace Botan {

/*
* Memory_Block Constructor
*/
Pooling_Allocator::Memory_Block::Memory_Block(void* buf)
   {
   buffer = static_cast<byte*>(buf);
   bitmap = 0;
   buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE);
   }

/*
* See if ptr is contained by this block
*/
bool Pooling_Allocator::Memory_Block::contains(void* ptr,
                                               size_t length) const
   {
   return ((buffer <= ptr) &&
           (buffer_end >= static_cast<byte*>(ptr) + length * BLOCK_SIZE));
   }

/*
* Allocate some memory, if possible
*/
byte* Pooling_Allocator::Memory_Block::alloc(size_t n)
   {
   if(n == 0 || n > BITMAP_SIZE)
      return 0;

   if(n == BITMAP_SIZE)
      {
      if(bitmap)
         return 0;
      else
         {
         bitmap = ~bitmap;
         return buffer;
         }
      }

   bitmap_type mask = (static_cast<bitmap_type>(1) << n) - 1;
   size_t offset = 0;

   while(bitmap & mask)
      {
      mask <<= 1;
      ++offset;

      if((bitmap & mask) == 0)
         break;
      if(mask >> 63)
         break;
      }

   if(bitmap & mask)
      return 0;

   bitmap |= mask;
   return buffer + offset * BLOCK_SIZE;
   }

/*
* Mark this memory as free, if we own it
*/
void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks)
   {
   clear_mem(static_cast<byte*>(ptr), blocks * BLOCK_SIZE);

   const size_t offset = (static_cast<byte*>(ptr) - buffer) / BLOCK_SIZE;

   if(offset == 0 && blocks == BITMAP_SIZE)
      bitmap = ~bitmap;
   else
      {
      for(size_t j = 0; j != blocks; ++j)
         bitmap &= ~(static_cast<bitmap_type>(1) << (j+offset));
      }
   }

/*
* Pooling_Allocator Constructor
*/
Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m)
   {
   last_used = blocks.begin();
   }

/*
* Pooling_Allocator Destructor
*/
Pooling_Allocator::~Pooling_Allocator()
   {
   delete mutex;
   if(blocks.size())
      throw Invalid_State("Pooling_Allocator: Never released memory");
   }

/*
* Free all remaining memory
*/
void Pooling_Allocator::destroy()
   {
   Mutex_Holder lock(mutex);

   blocks.clear();

   for(size_t j = 0; j != allocated.size(); ++j)
      dealloc_block(allocated[j].first, allocated[j].second);
   allocated.clear();
   }

/*
* Allocation
*/
void* Pooling_Allocator::allocate(size_t n)
   {
   const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
   const size_t BLOCK_SIZE = Memory_Block::block_size();

   Mutex_Holder lock(mutex);

   if(n <= BITMAP_SIZE * BLOCK_SIZE)
      {
      const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;

      byte* mem = allocate_blocks(block_no);
      if(mem)
         return mem;

      get_more_core(BOTAN_MEM_POOL_CHUNK_SIZE);

      mem = allocate_blocks(block_no);
      if(mem)
         return mem;

      throw Memory_Exhaustion();
      }

   void* new_buf = alloc_block(n);
   if(new_buf)
      return new_buf;

   throw Memory_Exhaustion();
   }

/*
* Deallocation
*/
void Pooling_Allocator::deallocate(void* ptr, size_t n)
   {
   const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
   const size_t BLOCK_SIZE = Memory_Block::block_size();

   if(ptr == 0 && n == 0)
      return;

   Mutex_Holder lock(mutex);

   if(n > BITMAP_SIZE * BLOCK_SIZE)
      dealloc_block(ptr, n);
   else
      {
      const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;

      std::vector<Memory_Block>::iterator i =
         std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr));

      if(i == blocks.end() || !i->contains(ptr, block_no))
         throw Invalid_State("Pointer released to the wrong allocator");

      i->free(ptr, block_no);
      }
   }

/*
* Try to get some memory from an existing block
*/
byte* Pooling_Allocator::allocate_blocks(size_t n)
   {
   if(blocks.empty())
      return 0;

   std::vector<Memory_Block>::iterator i = last_used;

   do
      {
      byte* mem = i->alloc(n);
      if(mem)
         {
         last_used = i;
         return mem;
         }

      ++i;
      if(i == blocks.end())
         i = blocks.begin();
      }
   while(i != last_used);

   return 0;
   }

/*
* Allocate more memory for the pool
*/
void Pooling_Allocator::get_more_core(size_t in_bytes)
   {
   const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
   const size_t BLOCK_SIZE = Memory_Block::block_size();

   const size_t TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE;

   // upper bound on allocation is 1 MiB
   in_bytes = std::min<size_t>(in_bytes, 1024 * 1024);

   const size_t in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE;
   const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE;

   void* ptr = alloc_block(to_allocate);
   if(ptr == 0)
      throw Memory_Exhaustion();

   allocated.push_back(std::make_pair(ptr, to_allocate));

   for(size_t j = 0; j != in_blocks; ++j)
      {
      byte* byte_ptr = static_cast<byte*>(ptr);
      blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE));
      }

   std::sort(blocks.begin(), blocks.end());
   last_used = std::lower_bound(blocks.begin(), blocks.end(),
                                Memory_Block(ptr));
   }

}
/*
* Basic Allocators
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <cstdlib>
#include <cstring>

namespace Botan {

namespace {

/*
* Perform Memory Allocation
*/
void* do_malloc(size_t n, bool do_lock)
   {
   void* ptr = std::malloc(n);

   if(!ptr)
      return 0;

   if(do_lock)
      lock_mem(ptr, n);

   std::memset(ptr, 0, n);
   return ptr;
   }

/*
* Perform Memory Deallocation
*/
void do_free(void* ptr, size_t n, bool do_lock)
   {
   if(!ptr)
      return;

   std::memset(ptr, 0, n);
   if(do_lock)
      unlock_mem(ptr, n);

   std::free(ptr);
   }

}

/*
* Malloc_Allocator's Allocation
*/
void* Malloc_Allocator::allocate(size_t n)
   {
   void* ptr = do_malloc(n, false);
   if(!ptr)
      throw Memory_Exhaustion();
   return ptr;
   }

/*
* Malloc_Allocator's Deallocation
*/
void Malloc_Allocator::deallocate(void* ptr, size_t n)
   {
   do_free(ptr, n, false);
   }

/*
* Locking_Allocator's Allocation
*/
void* Locking_Allocator::alloc_block(size_t n)
   {
   return do_malloc(n, true);
   }

/*
* Locking_Allocator's Deallocation
*/
void Locking_Allocator::dealloc_block(void* ptr, size_t n)
   {
   do_free(ptr, n, true);
   }

/*
* Get an allocator
*/
Allocator* Allocator::get(bool locking)
   {
   std::string type = "";
   if(!locking)
      type = "malloc";

   Allocator* alloc = global_state().get_allocator(type);
   if(alloc)
      return alloc;

   throw Internal_Error("Couldn't find an allocator to use in get_allocator");
   }

}
/*
* Algorithm Identifier
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create an AlgorithmIdentifier
*/
AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id,
                                         const MemoryRegion<byte>& param)
   {
   oid = alg_id;
   parameters = param;
   }

/*
* Create an AlgorithmIdentifier
*/
AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id,
                                         const MemoryRegion<byte>& param)
   {
   oid = OIDS::lookup(alg_id);
   parameters = param;
   }

/*
* Create an AlgorithmIdentifier
*/
AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id,
                                         Encoding_Option option)
   {
   const byte DER_NULL[] = { 0x05, 0x00 };

   oid = alg_id;

   if(option == USE_NULL_PARAM)
      {
      parameters += std::pair<const byte*, size_t>(DER_NULL, sizeof(DER_NULL));
      }
   }

/*
* Create an AlgorithmIdentifier
*/
AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id,
                                         Encoding_Option option)
   {
   const byte DER_NULL[] = { 0x05, 0x00 };

   oid = OIDS::lookup(alg_id);

   if(option == USE_NULL_PARAM)
      {
      parameters += std::pair<const byte*, size_t>(DER_NULL, sizeof(DER_NULL));
      }
   }

/*
* Compare two AlgorithmIdentifiers
*/
bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2)
   {
   if(a1.oid != a2.oid)
      return false;
   if(a1.parameters != a2.parameters)
      return false;
   return true;
   }

/*
* Compare two AlgorithmIdentifiers
*/
bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2)
   {
   return !(a1 == a2);
   }

/*
* DER encode an AlgorithmIdentifier
*/
void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const
   {
   codec.start_cons(SEQUENCE)
      .encode(oid)
      .raw_bytes(parameters)
   .end_cons();
   }

/*
* Decode a BER encoded AlgorithmIdentifier
*/
void AlgorithmIdentifier::decode_from(BER_Decoder& codec)
   {
   codec.start_cons(SEQUENCE)
      .decode(oid)
      .raw_bytes(parameters)
   .end_cons();
   }

}
/*
* AlternativeName
* (C) 1999-2007 Jack Lloyd
*     2007 Yves Jerschow
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Check if type is a known ASN.1 string type
*/
bool is_string_type(ASN1_Tag tag)
   {
   return (tag == NUMERIC_STRING ||
           tag == PRINTABLE_STRING ||
           tag == VISIBLE_STRING ||
           tag == T61_STRING ||
           tag == IA5_STRING ||
           tag == UTF8_STRING ||
           tag == BMP_STRING);
   }

}

/*
* Create an AlternativeName
*/
AlternativeName::AlternativeName(const std::string& email_addr,
                                 const std::string& uri,
                                 const std::string& dns,
                                 const std::string& ip)
   {
   add_attribute("RFC822", email_addr);
   add_attribute("DNS", dns);
   add_attribute("URI", uri);
   add_attribute("IP", ip);
   }

/*
* Add an attribute to an alternative name
*/
void AlternativeName::add_attribute(const std::string& type,
                                    const std::string& str)
   {
   if(type == "" || str == "")
      return;

   typedef std::multimap<std::string, std::string>::iterator iter;
   std::pair<iter, iter> range = alt_info.equal_range(type);
   for(iter j = range.first; j != range.second; ++j)
      if(j->second == str)
         return;

   multimap_insert(alt_info, type, str);
   }

/*
* Add an OtherName field
*/
void AlternativeName::add_othername(const OID& oid, const std::string& value,
                                    ASN1_Tag type)
   {
   if(value == "")
      return;
   multimap_insert(othernames, oid, ASN1_String(value, type));
   }

/*
* Get the attributes of this alternative name
*/
std::multimap<std::string, std::string> AlternativeName::get_attributes() const
   {
   return alt_info;
   }

/*
* Get the otherNames
*/
std::multimap<OID, ASN1_String> AlternativeName::get_othernames() const
   {
   return othernames;
   }

/*
* Return all of the alternative names
*/
std::multimap<std::string, std::string> AlternativeName::contents() const
   {
   std::multimap<std::string, std::string> names;

   typedef std::multimap<std::string, std::string>::const_iterator rdn_iter;
   for(rdn_iter j = alt_info.begin(); j != alt_info.end(); ++j)
      multimap_insert(names, j->first, j->second);

   typedef std::multimap<OID, ASN1_String>::const_iterator on_iter;
   for(on_iter j = othernames.begin(); j != othernames.end(); ++j)
      multimap_insert(names, OIDS::lookup(j->first), j->second.value());

   return names;
   }

/*
* Return if this object has anything useful
*/
bool AlternativeName::has_items() const
   {
   return (alt_info.size() > 0 || othernames.size() > 0);
   }

namespace {

/*
* DER encode an AlternativeName entry
*/
void encode_entries(DER_Encoder& encoder,
                    const std::multimap<std::string, std::string>& attr,
                    const std::string& type, ASN1_Tag tagging)
   {
   typedef std::multimap<std::string, std::string>::const_iterator iter;

   std::pair<iter, iter> range = attr.equal_range(type);
   for(iter j = range.first; j != range.second; ++j)
      {
      if(type == "RFC822" || type == "DNS" || type == "URI")
         {
         ASN1_String asn1_string(j->second, IA5_STRING);
         encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.iso_8859());
         }
      else if(type == "IP")
         {
         const u32bit ip = string_to_ipv4(j->second);
         byte ip_buf[4] = { 0 };
         store_be(ip, ip_buf);
         encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4);
         }
      }
   }

}

/*
* DER encode an AlternativeName extension
*/
void AlternativeName::encode_into(DER_Encoder& der) const
   {
   der.start_cons(SEQUENCE);

   encode_entries(der, alt_info, "RFC822", ASN1_Tag(1));
   encode_entries(der, alt_info, "DNS", ASN1_Tag(2));
   encode_entries(der, alt_info, "URI", ASN1_Tag(6));
   encode_entries(der, alt_info, "IP", ASN1_Tag(7));

   std::multimap<OID, ASN1_String>::const_iterator i;
   for(i = othernames.begin(); i != othernames.end(); ++i)
      {
      der.start_explicit(0)
         .encode(i->first)
         .start_explicit(0)
            .encode(i->second)
         .end_explicit()
      .end_explicit();
      }

   der.end_cons();
   }

/*
* Decode a BER encoded AlternativeName
*/
void AlternativeName::decode_from(BER_Decoder& source)
   {
   BER_Decoder names = source.start_cons(SEQUENCE);

   while(names.more_items())
      {
      BER_Object obj = names.get_next_object();
      if((obj.class_tag != CONTEXT_SPECIFIC) &&
         (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)))
         continue;

      const ASN1_Tag tag = obj.type_tag;

      if(tag == 0)
         {
         BER_Decoder othername(obj.value);

         OID oid;
         othername.decode(oid);
         if(othername.more_items())
            {
            BER_Object othername_value_outer = othername.get_next_object();
            othername.verify_end();

            if(othername_value_outer.type_tag != ASN1_Tag(0) ||
               othername_value_outer.class_tag !=
                   (CONTEXT_SPECIFIC | CONSTRUCTED)
               )
               throw Decoding_Error("Invalid tags on otherName value");

            BER_Decoder othername_value_inner(othername_value_outer.value);

            BER_Object value = othername_value_inner.get_next_object();
            othername_value_inner.verify_end();

            const ASN1_Tag value_type = value.type_tag;

            if(is_string_type(value_type) && value.class_tag == UNIVERSAL)
               add_othername(oid, ASN1::to_string(value), value_type);
            }
         }
      else if(tag == 1 || tag == 2 || tag == 6)
         {
         const std::string value = Charset::transcode(ASN1::to_string(obj),
                                                      LATIN1_CHARSET,
                                                      LOCAL_CHARSET);

         if(tag == 1) add_attribute("RFC822", value);
         if(tag == 2) add_attribute("DNS", value);
         if(tag == 6) add_attribute("URI", value);
         }
      else if(tag == 7)
         {
         if(obj.value.size() == 4)
            {
            const u32bit ip = load_be<u32bit>(&obj.value[0], 0);
            add_attribute("IP", ipv4_to_string(ip));
            }
         }

      }
   }

}
/*
* Attribute
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create an Attribute
*/
Attribute::Attribute(const OID& attr_oid, const MemoryRegion<byte>& attr_value)
   {
   oid = attr_oid;
   parameters = attr_value;
   }

/*
* Create an Attribute
*/
Attribute::Attribute(const std::string& attr_oid,
                     const MemoryRegion<byte>& attr_value)
   {
   oid = OIDS::lookup(attr_oid);
   parameters = attr_value;
   }

/*
* DER encode a Attribute
*/
void Attribute::encode_into(DER_Encoder& codec) const
   {
   codec.start_cons(SEQUENCE)
      .encode(oid)
      .start_cons(SET)
         .raw_bytes(parameters)
      .end_cons()
   .end_cons();
   }

/*
* Decode a BER encoded Attribute
*/
void Attribute::decode_from(BER_Decoder& codec)
   {
   codec.start_cons(SEQUENCE)
      .decode(oid)
      .start_cons(SET)
         .raw_bytes(parameters)
      .end_cons()
   .end_cons();
   }

}
/*
* ASN.1 Internals
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* BER Decoding Exceptions
*/
BER_Decoding_Error::BER_Decoding_Error(const std::string& str) :
   Decoding_Error("BER: " + str) {}

BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) :
      BER_Decoding_Error(str + ": " + to_string(tag)) {}

BER_Bad_Tag::BER_Bad_Tag(const std::string& str,
                         ASN1_Tag tag1, ASN1_Tag tag2) :
   BER_Decoding_Error(str + ": " + to_string(tag1) + "/" + to_string(tag2)) {}

namespace ASN1 {

/*
* Put some arbitrary bytes into a SEQUENCE
*/
SecureVector<byte> put_in_sequence(const MemoryRegion<byte>& contents)
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .raw_bytes(contents)
      .end_cons()
   .get_contents();
   }

/*
* Convert a BER object into a string object
*/
std::string to_string(const BER_Object& obj)
   {
   return std::string(reinterpret_cast<const char*>(&obj.value[0]),
                      obj.value.size());
   }

/*
* Do heuristic tests for BER data
*/
bool maybe_BER(DataSource& source)
   {
   byte first_byte;
   if(!source.peek_byte(first_byte))
      throw Stream_IO_Error("ASN1::maybe_BER: Source was empty");

   if(first_byte == (SEQUENCE | CONSTRUCTED))
      return true;
   return false;
   }

}

}
/*
* ASN.1 OID
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* ASN.1 OID Constructor
*/
OID::OID(const std::string& oid_str)
   {
   if(oid_str != "")
      {
      try
         {
         id = parse_asn1_oid(oid_str);
         }
      catch(...)
         {
         throw Invalid_OID(oid_str);
         }

      if(id.size() < 2 || id[0] > 2)
         throw Invalid_OID(oid_str);
      if((id[0] == 0 || id[0] == 1) && id[1] > 39)
         throw Invalid_OID(oid_str);
      }
   }

/*
* Clear the current OID
*/
void OID::clear()
   {
   id.clear();
   }

/*
* Return this OID as a string
*/
std::string OID::as_string() const
   {
   std::string oid_str;
   for(size_t i = 0; i != id.size(); ++i)
      {
      oid_str += to_string(id[i]);
      if(i != id.size() - 1)
         oid_str += '.';
      }
   return oid_str;
   }

/*
* OID equality comparison
*/
bool OID::operator==(const OID& oid) const
   {
   if(id.size() != oid.id.size())
      return false;
   for(size_t i = 0; i != id.size(); ++i)
      if(id[i] != oid.id[i])
         return false;
   return true;
   }

/*
* Append another component to the OID
*/
OID& OID::operator+=(u32bit component)
   {
   id.push_back(component);
   return (*this);
   }

/*
* Append another component to the OID
*/
OID operator+(const OID& oid, u32bit component)
   {
   OID new_oid(oid);
   new_oid += component;
   return new_oid;
   }

/*
* OID inequality comparison
*/
bool operator!=(const OID& a, const OID& b)
   {
   return !(a == b);
   }

/*
* Compare two OIDs
*/
bool operator<(const OID& a, const OID& b)
   {
   std::vector<u32bit> oid1 = a.get_id();
   std::vector<u32bit> oid2 = b.get_id();

   if(oid1.size() < oid2.size())
      return true;
   if(oid1.size() > oid2.size())
      return false;
   for(size_t i = 0; i != oid1.size(); ++i)
      {
      if(oid1[i] < oid2[i])
         return true;
      if(oid1[i] > oid2[i])
         return false;
      }
   return false;
   }

/*
* DER encode an OBJECT IDENTIFIER
*/
void OID::encode_into(DER_Encoder& der) const
   {
   if(id.size() < 2)
      throw Invalid_Argument("OID::encode_into: OID is invalid");

   MemoryVector<byte> encoding;
   encoding.push_back(40 * id[0] + id[1]);

   for(size_t i = 2; i != id.size(); ++i)
      {
      if(id[i] == 0)
         encoding.push_back(0);
      else
         {
         size_t blocks = high_bit(id[i]) + 6;
         blocks = (blocks - (blocks % 7)) / 7;

         for(size_t j = 0; j != blocks - 1; ++j)
            encoding.push_back(0x80 | ((id[i] >> 7*(blocks-j-1)) & 0x7F));
         encoding.push_back(id[i] & 0x7F);
         }
      }
   der.add_object(OBJECT_ID, UNIVERSAL, encoding);
   }

/*
* Decode a BER encoded OBJECT IDENTIFIER
*/
void OID::decode_from(BER_Decoder& decoder)
   {
   BER_Object obj = decoder.get_next_object();
   if(obj.type_tag != OBJECT_ID || obj.class_tag != UNIVERSAL)
      throw BER_Bad_Tag("Error decoding OID, unknown tag",
                        obj.type_tag, obj.class_tag);
   if(obj.value.size() < 2)
      throw BER_Decoding_Error("OID encoding is too short");


   clear();
   id.push_back(obj.value[0] / 40);
   id.push_back(obj.value[0] % 40);

   size_t i = 0;
   while(i != obj.value.size() - 1)
      {
      u32bit component = 0;
      while(i != obj.value.size() - 1)
         {
         ++i;
         component = (component << 7) + (obj.value[i] & 0x7F);
         if(!(obj.value[i] & 0x80))
            break;
         }
      id.push_back(component);
      }
   }

}
/*
* Simple ASN.1 String Types
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Choose an encoding for the string
*/
ASN1_Tag choose_encoding(const std::string& str,
                         const std::string& type)
   {
   static const byte IS_PRINTABLE[256] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
      0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
      0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00 };

   for(size_t i = 0; i != str.size(); ++i)
      {
      if(!IS_PRINTABLE[static_cast<byte>(str[i])])
         {
         if(type == "utf8")   return UTF8_STRING;
         if(type == "latin1") return T61_STRING;
         throw Invalid_Argument("choose_encoding: Bad string type " + type);
         }
      }
   return PRINTABLE_STRING;
   }

}

/*
* Create an ASN1_String
*/
ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : tag(t)
   {
   iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET);

   if(tag == DIRECTORY_STRING)
      tag = choose_encoding(iso_8859_str, "latin1");

   if(tag != NUMERIC_STRING &&
      tag != PRINTABLE_STRING &&
      tag != VISIBLE_STRING &&
      tag != T61_STRING &&
      tag != IA5_STRING &&
      tag != UTF8_STRING &&
      tag != BMP_STRING)
      throw Invalid_Argument("ASN1_String: Unknown string type " +
                             to_string(tag));
   }

/*
* Create an ASN1_String
*/
ASN1_String::ASN1_String(const std::string& str)
   {
   iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET);
   tag = choose_encoding(iso_8859_str, "latin1");
   }

/*
* Return this string in ISO 8859-1 encoding
*/
std::string ASN1_String::iso_8859() const
   {
   return iso_8859_str;
   }

/*
* Return this string in local encoding
*/
std::string ASN1_String::value() const
   {
   return Charset::transcode(iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET);
   }

/*
* Return the type of this string object
*/
ASN1_Tag ASN1_String::tagging() const
   {
   return tag;
   }

/*
* DER encode an ASN1_String
*/
void ASN1_String::encode_into(DER_Encoder& encoder) const
   {
   std::string value = iso_8859();
   if(tagging() == UTF8_STRING)
      value = Charset::transcode(value, LATIN1_CHARSET, UTF8_CHARSET);
   encoder.add_object(tagging(), UNIVERSAL, value);
   }

/*
* Decode a BER encoded ASN1_String
*/
void ASN1_String::decode_from(BER_Decoder& source)
   {
   BER_Object obj = source.get_next_object();

   Character_Set charset_is;

   if(obj.type_tag == BMP_STRING)
      charset_is = UCS2_CHARSET;
   else if(obj.type_tag == UTF8_STRING)
      charset_is = UTF8_CHARSET;
   else
      charset_is = LATIN1_CHARSET;

   *this = ASN1_String(
      Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET),
      obj.type_tag);
   }

}
/*
* X.509 Time Types
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create an X509_Time
*/
X509_Time::X509_Time(const std::string& time_str)
   {
   set_to(time_str);
   }

/*
* Create an X509_Time
*/
X509_Time::X509_Time(u64bit timer)
   {
   calendar_point cal = calendar_value(timer);

   year   = cal.year;
   month  = cal.month;
   day    = cal.day;
   hour   = cal.hour;
   minute = cal.minutes;
   second = cal.seconds;

   tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
   }

/*
* Create an X509_Time
*/
X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
   {
   set_to(t_spec, tag);
   }

/*
* Set the time with a human readable string
*/
void X509_Time::set_to(const std::string& time_str)
   {
   if(time_str == "")
      {
      year = month = day = hour = minute = second = 0;
      tag = NO_OBJECT;
      return;
      }

   std::vector<std::string> params;
   std::string current;

   for(size_t j = 0; j != time_str.size(); ++j)
      {
      if(Charset::is_digit(time_str[j]))
         current += time_str[j];
      else
         {
         if(current != "")
            params.push_back(current);
         current.clear();
         }
      }
   if(current != "")
      params.push_back(current);

   if(params.size() < 3 || params.size() > 6)
      throw Invalid_Argument("Invalid time specification " + time_str);

   year   = to_u32bit(params[0]);
   month  = to_u32bit(params[1]);
   day    = to_u32bit(params[2]);
   hour   = (params.size() >= 4) ? to_u32bit(params[3]) : 0;
   minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0;
   second = (params.size() == 6) ? to_u32bit(params[5]) : 0;

   tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;

   if(!passes_sanity_check())
      throw Invalid_Argument("Invalid time specification " + time_str);
   }

/*
* Set the time with an ISO time format string
*/
void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
   {
   if(spec_tag != GENERALIZED_TIME && spec_tag != UTC_TIME)
      throw Invalid_Argument("X509_Time: Invalid tag " + to_string(spec_tag));

   if(spec_tag == GENERALIZED_TIME && t_spec.size() != 13 && t_spec.size() != 15)
      throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec);

   if(spec_tag == UTC_TIME && t_spec.size() != 11 && t_spec.size() != 13)
      throw Invalid_Argument("Invalid UTCTime: " + t_spec);

   if(t_spec[t_spec.size()-1] != 'Z')
      throw Invalid_Argument("Invalid time encoding: " + t_spec);

   const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;

   std::vector<std::string> params;
   std::string current;

   for(size_t j = 0; j != YEAR_SIZE; ++j)
      current += t_spec[j];
   params.push_back(current);
   current.clear();

   for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
      {
      current += t_spec[j];
      if(current.size() == 2)
         {
         params.push_back(current);
         current.clear();
         }
      }

   year   = to_u32bit(params[0]);
   month  = to_u32bit(params[1]);
   day    = to_u32bit(params[2]);
   hour   = to_u32bit(params[3]);
   minute = to_u32bit(params[4]);
   second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
   tag    = spec_tag;

   if(spec_tag == UTC_TIME)
      {
      if(year >= 50) year += 1900;
      else           year += 2000;
      }

   if(!passes_sanity_check())
      throw Invalid_Argument("Invalid time specification " + t_spec);
   }

/*
* DER encode a X509_Time
*/
void X509_Time::encode_into(DER_Encoder& der) const
   {
   if(tag != GENERALIZED_TIME && tag != UTC_TIME)
      throw Invalid_Argument("X509_Time: Bad encoding tag");

   der.add_object(tag, UNIVERSAL,
                  Charset::transcode(as_string(),
                                     LOCAL_CHARSET,
                                     LATIN1_CHARSET));
   }

/*
* Decode a BER encoded X509_Time
*/
void X509_Time::decode_from(BER_Decoder& source)
   {
   BER_Object ber_time = source.get_next_object();

   set_to(Charset::transcode(ASN1::to_string(ber_time),
                             LATIN1_CHARSET,
                             LOCAL_CHARSET),
          ber_time.type_tag);
   }

/*
* Return a string representation of the time
*/
std::string X509_Time::as_string() const
   {
   if(time_is_set() == false)
      throw Invalid_State("X509_Time::as_string: No time set");

   std::string asn1rep;
   if(tag == GENERALIZED_TIME)
      asn1rep = to_string(year, 4);
   else if(tag == UTC_TIME)
      {
      if(year < 1950 || year >= 2050)
         throw Encoding_Error("X509_Time: The time " + readable_string() +
                              " cannot be encoded as a UTCTime");
      u32bit asn1year = (year >= 2000) ? (year - 2000) : (year - 1900);
      asn1rep = to_string(asn1year, 2);
      }
   else
      throw Invalid_Argument("X509_Time: Invalid tag " + to_string(tag));

   asn1rep += to_string(month, 2) + to_string(day, 2);
   asn1rep += to_string(hour, 2) + to_string(minute, 2) + to_string(second, 2);
   asn1rep += "Z";
   return asn1rep;
   }

/*
* Return if the time has been set somehow
*/
bool X509_Time::time_is_set() const
   {
   return (year != 0);
   }

/*
* Return a human readable string representation
*/
std::string X509_Time::readable_string() const
   {
   if(time_is_set() == false)
      throw Invalid_State("X509_Time::readable_string: No time set");

   std::string readable;
   readable += to_string(year,   4) + "/";
   readable += to_string(month    ) + "/";
   readable += to_string(day      ) + " ";
   readable += to_string(hour     ) + ":";
   readable += to_string(minute, 2) + ":";
   readable += to_string(second, 2) + " UTC";
   return readable;
   }

/*
* Do a general sanity check on the time
*/
bool X509_Time::passes_sanity_check() const
   {
   if(year < 1950 || year > 2100)
      return false;
   if(month == 0 || month > 12)
      return false;
   if(day == 0 || day > 31)
      return false;
   if(hour >= 24 || minute > 60 || second > 60)
      return false;
   return true;
   }

/*
* Compare this time against another
*/
s32bit X509_Time::cmp(const X509_Time& other) const
   {
   if(time_is_set() == false)
      throw Invalid_State("X509_Time::cmp: No time set");

   const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;

   if(year < other.year)     return EARLIER;
   if(year > other.year)     return LATER;
   if(month < other.month)   return EARLIER;
   if(month > other.month)   return LATER;
   if(day < other.day)       return EARLIER;
   if(day > other.day)       return LATER;
   if(hour < other.hour)     return EARLIER;
   if(hour > other.hour)     return LATER;
   if(minute < other.minute) return EARLIER;
   if(minute > other.minute) return LATER;
   if(second < other.second) return EARLIER;
   if(second > other.second) return LATER;

   return SAME_TIME;
   }

/*
* Compare two X509_Times for in various ways
*/
bool operator==(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) == 0); }
bool operator!=(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) != 0); }

bool operator<=(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) <= 0); }
bool operator>=(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) >= 0); }

bool operator<(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) < 0); }
bool operator>(const X509_Time& t1, const X509_Time& t2)
   { return (t1.cmp(t2) > 0); }

}
/*
* BER Decoder
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* BER decode an ASN.1 type tag
*/
size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag)
   {
   byte b;
   if(!ber->read_byte(b))
      {
      class_tag = type_tag = NO_OBJECT;
      return 0;
      }

   if((b & 0x1F) != 0x1F)
      {
      type_tag = ASN1_Tag(b & 0x1F);
      class_tag = ASN1_Tag(b & 0xE0);
      return 1;
      }

   size_t tag_bytes = 1;
   class_tag = ASN1_Tag(b & 0xE0);

   size_t tag_buf = 0;
   while(true)
      {
      if(!ber->read_byte(b))
         throw BER_Decoding_Error("Long-form tag truncated");
      if(tag_buf & 0xFF000000)
         throw BER_Decoding_Error("Long-form tag overflowed 32 bits");
      ++tag_bytes;
      tag_buf = (tag_buf << 7) | (b & 0x7F);
      if((b & 0x80) == 0) break;
      }
   type_tag = ASN1_Tag(tag_buf);
   return tag_bytes;
   }

/*
* Find the EOC marker
*/
size_t find_eoc(DataSource*);

/*
* BER decode an ASN.1 length field
*/
size_t decode_length(DataSource* ber, size_t& field_size)
   {
   byte b;
   if(!ber->read_byte(b))
      throw BER_Decoding_Error("Length field not found");
   field_size = 1;
   if((b & 0x80) == 0)
      return b;

   field_size += (b & 0x7F);
   if(field_size == 1) return find_eoc(ber);
   if(field_size > 5)
      throw BER_Decoding_Error("Length field is too large");

   size_t length = 0;

   for(size_t i = 0; i != field_size - 1; ++i)
      {
      if(get_byte(0, length) != 0)
         throw BER_Decoding_Error("Field length overflow");
      if(!ber->read_byte(b))
         throw BER_Decoding_Error("Corrupted length field");
      length = (length << 8) | b;
      }
   return length;
   }

/*
* BER decode an ASN.1 length field
*/
size_t decode_length(DataSource* ber)
   {
   size_t dummy;
   return decode_length(ber, dummy);
   }

/*
* Find the EOC marker
*/
size_t find_eoc(DataSource* ber)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE), data;

   while(true)
      {
      const size_t got = ber->peek(&buffer[0], buffer.size(), data.size());
      if(got == 0)
         break;

      data += std::make_pair(&buffer[0], got);
      }

   DataSource_Memory source(data);
   data.clear();

   size_t length = 0;
   while(true)
      {
      ASN1_Tag type_tag, class_tag;
      size_t tag_size = decode_tag(&source, type_tag, class_tag);
      if(type_tag == NO_OBJECT)
         break;

      size_t length_size = 0;
      size_t item_size = decode_length(&source, length_size);
      source.discard_next(item_size);

      length += item_size + length_size + tag_size;

      if(type_tag == EOC)
         break;
      }
   return length;
   }

}

/*
* Check a type invariant on BER data
*/
void BER_Object::assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(this->type_tag != type_tag || this->class_tag != class_tag)
      throw BER_Decoding_Error("Tag mismatch when decoding");
   }

/*
* Check if more objects are there
*/
bool BER_Decoder::more_items() const
   {
   if(source->end_of_data() && (pushed.type_tag == NO_OBJECT))
      return false;
   return true;
   }

/*
* Verify that no bytes remain in the source
*/
BER_Decoder& BER_Decoder::verify_end()
   {
   if(!source->end_of_data() || (pushed.type_tag != NO_OBJECT))
      throw Invalid_State("BER_Decoder::verify_end called, but data remains");
   return (*this);
   }

/*
* Save all the bytes remaining in the source
*/
BER_Decoder& BER_Decoder::raw_bytes(MemoryRegion<byte>& out)
   {
   out.clear();
   byte buf;
   while(source->read_byte(buf))
      out.push_back(buf);
   return (*this);
   }

/*
* Discard all the bytes remaining in the source
*/
BER_Decoder& BER_Decoder::discard_remaining()
   {
   byte buf;
   while(source->read_byte(buf))
      ;
   return (*this);
   }

/*
* Return the BER encoding of the next object
*/
BER_Object BER_Decoder::get_next_object()
   {
   BER_Object next;

   if(pushed.type_tag != NO_OBJECT)
      {
      next = pushed;
      pushed.class_tag = pushed.type_tag = NO_OBJECT;
      return next;
      }

   decode_tag(source, next.type_tag, next.class_tag);
   if(next.type_tag == NO_OBJECT)
      return next;

   size_t length = decode_length(source);
   next.value.resize(length);
   if(source->read(&next.value[0], length) != length)
      throw BER_Decoding_Error("Value truncated");

   if(next.type_tag == EOC && next.class_tag == UNIVERSAL)
      return get_next_object();

   return next;
   }

/*
* Push a object back into the stream
*/
void BER_Decoder::push_back(const BER_Object& obj)
   {
   if(pushed.type_tag != NO_OBJECT)
      throw Invalid_State("BER_Decoder: Only one push back is allowed");
   pushed = obj;
   }

/*
* Begin decoding a CONSTRUCTED type
*/
BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag,
                                    ASN1_Tag class_tag)
   {
   BER_Object obj = get_next_object();
   obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED));

   BER_Decoder result(&obj.value[0], obj.value.size());
   result.parent = this;
   return result;
   }

/*
* Finish decoding a CONSTRUCTED type
*/
BER_Decoder& BER_Decoder::end_cons()
   {
   if(!parent)
      throw Invalid_State("BER_Decoder::end_cons called with NULL parent");
   if(!source->end_of_data())
      throw Decoding_Error("BER_Decoder::end_cons called with data left");
   return (*parent);
   }

/*
* BER_Decoder Constructor
*/
BER_Decoder::BER_Decoder(DataSource& src)
   {
   source = &src;
   owns = false;
   pushed.type_tag = pushed.class_tag = NO_OBJECT;
   parent = 0;
   }

/*
* BER_Decoder Constructor
 */
BER_Decoder::BER_Decoder(const byte data[], size_t length)
   {
   source = new DataSource_Memory(data, length);
   owns = true;
   pushed.type_tag = pushed.class_tag = NO_OBJECT;
   parent = 0;
   }

/*
* BER_Decoder Constructor
*/
BER_Decoder::BER_Decoder(const MemoryRegion<byte>& data)
   {
   source = new DataSource_Memory(data);
   owns = true;
   pushed.type_tag = pushed.class_tag = NO_OBJECT;
   parent = 0;
   }

/*
* BER_Decoder Copy Constructor
*/
BER_Decoder::BER_Decoder(const BER_Decoder& other)
   {
   source = other.source;
   owns = false;
   if(other.owns)
      {
      other.owns = false;
      owns = true;
      }
   pushed.type_tag = pushed.class_tag = NO_OBJECT;
   parent = other.parent;
   }

/*
* BER_Decoder Destructor
*/
BER_Decoder::~BER_Decoder()
   {
   if(owns)
      delete source;
   source = 0;
   }

/*
* Request for an object to decode itself
*/
BER_Decoder& BER_Decoder::decode(ASN1_Object& obj)
   {
   obj.decode_from(*this);
   return (*this);
   }

/*
* Decode a BER encoded NULL
*/
BER_Decoder& BER_Decoder::decode_null()
   {
   BER_Object obj = get_next_object();
   obj.assert_is_a(NULL_TAG, UNIVERSAL);
   if(obj.value.size())
      throw BER_Decoding_Error("NULL object had nonzero size");
   return (*this);
   }

/*
* Decode a BER encoded BOOLEAN
*/
BER_Decoder& BER_Decoder::decode(bool& out)
   {
   return decode(out, BOOLEAN, UNIVERSAL);
   }

/*
* Decode a small BER encoded INTEGER
*/
BER_Decoder& BER_Decoder::decode(size_t& out)
   {
   return decode(out, INTEGER, UNIVERSAL);
   }

/*
* Decode a BER encoded INTEGER
*/
BER_Decoder& BER_Decoder::decode(BigInt& out)
   {
   return decode(out, INTEGER, UNIVERSAL);
   }

BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out)
   {
   SecureVector<byte> out_vec;
   decode(out_vec, OCTET_STRING);
   out = BigInt::decode(&out_vec[0], out_vec.size());
   return (*this);
   }

/*
* Decode a BER encoded BOOLEAN
*/
BER_Decoder& BER_Decoder::decode(bool& out,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   BER_Object obj = get_next_object();
   obj.assert_is_a(type_tag, class_tag);

   if(obj.value.size() != 1)
      throw BER_Decoding_Error("BER boolean value had invalid size");

   out = (obj.value[0]) ? true : false;
   return (*this);
   }

/*
* Decode a small BER encoded INTEGER
*/
BER_Decoder& BER_Decoder::decode(size_t& out,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   BigInt integer;
   decode(integer, type_tag, class_tag);

   if(integer.bits() > 32)
      throw BER_Decoding_Error("Decoded integer value larger than expected");

   out = 0;
   for(size_t i = 0; i != 4; ++i)
      out = (out << 8) | integer.byte_at(3-i);

   return (*this);
   }

/*
* Decode a BER encoded INTEGER
*/
BER_Decoder& BER_Decoder::decode(BigInt& out,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   BER_Object obj = get_next_object();
   obj.assert_is_a(type_tag, class_tag);

   if(obj.value.empty())
      out = 0;
   else
      {
      const bool negative = (obj.value[0] & 0x80) ? true : false;

      if(negative)
         {
         for(size_t i = obj.value.size(); i > 0; --i)
            if(obj.value[i-1]--)
               break;
         for(size_t i = 0; i != obj.value.size(); ++i)
            obj.value[i] = ~obj.value[i];
         }

      out = BigInt(&obj.value[0], obj.value.size());

      if(negative)
         out.flip_sign();
      }

   return (*this);
   }

/*
* BER decode a BIT STRING or OCTET STRING
*/
BER_Decoder& BER_Decoder::decode(MemoryRegion<byte>& out, ASN1_Tag real_type)
   {
   return decode(out, real_type, real_type, UNIVERSAL);
   }

/*
* BER decode a BIT STRING or OCTET STRING
*/
BER_Decoder& BER_Decoder::decode(MemoryRegion<byte>& buffer,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(real_type != OCTET_STRING && real_type != BIT_STRING)
      throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type);

   BER_Object obj = get_next_object();
   obj.assert_is_a(type_tag, class_tag);

   if(real_type == OCTET_STRING)
      buffer = obj.value;
   else
      {
      if(obj.value[0] >= 8)
         throw BER_Decoding_Error("Bad number of unused bits in BIT STRING");

      buffer.resize(obj.value.size() - 1);
      copy_mem(&buffer[0], &obj.value[1], obj.value.size() - 1);
      }
   return (*this);
   }

/*
* Decode an OPTIONAL string type
*/
BER_Decoder& BER_Decoder::decode_optional_string(MemoryRegion<byte>& out,
                                                 ASN1_Tag real_type,
                                                 u16bit type_no)
   {
   BER_Object obj = get_next_object();

   ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);

   out.clear();
   push_back(obj);

   if(obj.type_tag == type_tag && obj.class_tag == CONTEXT_SPECIFIC)
      decode(out, real_type, type_tag, CONTEXT_SPECIFIC);

   return (*this);
   }

}
/*
* DER Encoder
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

/*
* DER encode an ASN.1 type tag
*/
SecureVector<byte> encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if((class_tag | 0xE0) != 0xE0)
      throw Encoding_Error("DER_Encoder: Invalid class tag " +
                           to_string(class_tag));

   SecureVector<byte> encoded_tag;
   if(type_tag <= 30)
      encoded_tag.push_back(static_cast<byte>(type_tag | class_tag));
   else
      {
      size_t blocks = high_bit(type_tag) + 6;
      blocks = (blocks - (blocks % 7)) / 7;

      encoded_tag.push_back(class_tag | 0x1F);
      for(size_t i = 0; i != blocks - 1; ++i)
         encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F));
      encoded_tag.push_back(type_tag & 0x7F);
      }

   return encoded_tag;
   }

/*
* DER encode an ASN.1 length field
*/
SecureVector<byte> encode_length(size_t length)
   {
   SecureVector<byte> encoded_length;
   if(length <= 127)
      encoded_length.push_back(static_cast<byte>(length));
   else
      {
      const size_t top_byte = significant_bytes(length);

      encoded_length.push_back(static_cast<byte>(0x80 | top_byte));

      for(size_t i = sizeof(length) - top_byte; i != sizeof(length); ++i)
         encoded_length.push_back(get_byte(i, length));
      }
   return encoded_length;
   }

}

/*
* Return the encoded SEQUENCE/SET
*/
SecureVector<byte> DER_Encoder::DER_Sequence::get_contents()
   {
   const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED);

   if(type_tag == SET)
      {
      std::sort(set_contents.begin(), set_contents.end());
      for(size_t i = 0; i != set_contents.size(); ++i)
         contents += set_contents[i];
      set_contents.clear();
      }

   SecureVector<byte> result;
   result += encode_tag(type_tag, real_class_tag);
   result += encode_length(contents.size());
   result += contents;
   contents.clear();

   return result;
   }

/*
* Add an encoded value to the SEQUENCE/SET
*/
void DER_Encoder::DER_Sequence::add_bytes(const byte data[], size_t length)
   {
   if(type_tag == SET)
      set_contents.push_back(SecureVector<byte>(data, length));
   else
      contents += std::make_pair(data, length);
   }

/*
* Return the type and class taggings
*/
ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const
   {
   return ASN1_Tag(type_tag | class_tag);
   }

/*
* DER_Sequence Constructor
*/
DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) :
   type_tag(t1), class_tag(t2)
   {
   }

/*
* Return the encoded contents
*/
SecureVector<byte> DER_Encoder::get_contents()
   {
   if(subsequences.size() != 0)
      throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");

   SecureVector<byte> output;
   std::swap(output, contents);
   return output;
   }

/*
* Start a new ASN.1 SEQUENCE/SET/EXPLICIT
*/
DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag)
   {
   subsequences.push_back(DER_Sequence(type_tag, class_tag));
   return (*this);
   }

/*
* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT
*/
DER_Encoder& DER_Encoder::end_cons()
   {
   if(subsequences.empty())
      throw Invalid_State("DER_Encoder::end_cons: No such sequence");

   SecureVector<byte> seq = subsequences[subsequences.size()-1].get_contents();
   subsequences.pop_back();
   raw_bytes(seq);
   return (*this);
   }

/*
* Start a new ASN.1 EXPLICIT encoding
*/
DER_Encoder& DER_Encoder::start_explicit(u16bit type_no)
   {
   ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);

   if(type_tag == SET)
      throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform");

   return start_cons(type_tag, CONTEXT_SPECIFIC);
   }

/*
* Finish the current ASN.1 EXPLICIT encoding
*/
DER_Encoder& DER_Encoder::end_explicit()
   {
   return end_cons();
   }

/*
* Write raw bytes into the stream
*/
DER_Encoder& DER_Encoder::raw_bytes(const MemoryRegion<byte>& val)
   {
   return raw_bytes(&val[0], val.size());
   }

/*
* Write raw bytes into the stream
*/
DER_Encoder& DER_Encoder::raw_bytes(const byte bytes[], size_t length)
   {
   if(subsequences.size())
      subsequences[subsequences.size()-1].add_bytes(bytes, length);
   else
      contents += std::make_pair(bytes, length);

   return (*this);
   }

/*
* Encode a NULL object
*/
DER_Encoder& DER_Encoder::encode_null()
   {
   return add_object(NULL_TAG, UNIVERSAL, 0, 0);
   }

/*
* DER encode a BOOLEAN
*/
DER_Encoder& DER_Encoder::encode(bool is_true)
   {
   return encode(is_true, BOOLEAN, UNIVERSAL);
   }

/*
* DER encode a small INTEGER
*/
DER_Encoder& DER_Encoder::encode(size_t n)
   {
   return encode(BigInt(n), INTEGER, UNIVERSAL);
   }

/*
* DER encode a small INTEGER
*/
DER_Encoder& DER_Encoder::encode(const BigInt& n)
   {
   return encode(n, INTEGER, UNIVERSAL);
   }

/*
* DER encode an OCTET STRING or BIT STRING
*/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type)
   {
   return encode(&bytes[0], bytes.size(),
                 real_type, real_type, UNIVERSAL);
   }

/*
* Encode this object
*/
DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length,
                                 ASN1_Tag real_type)
   {
   return encode(bytes, length, real_type, real_type, UNIVERSAL);
   }

/*
* DER encode a BOOLEAN
*/
DER_Encoder& DER_Encoder::encode(bool is_true,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   byte val = is_true ? 0xFF : 0x00;
   return add_object(type_tag, class_tag, &val, 1);
   }

/*
* DER encode a small INTEGER
*/
DER_Encoder& DER_Encoder::encode(size_t n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(BigInt(n), type_tag, class_tag);
   }

/*
* DER encode an INTEGER
*/
DER_Encoder& DER_Encoder::encode(const BigInt& n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(n == 0)
      return add_object(type_tag, class_tag, 0);

   bool extra_zero = (n.bits() % 8 == 0);
   SecureVector<byte> contents(extra_zero + n.bytes());
   BigInt::encode(&contents[extra_zero], n);
   if(n < 0)
      {
      for(size_t i = 0; i != contents.size(); ++i)
         contents[i] = ~contents[i];
      for(size_t i = contents.size(); i > 0; --i)
         if(++contents[i-1])
            break;
      }

   return add_object(type_tag, class_tag, contents);
   }

/*
* DER encode an OCTET STRING or BIT STRING
*/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(&bytes[0], bytes.size(),
                 real_type, type_tag, class_tag);
   }

/*
* DER encode an OCTET STRING or BIT STRING
*/
DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(real_type != OCTET_STRING && real_type != BIT_STRING)
      throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");

   if(real_type == BIT_STRING)
      {
      SecureVector<byte> encoded;
      encoded.push_back(0);
      encoded += std::make_pair(bytes, length);
      return add_object(type_tag, class_tag, encoded);
      }
   else
      return add_object(type_tag, class_tag, bytes, length);
   }

/*
* Conditionally write some values to the stream
*/
DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec)
   {
   if(cond)
      return raw_bytes(codec.get_contents());
   return (*this);
   }

/*
* Request for an object to encode itself
*/
DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
   {
   obj.encode_into(*this);
   return (*this);
   }

/*
* Write the encoding of the byte(s)
*/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const byte rep[], size_t length)
   {
   SecureVector<byte> buffer;
   buffer += encode_tag(type_tag, class_tag);
   buffer += encode_length(length);
   buffer += std::make_pair(rep, length);

   return raw_bytes(buffer);
   }

/*
* Write the encoding of the byte(s)
*/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const MemoryRegion<byte>& rep_buf)
   {
   const byte* rep = &rep_buf[0];
   const size_t rep_len = rep_buf.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*
* Write the encoding of the byte(s)
*/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const std::string& rep_str)
   {
   const byte* rep = reinterpret_cast<const byte*>(rep_str.data());
   const size_t rep_len = rep_str.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*
* Write the encoding of the byte
*/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag, byte rep)
   {
   return add_object(type_tag, class_tag, &rep, 1);
   }

}
/*
* X509_DN
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create an empty X509_DN
*/
X509_DN::X509_DN()
   {
   }

/*
* Create an X509_DN
*/
X509_DN::X509_DN(const std::multimap<OID, std::string>& args)
   {
   std::multimap<OID, std::string>::const_iterator j;
   for(j = args.begin(); j != args.end(); ++j)
      add_attribute(j->first, j->second);
   }

/*
* Create an X509_DN
*/
X509_DN::X509_DN(const std::multimap<std::string, std::string>& args)
   {
   std::multimap<std::string, std::string>::const_iterator j;
   for(j = args.begin(); j != args.end(); ++j)
      add_attribute(OIDS::lookup(j->first), j->second);
   }

/*
* Add an attribute to a X509_DN
*/
void X509_DN::add_attribute(const std::string& type,
                            const std::string& str)
   {
   OID oid = OIDS::lookup(type);
   add_attribute(oid, str);
   }

/*
* Add an attribute to a X509_DN
*/
void X509_DN::add_attribute(const OID& oid, const std::string& str)
   {
   if(str == "")
      return;

   typedef std::multimap<OID, ASN1_String>::iterator rdn_iter;

   std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);
   for(rdn_iter j = range.first; j != range.second; ++j)
      if(j->second.value() == str)
         return;

   multimap_insert(dn_info, oid, ASN1_String(str));
   dn_bits.clear();
   }

/*
* Get the attributes of this X509_DN
*/
std::multimap<OID, std::string> X509_DN::get_attributes() const
   {
   typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;

   std::multimap<OID, std::string> retval;
   for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j)
      multimap_insert(retval, j->first, j->second.value());
   return retval;
   }

/*
* Get the contents of this X.500 Name
*/
std::multimap<std::string, std::string> X509_DN::contents() const
   {
   typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;

   std::multimap<std::string, std::string> retval;
   for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j)
      multimap_insert(retval, OIDS::lookup(j->first), j->second.value());
   return retval;
   }

/*
* Get a single attribute type
*/
std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const
   {
   typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;

   const OID oid = OIDS::lookup(deref_info_field(attr));
   std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);

   std::vector<std::string> values;
   for(rdn_iter j = range.first; j != range.second; ++j)
      values.push_back(j->second.value());
   return values;
   }

/*
* Return the BER encoded data, if any
*/
MemoryVector<byte> X509_DN::get_bits() const
   {
   return dn_bits;
   }

/*
* Deref aliases in a subject/issuer info request
*/
std::string X509_DN::deref_info_field(const std::string& info)
   {
   if(info == "Name" || info == "CommonName") return "X520.CommonName";
   if(info == "SerialNumber")                 return "X520.SerialNumber";
   if(info == "Country")                      return "X520.Country";
   if(info == "Organization")                 return "X520.Organization";
   if(info == "Organizational Unit" || info == "OrgUnit")
      return "X520.OrganizationalUnit";
   if(info == "Locality")                     return "X520.Locality";
   if(info == "State" || info == "Province")  return "X520.State";
   if(info == "Email")                        return "RFC822";
   return info;
   }

/*
* Compare two X509_DNs for equality
*/
bool operator==(const X509_DN& dn1, const X509_DN& dn2)
   {
   typedef std::multimap<OID, std::string>::const_iterator rdn_iter;

   std::multimap<OID, std::string> attr1 = dn1.get_attributes();
   std::multimap<OID, std::string> attr2 = dn2.get_attributes();

   if(attr1.size() != attr2.size()) return false;

   rdn_iter p1 = attr1.begin();
   rdn_iter p2 = attr2.begin();

   while(true)
      {
      if(p1 == attr1.end() && p2 == attr2.end())
         break;
      if(p1 == attr1.end())      return false;
      if(p2 == attr2.end())      return false;
      if(p1->first != p2->first) return false;
      if(!x500_name_cmp(p1->second, p2->second))
         return false;
      ++p1;
      ++p2;
      }
   return true;
   }

/*
* Compare two X509_DNs for inequality
*/
bool operator!=(const X509_DN& dn1, const X509_DN& dn2)
   {
   return !(dn1 == dn2);
   }

/*
* Compare two X509_DNs
*/
bool operator<(const X509_DN& dn1, const X509_DN& dn2)
   {
   typedef std::multimap<OID, std::string>::const_iterator rdn_iter;

   std::multimap<OID, std::string> attr1 = dn1.get_attributes();
   std::multimap<OID, std::string> attr2 = dn2.get_attributes();

   if(attr1.size() < attr2.size()) return true;
   if(attr1.size() > attr2.size()) return false;

   for(rdn_iter p1 = attr1.begin(); p1 != attr1.end(); ++p1)
      {
      std::multimap<OID, std::string>::const_iterator p2;
      p2 = attr2.find(p1->first);
      if(p2 == attr2.end())       return false;
      if(p1->second > p2->second) return false;
      if(p1->second < p2->second) return true;
      }
   return false;
   }

namespace {

/*
* DER encode a RelativeDistinguishedName
*/
void do_ava(DER_Encoder& encoder,
            const std::multimap<OID, std::string>& dn_info,
            ASN1_Tag string_type, const std::string& oid_str,
            bool must_exist = false)
   {
   typedef std::multimap<OID, std::string>::const_iterator rdn_iter;

   const OID oid = OIDS::lookup(oid_str);
   const bool exists = (dn_info.find(oid) != dn_info.end());

   if(!exists && must_exist)
      throw Encoding_Error("X509_DN: No entry for " + oid_str);
   if(!exists) return;

   std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);

   for(rdn_iter j = range.first; j != range.second; ++j)
      {
      encoder.start_cons(SET)
         .start_cons(SEQUENCE)
            .encode(oid)
            .encode(ASN1_String(j->second, string_type))
         .end_cons()
      .end_cons();
      }
   }

}

/*
* DER encode a DistinguishedName
*/
void X509_DN::encode_into(DER_Encoder& der) const
   {
   std::multimap<OID, std::string> dn_info = get_attributes();

   der.start_cons(SEQUENCE);

   if(!dn_bits.empty())
      der.raw_bytes(dn_bits);
   else
      {
      do_ava(der, dn_info, PRINTABLE_STRING, "X520.Country");
      do_ava(der, dn_info, DIRECTORY_STRING, "X520.State");
      do_ava(der, dn_info, DIRECTORY_STRING, "X520.Locality");
      do_ava(der, dn_info, DIRECTORY_STRING, "X520.Organization");
      do_ava(der, dn_info, DIRECTORY_STRING, "X520.OrganizationalUnit");
      do_ava(der, dn_info, DIRECTORY_STRING, "X520.CommonName");
      do_ava(der, dn_info, PRINTABLE_STRING, "X520.SerialNumber");
      }

   der.end_cons();
   }

/*
* Decode a BER encoded DistinguishedName
*/
void X509_DN::decode_from(BER_Decoder& source)
   {
   MemoryVector<byte> bits;

   source.start_cons(SEQUENCE)
      .raw_bytes(bits)
   .end_cons();

   BER_Decoder sequence(bits);

   while(sequence.more_items())
      {
      BER_Decoder rdn = sequence.start_cons(SET);

      while(rdn.more_items())
         {
         OID oid;
         ASN1_String str;

         rdn.start_cons(SEQUENCE)
            .decode(oid)
            .decode(str)
            .verify_end()
        .end_cons();

         add_attribute(oid, str.value());
         }
      }

   dn_bits = bits;
   }

}
/*
* Runtime benchmarking
* (C) 2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

/**
* Benchmark Buffered_Computation (hash or MAC)
*/
std::pair<u64bit, u64bit> bench_buf_comp(Buffered_Computation* buf_comp,
                                         u64bit nanoseconds_max,
                                         const byte buf[], size_t buf_len)
   {
   u64bit reps = 0;
   u64bit nanoseconds_used = 0;

   while(nanoseconds_used < nanoseconds_max)
      {
      const u64bit start = get_nanoseconds_clock();
      buf_comp->update(buf, buf_len);
      nanoseconds_used += get_nanoseconds_clock() - start;

      ++reps;
      }

   return std::make_pair(reps * buf_len, nanoseconds_used);
   }

/**
* Benchmark block cipher
*/
std::pair<u64bit, u64bit>
bench_block_cipher(BlockCipher* block_cipher,
                   u64bit nanoseconds_max,
                   byte buf[], size_t buf_len)
   {
   const size_t in_blocks = buf_len / block_cipher->block_size();

   u64bit reps = 0;
   u64bit nanoseconds_used = 0;

   block_cipher->set_key(buf, block_cipher->maximum_keylength());

   while(nanoseconds_used < nanoseconds_max)
      {
      const u64bit start = get_nanoseconds_clock();
      block_cipher->encrypt_n(buf, buf, in_blocks);
      nanoseconds_used += get_nanoseconds_clock() - start;

      ++reps;
      }

   return std::make_pair(reps * in_blocks * block_cipher->block_size(),
                         nanoseconds_used);
   }

/**
* Benchmark stream
*/
std::pair<u64bit, u64bit>
bench_stream_cipher(StreamCipher* stream_cipher,
                    u64bit nanoseconds_max,
                    byte buf[], size_t buf_len)
   {
   u64bit reps = 0;
   u64bit nanoseconds_used = 0;

   stream_cipher->set_key(buf, stream_cipher->maximum_keylength());

   while(nanoseconds_used < nanoseconds_max)
      {
      const u64bit start = get_nanoseconds_clock();
      stream_cipher->cipher1(buf, buf_len);
      nanoseconds_used += get_nanoseconds_clock() - start;

      ++reps;
      }

   return std::make_pair(reps * buf_len, nanoseconds_used);
   }

/**
* Benchmark hash
*/
std::pair<u64bit, u64bit>
bench_hash(HashFunction* hash,
           u64bit nanoseconds_max,
           const byte buf[], size_t buf_len)
   {
   return bench_buf_comp(hash, nanoseconds_max, buf, buf_len);
   }

/**
* Benchmark MAC
*/
std::pair<u64bit, u64bit>
bench_mac(MessageAuthenticationCode* mac,
          u64bit nanoseconds_max,
          const byte buf[], size_t buf_len)
   {
   mac->set_key(buf, mac->maximum_keylength());
   return bench_buf_comp(mac, nanoseconds_max, buf, buf_len);
   }

}

std::map<std::string, double>
algorithm_benchmark(const std::string& name,
                    Algorithm_Factory& af,
                    RandomNumberGenerator& rng,
                    u32bit milliseconds,
                    size_t buf_size)
   {
   std::vector<std::string> providers = af.providers_of(name);
   std::map<std::string, double> all_results;

   if(providers.empty()) // no providers, nothing to do
      return all_results;

   const u64bit ns_per_provider =
      (static_cast<u64bit>(milliseconds) * 1000 * 1000) / providers.size();

   std::vector<byte> buf(buf_size * 1024);
   rng.randomize(&buf[0], buf.size());

   for(size_t i = 0; i != providers.size(); ++i)
      {
      const std::string provider = providers[i];

      std::pair<u64bit, u64bit> results(0, 0);

      if(const BlockCipher* proto =
            af.prototype_block_cipher(name, provider))
         {
         std::auto_ptr<BlockCipher> block_cipher(proto->clone());
         results = bench_block_cipher(block_cipher.get(),
                                      ns_per_provider,
                                      &buf[0], buf.size());
         }
      else if(const StreamCipher* proto =
                 af.prototype_stream_cipher(name, provider))
         {
         std::auto_ptr<StreamCipher> stream_cipher(proto->clone());
         results = bench_stream_cipher(stream_cipher.get(),
                                       ns_per_provider,
                                       &buf[0], buf.size());
         }
      else if(const HashFunction* proto =
                 af.prototype_hash_function(name, provider))
         {
         std::auto_ptr<HashFunction> hash(proto->clone());
         results = bench_hash(hash.get(), ns_per_provider,
                              &buf[0], buf.size());
         }
      else if(const MessageAuthenticationCode* proto =
                 af.prototype_mac(name, provider))
         {
         std::auto_ptr<MessageAuthenticationCode> mac(proto->clone());
         results = bench_mac(mac.get(), ns_per_provider,
                             &buf[0], buf.size());
         }

      if(results.first && results.second)
         {
         /* 953.67 == 1000 * 1000 * 1000 / 1024 / 1024 - the conversion
            factor from bytes per nanosecond to mebibytes per second.
         */
         double speed = (953.67 * results.first) / results.second;
         all_results[provider] = speed;
         }
      }

   return all_results;
   }

}
/*
* AES
* (C) 1999-2010 Jack Lloyd
*
* Based on the public domain reference implemenation
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

const byte SE[256] = {
   0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
   0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
   0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
   0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
   0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
   0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
   0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
   0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
   0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
   0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
   0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
   0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
   0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
   0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
   0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
   0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
   0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
   0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
   0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
   0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
   0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
   0xB0, 0x54, 0xBB, 0x16 };

const byte SD[256] = {
   0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
   0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
   0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
   0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
   0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
   0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
   0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
   0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
   0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
   0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
   0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
   0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
   0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
   0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
   0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
   0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
   0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
   0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
   0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
   0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
   0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
   0x55, 0x21, 0x0C, 0x7D };

const u32bit TE[1024] = {
   0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD,
   0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D,
   0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D,
   0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
   0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7,
   0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A,
   0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4,
   0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
   0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1,
   0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D,
   0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E,
   0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
   0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E,
   0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C,
   0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46,
   0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
   0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7,
   0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81,
   0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE,
   0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
   0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A,
   0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F,
   0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2,
   0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
   0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E,
   0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C,
   0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256,
   0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
   0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4,
   0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7,
   0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA,
   0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
   0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1,
   0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21,
   0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42,
   0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
   0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158,
   0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133,
   0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22,
   0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
   0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631,
   0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11,
   0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, 0xA5C66363, 0x84F87C7C,
   0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5,
   0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7,
   0xE64DABAB, 0x9AEC7676, 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D,
   0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, 0xEC41ADAD, 0x67B3D4D4,
   0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0,
   0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F,
   0x02F5F7F7, 0x4F83CCCC, 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1,
   0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, 0x0C080404, 0x5295C7C7,
   0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A,
   0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727,
   0xCD7FB2B2, 0x9FEA7575, 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A,
   0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, 0xF6A45252, 0x4D763B3B,
   0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484,
   0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC,
   0xC879B1B1, 0xEDB65B5B, 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939,
   0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, 0x6BBBD0D0, 0x2AC5EFEF,
   0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585,
   0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C,
   0xBA259F9F, 0xE34BA8A8, 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F,
   0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, 0xDF63BCBC, 0xC177B6B6,
   0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2,
   0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797,
   0xCC884444, 0x392E1717, 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D,
   0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, 0xA0C06060, 0x98198181,
   0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888,
   0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E,
   0x1D160B0B, 0x76ADDBDB, 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A,
   0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, 0x5D9FC2C2, 0x6EBDD3D3,
   0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979,
   0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5,
   0xD29C4E4E, 0xE049A9A9, 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA,
   0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, 0xD56FBABA, 0x88F07878,
   0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6,
   0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD,
   0x860D8B8B, 0x850F8A8A, 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666,
   0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, 0xA3C26161, 0x5F6A3535,
   0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E,
   0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9,
   0x89078E8E, 0xA7339494, 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9,
   0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, 0x8F038C8C, 0xF859A1A1,
   0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868,
   0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454,
   0xD66DBBBB, 0x3A2C1616, 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B,
   0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, 0x30506030, 0x01030201,
   0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76,
   0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259,
   0x47C98E47, 0xF00BFBF0, 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF,
   0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, 0xB7C275B7, 0xFD1CE1FD,
   0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC,
   0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8,
   0x31536231, 0x153F2A15, 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3,
   0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, 0x07090E07, 0x12362412,
   0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75,
   0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E,
   0x5AEEB45A, 0xA0FB5BA0, 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3,
   0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, 0x53F5A653, 0xD168B9D1,
   0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B,
   0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C,
   0x58E8B058, 0xCF4A85CF, 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB,
   0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, 0x45CF8A45, 0xF910E9F9,
   0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8,
   0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D,
   0x38487038, 0xF504F1F5, 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221,
   0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, 0xCD4C81CD, 0x0C14180C,
   0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17,
   0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D,
   0x192B3219, 0x7395E673, 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC,
   0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, 0x46CA8C46, 0xEE29C7EE,
   0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB,
   0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06,
   0x246C4824, 0x5CE4B85C, 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462,
   0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, 0xE732D5E7, 0xC8438BC8,
   0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9,
   0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A,
   0xAEE947AE, 0x08181008, 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E,
   0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, 0xE823CBE8, 0xDD7CA1DD,
   0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A,
   0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603,
   0xF601F7F6, 0x0E121C0E, 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9,
   0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, 0xE138D9E1, 0xF813EBF8,
   0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394,
   0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55,
   0x28785028, 0xDF7AA5DF, 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D,
   0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, 0x41C38241, 0x99B02999,
   0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16,
   0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6,
   0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56,
   0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F,
   0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
   0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753,
   0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C,
   0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451,
   0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
   0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137,
   0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF,
   0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D,
   0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
   0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD,
   0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1,
   0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D,
   0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
   0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A,
   0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE,
   0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D,
   0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
   0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5,
   0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3,
   0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255,
   0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
   0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54,
   0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28,
   0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664,
   0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
   0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431,
   0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA,
   0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC,
   0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
   0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157,
   0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E,
   0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C,
   0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
   0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899,
   0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322,
   0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C,
   0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
   0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7,
   0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E,
   0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C };

const u32bit TD[1024] = {
   0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1,
   0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25,
   0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67,
   0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6,
   0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3,
   0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD,
   0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182,
   0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94,
   0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2,
   0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5,
   0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492,
   0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A,
   0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA,
   0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46,
   0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997,
   0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB,
   0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48,
   0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927,
   0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F,
   0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16,
   0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD,
   0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD,
   0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC,
   0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120,
   0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3,
   0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422,
   0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1,
   0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4,
   0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8,
   0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3,
   0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4,
   0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6,
   0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331,
   0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815,
   0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D,
   0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F,
   0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252,
   0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89,
   0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F,
   0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86,
   0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C,
   0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190,
   0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742, 0x5051F4A7, 0x537E4165,
   0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303,
   0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB,
   0x80263544, 0x8FB562A3, 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0,
   0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, 0xE7038F5F, 0x9515929C,
   0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8,
   0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD,
   0x66C920AC, 0xB47DCE3A, 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F,
   0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, 0x58704868, 0x198F45FD,
   0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB,
   0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5,
   0xBA02036A, 0x5CED1682, 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2,
   0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, 0x9D342E53, 0xA0A2F355,
   0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10,
   0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D,
   0x6F0406D4, 0xFF605015, 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E,
   0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, 0x47A17C0A, 0xE97C420F,
   0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72,
   0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6,
   0xD19B5B54, 0x3A24362E, 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91,
   0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, 0x0AE293BA, 0xE5C0A02A,
   0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9,
   0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5,
   0xC544663B, 0x345BFB7E, 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1,
   0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, 0x7D854A24, 0xF8D2BB3D,
   0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3,
   0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F,
   0xD8567D2C, 0xEF223390, 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B,
   0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, 0xE42C3A9D, 0x0D507892,
   0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF,
   0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D,
   0x6EE89C63, 0x7BDB3BBB, 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A,
   0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, 0xD9BAE79B, 0xCE4A6F36,
   0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266,
   0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA,
   0x0E7FCD50, 0x2F1791F6, 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604,
   0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, 0x049D5EEA, 0x5D018C35,
   0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647,
   0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9,
   0xEDE11CE5, 0x3C7A47B1, 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737,
   0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, 0x81CAAFF3, 0x3EB968C4,
   0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95,
   0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6,
   0x74486C5C, 0x42D0B857, 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27,
   0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, 0xFA552030, 0x6DF6AD76,
   0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562,
   0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C,
   0x97A38D46, 0xF9C66BD3, 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552,
   0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, 0x896A75C2, 0x7978F48E,
   0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE,
   0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B,
   0xA01CFE81, 0x2B94F908, 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B,
   0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, 0x2807B2EB, 0xC2032FB5,
   0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16,
   0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605,
   0x621FD134, 0xFE8AC4A6, 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6,
   0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, 0x8AF93E21, 0x063D96DD,
   0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050,
   0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789,
   0x5B38E719, 0xEEDB79C8, 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000,
   0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, 0xFFFBFD0E, 0x38560F85,
   0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436,
   0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC,
   0x4B695A77, 0x1A161C12, 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B,
   0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, 0x198557F1, 0x074CAF75,
   0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB,
   0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263,
   0x22401397, 0x112084C6, 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729,
   0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, 0x166C2BB3, 0xB999A970,
   0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233,
   0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A,
   0x8E26DAB7, 0xBFA43FAD, 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E,
   0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, 0x80BE9F5D, 0x937C69D0,
   0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B,
   0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF,
   0xCF0821BC, 0xE8E6EF15, 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0,
   0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, 0xBC37744E, 0xCAA6FC82,
   0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791,
   0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A,
   0x1FB8C12C, 0x517F4665, 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B,
   0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, 0x618C9AD7, 0x0C7A37A1,
   0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47,
   0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD,
   0x6F14DF3D, 0xDB867844, 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3,
   0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, 0x017139A8, 0xB3DE080C,
   0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8,
   0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F,
   0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5,
   0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725,
   0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
   0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358,
   0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27,
   0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5,
   0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
   0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272,
   0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3,
   0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7,
   0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
   0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40,
   0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D,
   0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6,
   0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
   0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832,
   0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736,
   0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93,
   0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
   0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2,
   0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3,
   0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB,
   0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
   0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC,
   0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247,
   0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9,
   0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
   0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890,
   0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF,
   0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E,
   0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
   0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A,
   0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533,
   0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43,
   0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
   0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292,
   0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB,
   0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55,
   0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
   0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC,
   0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064,
   0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 };

/*
* AES Encryption
*/
void aes_encrypt_n(const byte in[], byte out[],
                   size_t blocks,
                   const MemoryRegion<u32bit>& EK,
                   const MemoryRegion<byte>& ME)
   {
   const size_t BLOCK_SIZE = 16;

   const u32bit* TE0 = TE;
   const u32bit* TE1 = TE + 256;
   const u32bit* TE2 = TE + 512;
   const u32bit* TE3 = TE + 768;

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit T0 = load_be<u32bit>(in, 0) ^ EK[0];
      u32bit T1 = load_be<u32bit>(in, 1) ^ EK[1];
      u32bit T2 = load_be<u32bit>(in, 2) ^ EK[2];
      u32bit T3 = load_be<u32bit>(in, 3) ^ EK[3];

      /* Use only the first 256 entries of the TE table and do the
      * rotations directly in the code. This reduces the number of
      * cache lines potentially used in the first round from 64 to 16
      * (assuming a typical 64 byte cache line), which makes timing
      * attacks a little harder; the first round is particularly
      * vulnerable.
      */

      u32bit B0 = TE[get_byte(0, T0)] ^
                  rotate_right(TE[get_byte(1, T1)],  8) ^
                  rotate_right(TE[get_byte(2, T2)], 16) ^
                  rotate_right(TE[get_byte(3, T3)], 24) ^ EK[4];

      u32bit B1 = TE[get_byte(0, T1)] ^
                  rotate_right(TE[get_byte(1, T2)],  8) ^
                  rotate_right(TE[get_byte(2, T3)], 16) ^
                  rotate_right(TE[get_byte(3, T0)], 24) ^ EK[5];

      u32bit B2 = TE[get_byte(0, T2)] ^
                  rotate_right(TE[get_byte(1, T3)],  8) ^
                  rotate_right(TE[get_byte(2, T0)], 16) ^
                  rotate_right(TE[get_byte(3, T1)], 24) ^ EK[6];

      u32bit B3 = TE[get_byte(0, T3)] ^
                  rotate_right(TE[get_byte(1, T0)],  8) ^
                  rotate_right(TE[get_byte(2, T1)], 16) ^
                  rotate_right(TE[get_byte(3, T2)], 24) ^ EK[7];

      for(size_t r = 2*4; r < EK.size(); r += 2*4)
         {
         T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(1, B1)] ^
              TE2[get_byte(2, B2)] ^ TE3[get_byte(3, B3)] ^ EK[r];
         T1 = TE0[get_byte(0, B1)] ^ TE1[get_byte(1, B2)] ^
              TE2[get_byte(2, B3)] ^ TE3[get_byte(3, B0)] ^ EK[r+1];
         T2 = TE0[get_byte(0, B2)] ^ TE1[get_byte(1, B3)] ^
              TE2[get_byte(2, B0)] ^ TE3[get_byte(3, B1)] ^ EK[r+2];
         T3 = TE0[get_byte(0, B3)] ^ TE1[get_byte(1, B0)] ^
              TE2[get_byte(2, B1)] ^ TE3[get_byte(3, B2)] ^ EK[r+3];

         B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(1, T1)] ^
              TE2[get_byte(2, T2)] ^ TE3[get_byte(3, T3)] ^ EK[r+4];
         B1 = TE0[get_byte(0, T1)] ^ TE1[get_byte(1, T2)] ^
              TE2[get_byte(2, T3)] ^ TE3[get_byte(3, T0)] ^ EK[r+5];
         B2 = TE0[get_byte(0, T2)] ^ TE1[get_byte(1, T3)] ^
              TE2[get_byte(2, T0)] ^ TE3[get_byte(3, T1)] ^ EK[r+6];
         B3 = TE0[get_byte(0, T3)] ^ TE1[get_byte(1, T0)] ^
              TE2[get_byte(2, T1)] ^ TE3[get_byte(3, T2)] ^ EK[r+7];
         }

      /*
      Joseph Bonneau and Ilya Mironov's paper "Cache-Collision Timing
      Attacks Against AES" describes an attack that can recover AES
      keys with as few as 2**13 samples.

      http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753

      They recommend using a byte-wide table, which still allows an attack
      but increases the samples required from 2**13 to 2**25:

      """In addition to OpenSSL v. 0.9.8.(a), which was used in our
      experiments, the AES implementations of Crypto++ 5.2.1 and
      LibTomCrypt 1.09 use the original Rijndael C implementation with
      very few changes and are highly vulnerable. The AES implementations
      in libgcrypt v. 1.2.2 and Botan v. 1.4.2 are also vulnerable, but
      use a smaller byte-wide final table which lessens the effectiveness
      of the attacks."""
      */

      out[ 0] = SE[get_byte(0, B0)] ^ ME[0];
      out[ 1] = SE[get_byte(1, B1)] ^ ME[1];
      out[ 2] = SE[get_byte(2, B2)] ^ ME[2];
      out[ 3] = SE[get_byte(3, B3)] ^ ME[3];
      out[ 4] = SE[get_byte(0, B1)] ^ ME[4];
      out[ 5] = SE[get_byte(1, B2)] ^ ME[5];
      out[ 6] = SE[get_byte(2, B3)] ^ ME[6];
      out[ 7] = SE[get_byte(3, B0)] ^ ME[7];
      out[ 8] = SE[get_byte(0, B2)] ^ ME[8];
      out[ 9] = SE[get_byte(1, B3)] ^ ME[9];
      out[10] = SE[get_byte(2, B0)] ^ ME[10];
      out[11] = SE[get_byte(3, B1)] ^ ME[11];
      out[12] = SE[get_byte(0, B3)] ^ ME[12];
      out[13] = SE[get_byte(1, B0)] ^ ME[13];
      out[14] = SE[get_byte(2, B1)] ^ ME[14];
      out[15] = SE[get_byte(3, B2)] ^ ME[15];

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* AES Decryption
*/
void aes_decrypt_n(const byte in[], byte out[], size_t blocks,
                   const MemoryRegion<u32bit>& DK,
                   const MemoryRegion<byte>& MD)
   {
   const size_t BLOCK_SIZE = 16;

   const u32bit* TD0 = TD;
   const u32bit* TD1 = TD + 256;
   const u32bit* TD2 = TD + 512;
   const u32bit* TD3 = TD + 768;

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit T0 = load_be<u32bit>(in, 0) ^ DK[0];
      u32bit T1 = load_be<u32bit>(in, 1) ^ DK[1];
      u32bit T2 = load_be<u32bit>(in, 2) ^ DK[2];
      u32bit T3 = load_be<u32bit>(in, 3) ^ DK[3];

      u32bit B0 = TD[get_byte(0, T0)] ^
                  rotate_right(TD[get_byte(1, T3)],  8) ^
                  rotate_right(TD[get_byte(2, T2)], 16) ^
                  rotate_right(TD[get_byte(3, T1)], 24) ^ DK[4];

      u32bit B1 = TD[get_byte(0, T1)] ^
                  rotate_right(TD[get_byte(1, T0)],  8) ^
                  rotate_right(TD[get_byte(2, T3)], 16) ^
                  rotate_right(TD[get_byte(3, T2)], 24) ^ DK[5];

      u32bit B2 = TD[get_byte(0, T2)] ^
                  rotate_right(TD[get_byte(1, T1)],  8) ^
                  rotate_right(TD[get_byte(2, T0)], 16) ^
                  rotate_right(TD[get_byte(3, T3)], 24) ^ DK[6];

      u32bit B3 = TD[get_byte(0, T3)] ^
                  rotate_right(TD[get_byte(1, T2)],  8) ^
                  rotate_right(TD[get_byte(2, T1)], 16) ^
                  rotate_right(TD[get_byte(3, T0)], 24) ^ DK[7];

      for(size_t r = 2*4; r < DK.size(); r += 2*4)
         {
         T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(1, B3)] ^
              TD2[get_byte(2, B2)] ^ TD3[get_byte(3, B1)] ^ DK[r];
         T1 = TD0[get_byte(0, B1)] ^ TD1[get_byte(1, B0)] ^
              TD2[get_byte(2, B3)] ^ TD3[get_byte(3, B2)] ^ DK[r+1];
         T2 = TD0[get_byte(0, B2)] ^ TD1[get_byte(1, B1)] ^
              TD2[get_byte(2, B0)] ^ TD3[get_byte(3, B3)] ^ DK[r+2];
         T3 = TD0[get_byte(0, B3)] ^ TD1[get_byte(1, B2)] ^
              TD2[get_byte(2, B1)] ^ TD3[get_byte(3, B0)] ^ DK[r+3];

         B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(1, T3)] ^
              TD2[get_byte(2, T2)] ^ TD3[get_byte(3, T1)] ^ DK[r+4];
         B1 = TD0[get_byte(0, T1)] ^ TD1[get_byte(1, T0)] ^
              TD2[get_byte(2, T3)] ^ TD3[get_byte(3, T2)] ^ DK[r+5];
         B2 = TD0[get_byte(0, T2)] ^ TD1[get_byte(1, T1)] ^
              TD2[get_byte(2, T0)] ^ TD3[get_byte(3, T3)] ^ DK[r+6];
         B3 = TD0[get_byte(0, T3)] ^ TD1[get_byte(1, T2)] ^
              TD2[get_byte(2, T1)] ^ TD3[get_byte(3, T0)] ^ DK[r+7];
         }

      out[ 0] = SD[get_byte(0, B0)] ^ MD[0];
      out[ 1] = SD[get_byte(1, B3)] ^ MD[1];
      out[ 2] = SD[get_byte(2, B2)] ^ MD[2];
      out[ 3] = SD[get_byte(3, B1)] ^ MD[3];
      out[ 4] = SD[get_byte(0, B1)] ^ MD[4];
      out[ 5] = SD[get_byte(1, B0)] ^ MD[5];
      out[ 6] = SD[get_byte(2, B3)] ^ MD[6];
      out[ 7] = SD[get_byte(3, B2)] ^ MD[7];
      out[ 8] = SD[get_byte(0, B2)] ^ MD[8];
      out[ 9] = SD[get_byte(1, B1)] ^ MD[9];
      out[10] = SD[get_byte(2, B0)] ^ MD[10];
      out[11] = SD[get_byte(3, B3)] ^ MD[11];
      out[12] = SD[get_byte(0, B3)] ^ MD[12];
      out[13] = SD[get_byte(1, B2)] ^ MD[13];
      out[14] = SD[get_byte(2, B1)] ^ MD[14];
      out[15] = SD[get_byte(3, B0)] ^ MD[15];

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

void aes_key_schedule(const byte key[], size_t length,
                      MemoryRegion<u32bit>& EK,
                      MemoryRegion<u32bit>& DK,
                      MemoryRegion<byte>& ME,
                      MemoryRegion<byte>& MD)
   {
   static const u32bit RC[10] = {
      0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
      0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 };

   const size_t rounds = (length / 4) + 6;

   SecureVector<u32bit> XEK(length + 32), XDK(length + 32);

   const size_t X = length / 4;
   for(size_t i = 0; i != X; ++i)
      XEK[i] = load_be<u32bit>(key, i);

   for(size_t i = X; i < 4*(rounds+1); i += X)
      {
      XEK[i] = XEK[i-X] ^ RC[(i-X)/X] ^
               make_u32bit(SE[get_byte(1, XEK[i-1])],
                           SE[get_byte(2, XEK[i-1])],
                           SE[get_byte(3, XEK[i-1])],
                           SE[get_byte(0, XEK[i-1])]);

      for(size_t j = 1; j != X; ++j)
         {
         XEK[i+j] = XEK[i+j-X];

         if(X == 8 && j == 4)
            XEK[i+j] ^= make_u32bit(SE[get_byte(0, XEK[i+j-1])],
                                    SE[get_byte(1, XEK[i+j-1])],
                                    SE[get_byte(2, XEK[i+j-1])],
                                    SE[get_byte(3, XEK[i+j-1])]);
         else
            XEK[i+j] ^= XEK[i+j-1];
         }
      }

   for(size_t i = 0; i != 4*(rounds+1); i += 4)
      {
      XDK[i  ] = XEK[4*rounds-i  ];
      XDK[i+1] = XEK[4*rounds-i+1];
      XDK[i+2] = XEK[4*rounds-i+2];
      XDK[i+3] = XEK[4*rounds-i+3];
      }

   for(size_t i = 4; i != length + 24; ++i)
      XDK[i] = TD[SE[get_byte(0, XDK[i])] +   0] ^
               TD[SE[get_byte(1, XDK[i])] + 256] ^
               TD[SE[get_byte(2, XDK[i])] + 512] ^
               TD[SE[get_byte(3, XDK[i])] + 768];

   for(size_t i = 0; i != 4; ++i)
      {
      store_be(XEK[i+4*rounds], &ME[4*i]);
      store_be(XEK[i], &MD[4*i]);
      }

   EK.resize(length + 24);
   DK.resize(length + 24);
   copy_mem(&EK[0], &XEK[0], EK.size());
   copy_mem(&DK[0], &XDK[0], DK.size());
   }

}

void AES_128::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_encrypt_n(in, out, blocks, EK, ME);
   }

void AES_128::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_decrypt_n(in, out, blocks, DK, MD);
   }

void AES_128::key_schedule(const byte key[], size_t length)
   {
   aes_key_schedule(key, length, EK, DK, ME, MD);
   }

void AES_128::clear()
   {
   zeroise(EK);
   zeroise(DK);
   zeroise(ME);
   zeroise(MD);
   }

void AES_192::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_encrypt_n(in, out, blocks, EK, ME);
   }

void AES_192::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_decrypt_n(in, out, blocks, DK, MD);
   }

void AES_192::key_schedule(const byte key[], size_t length)
   {
   aes_key_schedule(key, length, EK, DK, ME, MD);
   }

void AES_192::clear()
   {
   zeroise(EK);
   zeroise(DK);
   zeroise(ME);
   zeroise(MD);
   }

void AES_256::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_encrypt_n(in, out, blocks, EK, ME);
   }

void AES_256::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   aes_decrypt_n(in, out, blocks, DK, MD);
   }

void AES_256::key_schedule(const byte key[], size_t length)
   {
   aes_key_schedule(key, length, EK, DK, ME, MD);
   }

void AES_256::clear()
   {
   zeroise(EK);
   zeroise(DK);
   zeroise(ME);
   zeroise(MD);
   }

}
/*
* S-Box and P-Box Tables for Blowfish
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u32bit Blowfish::P_INIT[18] = {
   0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
   0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
   0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B };

const u32bit Blowfish::S_INIT[1024] = {
   0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96,
   0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
   0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658,
   0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
   0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E,
   0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
   0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6,
   0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
   0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C,
   0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
   0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1,
   0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
   0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A,
   0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
   0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176,
   0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
   0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706,
   0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
   0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B,
   0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
   0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C,
   0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
   0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A,
   0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
   0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760,
   0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
   0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8,
   0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
   0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33,
   0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
   0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0,
   0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
   0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777,
   0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
   0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705,
   0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
   0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E,
   0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
   0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9,
   0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
   0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F,
   0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
   0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, 0x4B7A70E9, 0xB5B32944,
   0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
   0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29,
   0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
   0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26,
   0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
   0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C,
   0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
   0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6,
   0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
   0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F,
   0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
   0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810,
   0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
   0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA,
   0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
   0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55,
   0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
   0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1,
   0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
   0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78,
   0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
   0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883,
   0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
   0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170,
   0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
   0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7,
   0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
   0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099,
   0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
   0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263,
   0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
   0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3,
   0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
   0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7,
   0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
   0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D,
   0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
   0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460,
   0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
   0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484,
   0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
   0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A,
   0xE6E39F2B, 0xDB83ADF7, 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
   0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A,
   0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
   0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785,
   0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
   0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900,
   0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
   0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9,
   0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
   0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397,
   0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
   0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9,
   0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
   0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F,
   0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
   0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E,
   0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
   0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD,
   0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
   0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8,
   0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
   0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C,
   0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
   0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B,
   0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
   0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386,
   0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
   0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0,
   0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
   0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2,
   0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
   0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770,
   0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
   0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C,
   0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
   0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA,
   0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
   0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63,
   0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
   0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9,
   0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
   0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4,
   0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0,
   0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742,
   0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
   0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79,
   0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
   0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A,
   0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
   0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1,
   0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
   0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797,
   0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
   0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6,
   0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
   0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA,
   0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
   0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5,
   0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
   0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE,
   0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
   0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD,
   0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
   0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB,
   0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
   0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC,
   0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
   0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC,
   0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
   0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A,
   0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
   0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A,
   0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
   0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B,
   0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
   0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E,
   0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
   0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623,
   0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
   0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A,
   0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
   0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3,
   0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
   0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C,
   0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
   0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 };

}
/*
* Blowfish
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Blowfish Encryption
*/
void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* S1 = &S[0];
   const u32bit* S2 = &S[256];
   const u32bit* S3 = &S[512];
   const u32bit* S4 = &S[768];

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      for(size_t j = 0; j != 16; j += 2)
         {
         L ^= P[j];
         R ^= ((S1[get_byte(0, L)]  + S2[get_byte(1, L)]) ^
                S3[get_byte(2, L)]) + S4[get_byte(3, L)];

         R ^= P[j+1];
         L ^= ((S1[get_byte(0, R)]  + S2[get_byte(1, R)]) ^
                S3[get_byte(2, R)]) + S4[get_byte(3, R)];
         }

      L ^= P[16]; R ^= P[17];

      store_be(out, R, L);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Blowfish Decryption
*/
void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* S1 = &S[0];
   const u32bit* S2 = &S[256];
   const u32bit* S3 = &S[512];
   const u32bit* S4 = &S[768];

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      for(size_t j = 17; j != 1; j -= 2)
         {
         L ^= P[j];
         R ^= ((S1[get_byte(0, L)]  + S2[get_byte(1, L)]) ^
                S3[get_byte(2, L)]) + S4[get_byte(3, L)];

         R ^= P[j-1];
         L ^= ((S1[get_byte(0, R)]  + S2[get_byte(1, R)]) ^
                S3[get_byte(2, R)]) + S4[get_byte(3, R)];
         }

      L ^= P[1]; R ^= P[0];

      store_be(out, R, L);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Blowfish Key Schedule
*/
void Blowfish::key_schedule(const byte key[], size_t length)
   {
   clear();

   const byte null_salt[16] = { 0 };

   key_expansion(key, length, null_salt);
   }

void Blowfish::key_expansion(const byte key[],
                             size_t length,
                             const byte salt[16])
   {
   for(size_t i = 0, j = 0; i != 18; ++i, j += 4)
      P[i] ^= make_u32bit(key[(j  ) % length], key[(j+1) % length],
                          key[(j+2) % length], key[(j+3) % length]);

   u32bit L = 0, R = 0;
   generate_sbox(P, L, R, salt, 0);
   generate_sbox(S, L, R, salt, 2);
   }

/*
* Modified key schedule used for bcrypt password hashing
*/
void Blowfish::eks_key_schedule(const byte key[], size_t length,
                                const byte salt[16], size_t workfactor)
   {
   if(length == 0 || length >= 56)
      throw Invalid_Key_Length("EKSBlowfish", length);

   if(workfactor == 0)
      throw std::invalid_argument("Bcrypt work factor must be at least 1");

   /*
   * On a 2.8 GHz Core-i7, workfactor == 18 takes about 25 seconds to
   * hash a password. This seems like a reasonable upper bound for the
   * time being.
   */
   if(workfactor > 18)
      throw std::invalid_argument("Requested Bcrypt work factor too large");

   clear();

   const byte null_salt[16] = { 0 };

   key_expansion(key, length, salt);

   const size_t rounds = 1 << workfactor;

   for(size_t r = 0; r != rounds; ++r)
      {
      key_expansion(key, length, null_salt);
      key_expansion(salt, 16, null_salt);
      }
   }

/*
* Generate one of the Sboxes
*/
void Blowfish::generate_sbox(MemoryRegion<u32bit>& box,
                             u32bit& L, u32bit& R,
                             const byte salt[16],
                             size_t salt_off) const
   {
   const u32bit* S1 = &S[0];
   const u32bit* S2 = &S[256];
   const u32bit* S3 = &S[512];
   const u32bit* S4 = &S[768];

   for(size_t i = 0; i != box.size(); i += 2)
      {
      L ^= load_be<u32bit>(salt, (i + salt_off) % 4);
      R ^= load_be<u32bit>(salt, (i + salt_off + 1) % 4);

      for(size_t j = 0; j != 16; j += 2)
         {
         L ^= P[j];
         R ^= ((S1[get_byte(0, L)]  + S2[get_byte(1, L)]) ^
                S3[get_byte(2, L)]) + S4[get_byte(3, L)];

         R ^= P[j+1];
         L ^= ((S1[get_byte(0, R)]  + S2[get_byte(1, R)]) ^
                S3[get_byte(2, R)]) + S4[get_byte(3, R)];
         }

      u32bit T = R; R = L ^ P[16]; L = T ^ P[17];
      box[i] = L;
      box[i+1] = R;
      }
   }

/*
* Clear memory of sensitive data
*/
void Blowfish::clear()
   {
   std::copy(P_INIT, P_INIT + 18, P.begin());
   std::copy(S_INIT, S_INIT + 1024, S.begin());
   }

}
/*
* Camellia
* (C) 2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace Camellia_F {

namespace {

/*
* We use the slow byte-wise version of F in the first and last rounds
* to help protect against timing attacks
*/
u64bit F_SLOW(u64bit v, u64bit K)
   {
   static const byte SBOX[256] = {
      0x70, 0x82, 0x2C, 0xEC, 0xB3, 0x27, 0xC0, 0xE5, 0xE4, 0x85, 0x57,
      0x35, 0xEA, 0x0C, 0xAE, 0x41, 0x23, 0xEF, 0x6B, 0x93, 0x45, 0x19,
      0xA5, 0x21, 0xED, 0x0E, 0x4F, 0x4E, 0x1D, 0x65, 0x92, 0xBD, 0x86,
      0xB8, 0xAF, 0x8F, 0x7C, 0xEB, 0x1F, 0xCE, 0x3E, 0x30, 0xDC, 0x5F,
      0x5E, 0xC5, 0x0B, 0x1A, 0xA6, 0xE1, 0x39, 0xCA, 0xD5, 0x47, 0x5D,
      0x3D, 0xD9, 0x01, 0x5A, 0xD6, 0x51, 0x56, 0x6C, 0x4D, 0x8B, 0x0D,
      0x9A, 0x66, 0xFB, 0xCC, 0xB0, 0x2D, 0x74, 0x12, 0x2B, 0x20, 0xF0,
      0xB1, 0x84, 0x99, 0xDF, 0x4C, 0xCB, 0xC2, 0x34, 0x7E, 0x76, 0x05,
      0x6D, 0xB7, 0xA9, 0x31, 0xD1, 0x17, 0x04, 0xD7, 0x14, 0x58, 0x3A,
      0x61, 0xDE, 0x1B, 0x11, 0x1C, 0x32, 0x0F, 0x9C, 0x16, 0x53, 0x18,
      0xF2, 0x22, 0xFE, 0x44, 0xCF, 0xB2, 0xC3, 0xB5, 0x7A, 0x91, 0x24,
      0x08, 0xE8, 0xA8, 0x60, 0xFC, 0x69, 0x50, 0xAA, 0xD0, 0xA0, 0x7D,
      0xA1, 0x89, 0x62, 0x97, 0x54, 0x5B, 0x1E, 0x95, 0xE0, 0xFF, 0x64,
      0xD2, 0x10, 0xC4, 0x00, 0x48, 0xA3, 0xF7, 0x75, 0xDB, 0x8A, 0x03,
      0xE6, 0xDA, 0x09, 0x3F, 0xDD, 0x94, 0x87, 0x5C, 0x83, 0x02, 0xCD,
      0x4A, 0x90, 0x33, 0x73, 0x67, 0xF6, 0xF3, 0x9D, 0x7F, 0xBF, 0xE2,
      0x52, 0x9B, 0xD8, 0x26, 0xC8, 0x37, 0xC6, 0x3B, 0x81, 0x96, 0x6F,
      0x4B, 0x13, 0xBE, 0x63, 0x2E, 0xE9, 0x79, 0xA7, 0x8C, 0x9F, 0x6E,
      0xBC, 0x8E, 0x29, 0xF5, 0xF9, 0xB6, 0x2F, 0xFD, 0xB4, 0x59, 0x78,
      0x98, 0x06, 0x6A, 0xE7, 0x46, 0x71, 0xBA, 0xD4, 0x25, 0xAB, 0x42,
      0x88, 0xA2, 0x8D, 0xFA, 0x72, 0x07, 0xB9, 0x55, 0xF8, 0xEE, 0xAC,
      0x0A, 0x36, 0x49, 0x2A, 0x68, 0x3C, 0x38, 0xF1, 0xA4, 0x40, 0x28,
      0xD3, 0x7B, 0xBB, 0xC9, 0x43, 0xC1, 0x15, 0xE3, 0xAD, 0xF4, 0x77,
      0xC7, 0x80, 0x9E };

   const u64bit x = v ^ K;

   const byte t1 = SBOX[get_byte(0, x)];
   const byte t2 = rotate_left(SBOX[get_byte(1, x)], 1);
   const byte t3 = rotate_left(SBOX[get_byte(2, x)], 7);
   const byte t4 = SBOX[rotate_left(get_byte(3, x), 1)];
   const byte t5 = rotate_left(SBOX[get_byte(4, x)], 1);
   const byte t6 = rotate_left(SBOX[get_byte(5, x)], 7);
   const byte t7 = SBOX[rotate_left(get_byte(6, x), 1)];
   const byte t8 = SBOX[get_byte(7, x)];

   const byte y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8;
   const byte y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8;
   const byte y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8;
   const byte y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7;
   const byte y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8;
   const byte y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8;
   const byte y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8;
   const byte y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7;

   return make_u64bit(y1, y2, y3, y4, y5, y6, y7, y8);
   }

inline u64bit F(u64bit v, u64bit K)
   {
   const u64bit x = v ^ K;

   return Camellia_SBOX1[get_byte(0, x)] ^
          Camellia_SBOX2[get_byte(1, x)] ^
          Camellia_SBOX3[get_byte(2, x)] ^
          Camellia_SBOX4[get_byte(3, x)] ^
          Camellia_SBOX5[get_byte(4, x)] ^
          Camellia_SBOX6[get_byte(5, x)] ^
          Camellia_SBOX7[get_byte(6, x)] ^
          Camellia_SBOX8[get_byte(7, x)];
   }

inline u64bit FL(u64bit v, u64bit K)
   {
   u32bit x1 = (v >> 32);
   u32bit x2 = (v & 0xFFFFFFFF);

   const u32bit k1 = (K >> 32);
   const u32bit k2 = (K & 0xFFFFFFFF);

   x2 ^= rotate_left(x1 & k1, 1);
   x1 ^= (x2 | k2);

   return ((static_cast<u64bit>(x1) << 32) | x2);
   }

inline u64bit FLINV(u64bit v, u64bit K)
   {
   u32bit x1 = (v >> 32);
   u32bit x2 = (v & 0xFFFFFFFF);

   const u32bit k1 = (K >> 32);
   const u32bit k2 = (K & 0xFFFFFFFF);

   x1 ^= (x2 | k2);
   x2 ^= rotate_left(x1 & k1, 1);

   return ((static_cast<u64bit>(x1) << 32) | x2);
   }

/*
* Camellia Encryption
*/
void encrypt(const byte in[], byte out[], size_t blocks,
             const SecureVector<u64bit>& SK, const size_t rounds)
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit D1 = load_be<u64bit>(in, 0);
      u64bit D2 = load_be<u64bit>(in, 1);

      const u64bit* K = &SK[0];

      D1 ^= *K++;
      D2 ^= *K++;

      D2 ^= F_SLOW(D1, *K++);
      D1 ^= F_SLOW(D2, *K++);

      for(size_t r = 1; r != rounds - 1; ++r)
         {
         if(r % 3 == 0)
            {
            D1 = FL   (D1, *K++);
            D2 = FLINV(D2, *K++);
            }

         D2 ^= F(D1, *K++);
         D1 ^= F(D2, *K++);
         }

      D2 ^= F_SLOW(D1, *K++);
      D1 ^= F_SLOW(D2, *K++);

      D2 ^= *K++;
      D1 ^= *K++;

      store_be(out, D2, D1);

      in += 16;
      out += 16;
      }
   }

/*
* Camellia Decryption
*/
void decrypt(const byte in[], byte out[], size_t blocks,
             const SecureVector<u64bit>& SK, const size_t rounds)
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit D1 = load_be<u64bit>(in, 0);
      u64bit D2 = load_be<u64bit>(in, 1);

      const u64bit* K = &SK[SK.size()-1];

      D2 ^= *K--;
      D1 ^= *K--;

      D2 ^= F_SLOW(D1, *K--);
      D1 ^= F_SLOW(D2, *K--);

      for(size_t r = 1; r != rounds - 1; ++r)
         {
         if(r % 3 == 0)
            {
            D1 = FL   (D1, *K--);
            D2 = FLINV(D2, *K--);
            }

         D2 ^= F(D1, *K--);
         D1 ^= F(D2, *K--);
         }

      D2 ^= F_SLOW(D1, *K--);
      D1 ^= F_SLOW(D2, *K--);

      D1 ^= *K--;
      D2 ^= *K;

      store_be(out, D2, D1);

      in += 16;
      out += 16;
      }
   }

u64bit left_rot_hi(u64bit h, u64bit l, size_t shift)
   {
   return (h << shift) | ((l >> (64-shift)));
   }

u64bit left_rot_lo(u64bit h, u64bit l, size_t shift)
   {
   return (h >> (64-shift)) | (l << shift);
   }

/*
* Camellia Key Schedule
*/
void key_schedule(SecureVector<u64bit>& SK, const byte key[], size_t length)
   {
   const u64bit Sigma1 = 0xA09E667F3BCC908BULL;
   const u64bit Sigma2 = 0xB67AE8584CAA73B2ULL;
   const u64bit Sigma3 = 0xC6EF372FE94F82BEULL;
   const u64bit Sigma4 = 0x54FF53A5F1D36F1CULL;
   const u64bit Sigma5 = 0x10E527FADE682D1DULL;
   const u64bit Sigma6 = 0xB05688C2B3E6C1FDULL;

   const u64bit KL_H = load_be<u64bit>(key, 0);
   const u64bit KL_L = load_be<u64bit>(key, 1);

   const u64bit KR_H = (length >= 24) ? load_be<u64bit>(key, 2) : 0;
   const u64bit KR_L =
      (length == 32) ? load_be<u64bit>(key, 3) : ((length == 24) ? ~KR_H : 0);

   u64bit D1 = KL_H ^ KR_H;
   u64bit D2 = KL_L ^ KR_L;
   D2 ^= F(D1, Sigma1);
   D1 ^= F(D2, Sigma2);
   D1 ^= KL_H;
   D2 ^= KL_L;
   D2 ^= F(D1, Sigma3);
   D1 ^= F(D2, Sigma4);

   const u64bit KA_H = D1;
   const u64bit KA_L = D2;

   D1 = KA_H ^ KR_H;
   D2 = KA_L ^ KR_L;
   D2 ^= F(D1, Sigma5);
   D1 ^= F(D2, Sigma6);

   const u64bit KB_H = D1;
   const u64bit KB_L = D2;

   if(length == 16)
      {
      SK.resize(26);

      SK[ 0] = KL_H;
      SK[ 1] = KL_L;
      SK[ 2] = KA_H;
      SK[ 3] = KA_L;
      SK[ 4] = left_rot_hi(KL_H, KL_L, 15);
      SK[ 5] = left_rot_lo(KL_H, KL_L, 15);
      SK[ 6] = left_rot_hi(KA_H, KA_L, 15);
      SK[ 7] = left_rot_lo(KA_H, KA_L, 15);
      SK[ 8] = left_rot_hi(KA_H, KA_L, 30);
      SK[ 9] = left_rot_lo(KA_H, KA_L, 30);
      SK[10] = left_rot_hi(KL_H, KL_L, 45);
      SK[11] = left_rot_lo(KL_H, KL_L, 45);
      SK[12] = left_rot_hi(KA_H, KA_L,  45);
      SK[13] = left_rot_lo(KL_H, KL_L,  60);
      SK[14] = left_rot_hi(KA_H, KA_L,  60);
      SK[15] = left_rot_lo(KA_H, KA_L,  60);
      SK[16] = left_rot_lo(KL_H, KL_L,  77-64);
      SK[17] = left_rot_hi(KL_H, KL_L,  77-64);
      SK[18] = left_rot_lo(KL_H, KL_L,  94-64);
      SK[19] = left_rot_hi(KL_H, KL_L,  94-64);
      SK[20] = left_rot_lo(KA_H, KA_L,  94-64);
      SK[21] = left_rot_hi(KA_H, KA_L,  94-64);
      SK[22] = left_rot_lo(KL_H, KL_L, 111-64);
      SK[23] = left_rot_hi(KL_H, KL_L, 111-64);
      SK[24] = left_rot_lo(KA_H, KA_L, 111-64);
      SK[25] = left_rot_hi(KA_H, KA_L, 111-64);
      }
   else
      {
      SK.resize(34);

      SK[ 0] = KL_H;
      SK[ 1] = KL_L;
      SK[ 2] = KB_H;
      SK[ 3] = KB_L;

      SK[ 4] = left_rot_hi(KR_H, KR_L, 15);
      SK[ 5] = left_rot_lo(KR_H, KR_L, 15);
      SK[ 6] = left_rot_hi(KA_H, KA_L, 15);
      SK[ 7] = left_rot_lo(KA_H, KA_L, 15);

      SK[ 8] = left_rot_hi(KR_H, KR_L, 30);
      SK[ 9] = left_rot_lo(KR_H, KR_L, 30);
      SK[10] = left_rot_hi(KB_H, KB_L, 30);
      SK[11] = left_rot_lo(KB_H, KB_L, 30);

      SK[12] = left_rot_hi(KL_H, KL_L, 45);
      SK[13] = left_rot_lo(KL_H, KL_L, 45);
      SK[14] = left_rot_hi(KA_H, KA_L, 45);
      SK[15] = left_rot_lo(KA_H, KA_L, 45);

      SK[16] = left_rot_hi(KL_H, KL_L, 60);
      SK[17] = left_rot_lo(KL_H, KL_L, 60);
      SK[18] = left_rot_hi(KR_H, KR_L, 60);
      SK[19] = left_rot_lo(KR_H, KR_L, 60);
      SK[20] = left_rot_hi(KB_H, KB_L, 60);
      SK[21] = left_rot_lo(KB_H, KB_L, 60);

      SK[22] = left_rot_lo(KL_H, KL_L,  77-64);
      SK[23] = left_rot_hi(KL_H, KL_L,  77-64);
      SK[24] = left_rot_lo(KA_H, KA_L,  77-64);
      SK[25] = left_rot_hi(KA_H, KA_L,  77-64);

      SK[26] = left_rot_lo(KR_H, KR_L,  94-64);
      SK[27] = left_rot_hi(KR_H, KR_L,  94-64);
      SK[28] = left_rot_lo(KA_H, KA_L,  94-64);
      SK[29] = left_rot_hi(KA_H, KA_L,  94-64);
      SK[30] = left_rot_lo(KL_H, KL_L, 111-64);
      SK[31] = left_rot_hi(KL_H, KL_L, 111-64);
      SK[32] = left_rot_lo(KB_H, KB_L, 111-64);
      SK[33] = left_rot_hi(KB_H, KB_L, 111-64);
      }
   }

}

}

void Camellia_128::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::encrypt(in, out, blocks, SK, 9);
   }

void Camellia_192::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::encrypt(in, out, blocks, SK, 12);
   }

void Camellia_256::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::encrypt(in, out, blocks, SK, 12);
   }

void Camellia_128::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::decrypt(in, out, blocks, SK, 9);
   }

void Camellia_192::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::decrypt(in, out, blocks, SK, 12);
   }

void Camellia_256::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   Camellia_F::decrypt(in, out, blocks, SK, 12);
   }

void Camellia_128::key_schedule(const byte key[], size_t length)
   {
   Camellia_F::key_schedule(SK, key, length);
   }

void Camellia_192::key_schedule(const byte key[], size_t length)
   {
   Camellia_F::key_schedule(SK, key, length);
   }

void Camellia_256::key_schedule(const byte key[], size_t length)
   {
   Camellia_F::key_schedule(SK, key, length);
   }

}
/*
* Block Cipher Cascade
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

void Cascade_Cipher::encrypt_n(const byte in[], byte out[],
                               size_t blocks) const
   {
   size_t c1_blocks = blocks * (block_size() / cipher1->block_size());
   size_t c2_blocks = blocks * (block_size() / cipher2->block_size());

   cipher1->encrypt_n(in, out, c1_blocks);
   cipher2->encrypt_n(out, out, c2_blocks);
   }

void Cascade_Cipher::decrypt_n(const byte in[], byte out[],
                               size_t blocks) const
   {
   size_t c1_blocks = blocks * (block_size() / cipher1->block_size());
   size_t c2_blocks = blocks * (block_size() / cipher2->block_size());

   cipher2->decrypt_n(in, out, c2_blocks);
   cipher1->decrypt_n(out, out, c1_blocks);
   }

void Cascade_Cipher::key_schedule(const byte key[], size_t)
   {
   const byte* key2 = key + cipher1->maximum_keylength();

   cipher1->set_key(key , cipher1->maximum_keylength());
   cipher2->set_key(key2, cipher2->maximum_keylength());
   }

void Cascade_Cipher::clear()
   {
   cipher1->clear();
   cipher2->clear();
   }

std::string Cascade_Cipher::name() const
   {
   return "Cascade(" + cipher1->name() + "," + cipher2->name() + ")";
   }

BlockCipher* Cascade_Cipher::clone() const
   {
   return new Cascade_Cipher(cipher1->clone(),
                             cipher2->clone());
   }

namespace {

size_t euclids_algorithm(size_t a, size_t b)
   {
   while(b != 0) // gcd
      {
      size_t t = b;
      b = a % b;
      a = t;
      }

   return a;
   }

size_t block_size_for_cascade(size_t bs, size_t bs2)
   {
   if(bs == bs2)
      return bs;

   size_t gcd = euclids_algorithm(bs, bs2);

   return (bs * bs2) / gcd;
   }

}

Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) :
   cipher1(c1), cipher2(c2)
   {
   block = block_size_for_cascade(c1->block_size(), c2->block_size());

   if(block_size() % c1->block_size() || block_size() % c2->block_size())
      throw Internal_Error("Failure in " + name() + " constructor");
   }

Cascade_Cipher::~Cascade_Cipher()
   {
   delete cipher1;
   delete cipher2;
   }

}
/*
* CAST-128
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* CAST-128 Round Type 1
*/
inline void R1(u32bit& L, u32bit R, u32bit MK, u32bit RK)
   {
   u32bit T = rotate_left(MK + R, RK);
   L ^= (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) -
         CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)];
   }

/*
* CAST-128 Round Type 2
*/
inline void R2(u32bit& L, u32bit R, u32bit MK, u32bit RK)
   {
   u32bit T = rotate_left(MK ^ R, RK);
   L ^= (CAST_SBOX1[get_byte(0, T)]  - CAST_SBOX2[get_byte(1, T)] +
         CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)];
   }

/*
* CAST-128 Round Type 3
*/
inline void R3(u32bit& L, u32bit R, u32bit MK, u32bit RK)
   {
   u32bit T = rotate_left(MK - R, RK);
   L ^= ((CAST_SBOX1[get_byte(0, T)]  + CAST_SBOX2[get_byte(1, T)]) ^
          CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)];
   }

}

/*
* CAST-128 Encryption
*/
void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      R1(L, R, MK[ 0], RK[ 0]);
      R2(R, L, MK[ 1], RK[ 1]);
      R3(L, R, MK[ 2], RK[ 2]);
      R1(R, L, MK[ 3], RK[ 3]);
      R2(L, R, MK[ 4], RK[ 4]);
      R3(R, L, MK[ 5], RK[ 5]);
      R1(L, R, MK[ 6], RK[ 6]);
      R2(R, L, MK[ 7], RK[ 7]);
      R3(L, R, MK[ 8], RK[ 8]);
      R1(R, L, MK[ 9], RK[ 9]);
      R2(L, R, MK[10], RK[10]);
      R3(R, L, MK[11], RK[11]);
      R1(L, R, MK[12], RK[12]);
      R2(R, L, MK[13], RK[13]);
      R3(L, R, MK[14], RK[14]);
      R1(R, L, MK[15], RK[15]);

      store_be(out, R, L);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* CAST-128 Decryption
*/
void CAST_128::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      R1(L, R, MK[15], RK[15]);
      R3(R, L, MK[14], RK[14]);
      R2(L, R, MK[13], RK[13]);
      R1(R, L, MK[12], RK[12]);
      R3(L, R, MK[11], RK[11]);
      R2(R, L, MK[10], RK[10]);
      R1(L, R, MK[ 9], RK[ 9]);
      R3(R, L, MK[ 8], RK[ 8]);
      R2(L, R, MK[ 7], RK[ 7]);
      R1(R, L, MK[ 6], RK[ 6]);
      R3(L, R, MK[ 5], RK[ 5]);
      R2(R, L, MK[ 4], RK[ 4]);
      R1(L, R, MK[ 3], RK[ 3]);
      R3(R, L, MK[ 2], RK[ 2]);
      R2(L, R, MK[ 1], RK[ 1]);
      R1(R, L, MK[ 0], RK[ 0]);

      store_be(out, R, L);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* CAST-128 Key Schedule
*/
void CAST_128::key_schedule(const byte key[], size_t length)
   {
   clear();
   SecureVector<u32bit> X(4);
   for(size_t j = 0; j != length; ++j)
      X[j/4] = (X[j/4] << 8) + key[j];

   cast_ks(MK, X);
   cast_ks(RK, X);

   for(size_t j = 0; j != 16; ++j)
      RK[j] %= 32;
   }

/*
* S-Box Based Key Expansion
*/
void CAST_128::cast_ks(MemoryRegion<u32bit>& K,
                       MemoryRegion<u32bit>& X)
   {
   class ByteReader
      {
      public:
         byte operator()(size_t i) { return (X[i/4] >> (8*(3 - (i%4)))); }
         ByteReader(const u32bit* x) : X(x) {}
      private:
         const u32bit* X;
      };

   SecureVector<u32bit> Z(4);
   ByteReader x(&X[0]), z(&Z[0]);

   Z[0]  = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)];
   Z[1]  = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)];
   Z[2]  = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)];
   Z[3]  = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)];
   K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)];
   K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)];
   K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)];
   K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)];
   X[0]  = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)];
   X[1]  = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)];
   X[2]  = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)];
   X[3]  = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)];
   K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)];
   K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)];
   K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)];
   K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)];
   Z[0]  = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)];
   Z[1]  = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)];
   Z[2]  = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)];
   Z[3]  = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)];
   K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)];
   K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)];
   K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)];
   K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)];
   X[0]  = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)];
   X[1]  = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)];
   X[2]  = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)];
   X[3]  = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)];
   K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)];
   K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)];
   K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)];
   K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)];
   }

}
/*
* CAST-256
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* CAST-256 Round Type 1
*/
void round1(u32bit& out, u32bit in, u32bit mask, u32bit rot)
   {
   u32bit temp = rotate_left(mask + in, rot);
   out  ^= (CAST_SBOX1[get_byte(0, temp)] ^ CAST_SBOX2[get_byte(1, temp)]) -
            CAST_SBOX3[get_byte(2, temp)] + CAST_SBOX4[get_byte(3, temp)];
   }

/*
* CAST-256 Round Type 2
*/
void round2(u32bit& out, u32bit in, u32bit mask, u32bit rot)
   {
   u32bit temp = rotate_left(mask ^ in, rot);
   out  ^= (CAST_SBOX1[get_byte(0, temp)]  - CAST_SBOX2[get_byte(1, temp)] +
            CAST_SBOX3[get_byte(2, temp)]) ^ CAST_SBOX4[get_byte(3, temp)];
   }

/*
* CAST-256 Round Type 3
*/
void round3(u32bit& out, u32bit in, u32bit mask, u32bit rot)
   {
   u32bit temp = rotate_left(mask - in, rot);
   out  ^= ((CAST_SBOX1[get_byte(0, temp)]  + CAST_SBOX2[get_byte(1, temp)]) ^
             CAST_SBOX3[get_byte(2, temp)]) - CAST_SBOX4[get_byte(3, temp)];
   }

}

/*
* CAST-256 Encryption
*/
void CAST_256::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_be<u32bit>(in, 0);
      u32bit B = load_be<u32bit>(in, 1);
      u32bit C = load_be<u32bit>(in, 2);
      u32bit D = load_be<u32bit>(in, 3);

      round1(C, D, MK[ 0], RK[ 0]); round2(B, C, MK[ 1], RK[ 1]);
      round3(A, B, MK[ 2], RK[ 2]); round1(D, A, MK[ 3], RK[ 3]);
      round1(C, D, MK[ 4], RK[ 4]); round2(B, C, MK[ 5], RK[ 5]);
      round3(A, B, MK[ 6], RK[ 6]); round1(D, A, MK[ 7], RK[ 7]);
      round1(C, D, MK[ 8], RK[ 8]); round2(B, C, MK[ 9], RK[ 9]);
      round3(A, B, MK[10], RK[10]); round1(D, A, MK[11], RK[11]);
      round1(C, D, MK[12], RK[12]); round2(B, C, MK[13], RK[13]);
      round3(A, B, MK[14], RK[14]); round1(D, A, MK[15], RK[15]);
      round1(C, D, MK[16], RK[16]); round2(B, C, MK[17], RK[17]);
      round3(A, B, MK[18], RK[18]); round1(D, A, MK[19], RK[19]);
      round1(C, D, MK[20], RK[20]); round2(B, C, MK[21], RK[21]);
      round3(A, B, MK[22], RK[22]); round1(D, A, MK[23], RK[23]);
      round1(D, A, MK[27], RK[27]); round3(A, B, MK[26], RK[26]);
      round2(B, C, MK[25], RK[25]); round1(C, D, MK[24], RK[24]);
      round1(D, A, MK[31], RK[31]); round3(A, B, MK[30], RK[30]);
      round2(B, C, MK[29], RK[29]); round1(C, D, MK[28], RK[28]);
      round1(D, A, MK[35], RK[35]); round3(A, B, MK[34], RK[34]);
      round2(B, C, MK[33], RK[33]); round1(C, D, MK[32], RK[32]);
      round1(D, A, MK[39], RK[39]); round3(A, B, MK[38], RK[38]);
      round2(B, C, MK[37], RK[37]); round1(C, D, MK[36], RK[36]);
      round1(D, A, MK[43], RK[43]); round3(A, B, MK[42], RK[42]);
      round2(B, C, MK[41], RK[41]); round1(C, D, MK[40], RK[40]);
      round1(D, A, MK[47], RK[47]); round3(A, B, MK[46], RK[46]);
      round2(B, C, MK[45], RK[45]); round1(C, D, MK[44], RK[44]);

      store_be(out, A, B, C, D);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* CAST-256 Decryption
*/
void CAST_256::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_be<u32bit>(in, 0);
      u32bit B = load_be<u32bit>(in, 1);
      u32bit C = load_be<u32bit>(in, 2);
      u32bit D = load_be<u32bit>(in, 3);

      round1(C, D, MK[44], RK[44]); round2(B, C, MK[45], RK[45]);
      round3(A, B, MK[46], RK[46]); round1(D, A, MK[47], RK[47]);
      round1(C, D, MK[40], RK[40]); round2(B, C, MK[41], RK[41]);
      round3(A, B, MK[42], RK[42]); round1(D, A, MK[43], RK[43]);
      round1(C, D, MK[36], RK[36]); round2(B, C, MK[37], RK[37]);
      round3(A, B, MK[38], RK[38]); round1(D, A, MK[39], RK[39]);
      round1(C, D, MK[32], RK[32]); round2(B, C, MK[33], RK[33]);
      round3(A, B, MK[34], RK[34]); round1(D, A, MK[35], RK[35]);
      round1(C, D, MK[28], RK[28]); round2(B, C, MK[29], RK[29]);
      round3(A, B, MK[30], RK[30]); round1(D, A, MK[31], RK[31]);
      round1(C, D, MK[24], RK[24]); round2(B, C, MK[25], RK[25]);
      round3(A, B, MK[26], RK[26]); round1(D, A, MK[27], RK[27]);
      round1(D, A, MK[23], RK[23]); round3(A, B, MK[22], RK[22]);
      round2(B, C, MK[21], RK[21]); round1(C, D, MK[20], RK[20]);
      round1(D, A, MK[19], RK[19]); round3(A, B, MK[18], RK[18]);
      round2(B, C, MK[17], RK[17]); round1(C, D, MK[16], RK[16]);
      round1(D, A, MK[15], RK[15]); round3(A, B, MK[14], RK[14]);
      round2(B, C, MK[13], RK[13]); round1(C, D, MK[12], RK[12]);
      round1(D, A, MK[11], RK[11]); round3(A, B, MK[10], RK[10]);
      round2(B, C, MK[ 9], RK[ 9]); round1(C, D, MK[ 8], RK[ 8]);
      round1(D, A, MK[ 7], RK[ 7]); round3(A, B, MK[ 6], RK[ 6]);
      round2(B, C, MK[ 5], RK[ 5]); round1(C, D, MK[ 4], RK[ 4]);
      round1(D, A, MK[ 3], RK[ 3]); round3(A, B, MK[ 2], RK[ 2]);
      round2(B, C, MK[ 1], RK[ 1]); round1(C, D, MK[ 0], RK[ 0]);

      store_be(out, A, B, C, D);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* CAST-256 Key Schedule
*/
void CAST_256::key_schedule(const byte key[], size_t length)
   {
   SecureVector<u32bit> K(8);
   for(size_t j = 0; j != length; ++j)
      K[j/4] = (K[j/4] << 8) + key[j];

   u32bit A = K[0], B = K[1], C = K[2], D = K[3],
          E = K[4], F = K[5], G = K[6], H = K[7];

   for(size_t j = 0; j != 48; j += 4)
      {
      round1(G, H, KEY_MASK[4*j+ 0], KEY_ROT[(4*j+ 0) % 32]);
      round2(F, G, KEY_MASK[4*j+ 1], KEY_ROT[(4*j+ 1) % 32]);
      round3(E, F, KEY_MASK[4*j+ 2], KEY_ROT[(4*j+ 2) % 32]);
      round1(D, E, KEY_MASK[4*j+ 3], KEY_ROT[(4*j+ 3) % 32]);
      round2(C, D, KEY_MASK[4*j+ 4], KEY_ROT[(4*j+ 4) % 32]);
      round3(B, C, KEY_MASK[4*j+ 5], KEY_ROT[(4*j+ 5) % 32]);
      round1(A, B, KEY_MASK[4*j+ 6], KEY_ROT[(4*j+ 6) % 32]);
      round2(H, A, KEY_MASK[4*j+ 7], KEY_ROT[(4*j+ 7) % 32]);
      round1(G, H, KEY_MASK[4*j+ 8], KEY_ROT[(4*j+ 8) % 32]);
      round2(F, G, KEY_MASK[4*j+ 9], KEY_ROT[(4*j+ 9) % 32]);
      round3(E, F, KEY_MASK[4*j+10], KEY_ROT[(4*j+10) % 32]);
      round1(D, E, KEY_MASK[4*j+11], KEY_ROT[(4*j+11) % 32]);
      round2(C, D, KEY_MASK[4*j+12], KEY_ROT[(4*j+12) % 32]);
      round3(B, C, KEY_MASK[4*j+13], KEY_ROT[(4*j+13) % 32]);
      round1(A, B, KEY_MASK[4*j+14], KEY_ROT[(4*j+14) % 32]);
      round2(H, A, KEY_MASK[4*j+15], KEY_ROT[(4*j+15) % 32]);

      RK[j  ] = (A % 32);
      RK[j+1] = (C % 32);
      RK[j+2] = (E % 32);
      RK[j+3] = (G % 32);
      MK[j  ] = H;
      MK[j+1] = F;
      MK[j+2] = D;
      MK[j+3] = B;
      }
   }

}
/*
* S-Box Tables for CAST-128 and CAST-256
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u32bit CAST_SBOX1[256] = {
   0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3,
   0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675,
   0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059,
   0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D,
   0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B,
   0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE,
   0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159,
   0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935,
   0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F,
   0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165,
   0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38,
   0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE,
   0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493,
   0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A,
   0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB,
   0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291,
   0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14,
   0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6,
   0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8,
   0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511,
   0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495,
   0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E,
   0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426,
   0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324,
   0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98,
   0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F,
   0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD,
   0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D,
   0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464,
   0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A,
   0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153,
   0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D,
   0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274,
   0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755,
   0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1,
   0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9,
   0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1,
   0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79,
   0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C,
   0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E,
   0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF,
   0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D,
   0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF };

const u32bit CAST_SBOX2[256] = {
   0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A,
   0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA,
   0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605,
   0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB,
   0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B,
   0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4,
   0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083,
   0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359,
   0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F,
   0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D,
   0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E,
   0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34,
   0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366,
   0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4,
   0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064,
   0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860,
   0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6,
   0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709,
   0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364,
   0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B,
   0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B,
   0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9,
   0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C,
   0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13,
   0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741,
   0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB,
   0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B,
   0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6,
   0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA,
   0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8,
   0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028,
   0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D,
   0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6,
   0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B,
   0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1,
   0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6,
   0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB,
   0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA,
   0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D,
   0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA,
   0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E,
   0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF,
   0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 };

const u32bit CAST_SBOX3[256] = {
   0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B,
   0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE,
   0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9,
   0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E,
   0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD,
   0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E,
   0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264,
   0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B,
   0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E,
   0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F,
   0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E,
   0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82,
   0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790,
   0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504,
   0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E,
   0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176,
   0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8,
   0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D,
   0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240,
   0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341,
   0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C,
   0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15,
   0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788,
   0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F,
   0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA,
   0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392,
   0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F,
   0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B,
   0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE,
   0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67,
   0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9,
   0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536,
   0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888,
   0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D,
   0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2,
   0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69,
   0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2,
   0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE,
   0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D,
   0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D,
   0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00,
   0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5,
   0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 };

const u32bit CAST_SBOX4[256] = {
   0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57,
   0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120,
   0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD,
   0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15,
   0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE,
   0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701,
   0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801,
   0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5,
   0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1,
   0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746,
   0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3,
   0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D,
   0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C,
   0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C,
   0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16,
   0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003,
   0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7,
   0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327,
   0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002,
   0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24,
   0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7,
   0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031,
   0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF,
   0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF,
   0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035,
   0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69,
   0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC,
   0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7,
   0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E,
   0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3,
   0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6,
   0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2,
   0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F,
   0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091,
   0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6,
   0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF,
   0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2,
   0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367,
   0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA,
   0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04,
   0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6,
   0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E,
   0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 };

const u32bit CAST_128::S5[256] = {
   0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5,
   0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00,
   0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD,
   0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF,
   0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB,
   0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725,
   0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040,
   0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7,
   0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2,
   0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC,
   0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399,
   0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774,
   0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966,
   0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468,
   0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9,
   0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910,
   0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616,
   0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4,
   0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419,
   0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049,
   0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9,
   0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6,
   0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C,
   0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE,
   0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715,
   0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6,
   0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D,
   0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4,
   0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA,
   0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487,
   0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4,
   0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5,
   0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C,
   0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78,
   0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87,
   0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801,
   0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110,
   0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58,
   0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3,
   0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20,
   0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D,
   0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55,
   0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 };

const u32bit CAST_128::S6[256] = {
   0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4,
   0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9,
   0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD,
   0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367,
   0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F,
   0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C,
   0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0,
   0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3,
   0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941,
   0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D,
   0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223,
   0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9,
   0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6,
   0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A,
   0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7,
   0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC,
   0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89,
   0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE,
   0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0,
   0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F,
   0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4,
   0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853,
   0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87,
   0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F,
   0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585,
   0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751,
   0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75,
   0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13,
   0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283,
   0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459,
   0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF,
   0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891,
   0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0,
   0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB,
   0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200,
   0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084,
   0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF,
   0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B,
   0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869,
   0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5,
   0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB,
   0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454,
   0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F };

const u32bit CAST_128::S7[256] = {
   0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912,
   0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82,
   0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9,
   0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43,
   0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4,
   0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9,
   0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE,
   0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516,
   0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7,
   0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E,
   0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E,
   0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756,
   0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9,
   0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B,
   0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3,
   0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688,
   0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C,
   0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802,
   0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778,
   0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7,
   0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE,
   0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858,
   0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310,
   0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A,
   0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476,
   0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF,
   0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70,
   0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962,
   0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A,
   0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07,
   0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C,
   0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C,
   0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E,
   0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378,
   0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E,
   0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE,
   0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301,
   0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2,
   0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4,
   0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914,
   0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021,
   0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA,
   0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 };

const u32bit CAST_128::S8[256] = {
   0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B,
   0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174,
   0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C,
   0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD,
   0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7,
   0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164,
   0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D,
   0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862,
   0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8,
   0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6,
   0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04,
   0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E,
   0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38,
   0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8,
   0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354,
   0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42,
   0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160,
   0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB,
   0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2,
   0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225,
   0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98,
   0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441,
   0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4,
   0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054,
   0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5,
   0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C,
   0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5,
   0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C,
   0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B,
   0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4,
   0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084,
   0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101,
   0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A,
   0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF,
   0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77,
   0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A,
   0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F,
   0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819,
   0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3,
   0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C,
   0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1,
   0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D,
   0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E };

const u32bit CAST_256::KEY_MASK[192] = {
   0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE,
   0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984,
   0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A,
   0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510,
   0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6,
   0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C,
   0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662,
   0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28,
   0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE,
   0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4,
   0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A,
   0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340,
   0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906,
   0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC,
   0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492,
   0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58,
   0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E,
   0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4,
   0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA,
   0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170,
   0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736,
   0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC,
   0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2,
   0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888,
   0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E,
   0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414,
   0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA,
   0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0,
   0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566,
   0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C,
   0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2,
   0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 };

const byte CAST_256::KEY_ROT[32] = {
   0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C, 0x1D, 0x0E,
   0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16, 0x07, 0x18, 0x09, 0x1A,
   0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00, 0x11, 0x02 };

}
/*
* DES
* (C) 1999-2008 Jack Lloyd
*
* Based on a public domain implemenation by Phil Karn (who in turn
* credited Richard Outerbridge and Jim Gillogly)
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* DES Key Schedule
*/
void des_key_schedule(u32bit round_key[32], const byte key[8])
   {
   static const byte ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2,
                                 1, 2, 2, 2, 2, 2, 2, 1 };

   u32bit C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) |
              ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) |
              ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) |
              ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) |
              ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) |
              ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) |
              ((key[3] & 0x40) <<  9) | ((key[2] & 0x40) <<  8) |
              ((key[1] & 0x40) <<  7) | ((key[0] & 0x40) <<  6) |
              ((key[7] & 0x20) <<  6) | ((key[6] & 0x20) <<  5) |
              ((key[5] & 0x20) <<  4) | ((key[4] & 0x20) <<  3) |
              ((key[3] & 0x20) <<  2) | ((key[2] & 0x20) <<  1) |
              ((key[1] & 0x20)      ) | ((key[0] & 0x20) >>  1) |
              ((key[7] & 0x10) >>  1) | ((key[6] & 0x10) >>  2) |
              ((key[5] & 0x10) >>  3) | ((key[4] & 0x10) >>  4);
   u32bit D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) |
              ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) |
              ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) |
              ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) |
              ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) |
              ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) |
              ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) |
              ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) |
              ((key[7] & 0x08) <<  8) | ((key[6] & 0x08) <<  7) |
              ((key[5] & 0x08) <<  6) | ((key[4] & 0x08) <<  5) |
              ((key[3] & 0x08) <<  4) | ((key[2] & 0x08) <<  3) |
              ((key[1] & 0x08) <<  2) | ((key[0] & 0x08) <<  1) |
              ((key[3] & 0x10) >>  1) | ((key[2] & 0x10) >>  2) |
              ((key[1] & 0x10) >>  3) | ((key[0] & 0x10) >>  4);

   for(size_t i = 0; i != 16; ++i)
      {
      C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF;
      D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF;
      round_key[2*i  ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) |
                         ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) |
                         ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) |
                         ((C & 0x01000000) >>  6) | ((C & 0x00100000) >>  4) |
                         ((C & 0x00010000) <<  3) | ((C & 0x08000000) >>  2) |
                         ((C & 0x00800000) <<  1) | ((D & 0x00000010) <<  8) |
                         ((D & 0x00000002) <<  7) | ((D & 0x00000001) <<  2) |
                         ((D & 0x00000200)      ) | ((D & 0x00008000) >>  2) |
                         ((D & 0x00000088) >>  3) | ((D & 0x00001000) >>  7) |
                         ((D & 0x00080000) >>  9) | ((D & 0x02020000) >> 14) |
                         ((D & 0x00400000) >> 21);
      round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) |
                         ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) |
                         ((C & 0x00001000) <<  9) | ((C & 0x00040000) <<  6) |
                         ((C & 0x02400000) <<  4) | ((C & 0x00008000) <<  2) |
                         ((C & 0x00200000) >>  1) | ((C & 0x04000000) >> 10) |
                         ((D & 0x00000020) <<  6) | ((D & 0x00000100)      ) |
                         ((D & 0x00000800) >>  1) | ((D & 0x00000040) >>  3) |
                         ((D & 0x00010000) >>  4) | ((D & 0x00000400) >>  5) |
                         ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) |
                         ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) |
                         ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26);
      }
   }

/*
* DES Encryption
*/
void des_encrypt(u32bit& L, u32bit& R,
                 const u32bit round_key[32])
   {
   for(size_t i = 0; i != 16; i += 2)
      {
      u32bit T0, T1;

      T0 = rotate_right(R, 4) ^ round_key[2*i];
      T1 =              R     ^ round_key[2*i + 1];

      L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^
           DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^
           DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^
           DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)];

      T0 = rotate_right(L, 4) ^ round_key[2*i + 2];
      T1 =              L     ^ round_key[2*i + 3];

      R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^
           DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^
           DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^
           DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)];
      }
   }

/*
* DES Decryption
*/
void des_decrypt(u32bit& L, u32bit& R,
                 const u32bit round_key[32])
   {
   for(size_t i = 16; i != 0; i -= 2)
      {
      u32bit T0, T1;

      T0 = rotate_right(R, 4) ^ round_key[2*i - 2];
      T1 =              R     ^ round_key[2*i - 1];

      L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^
           DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^
           DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^
           DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)];

      T0 = rotate_right(L, 4) ^ round_key[2*i - 4];
      T1 =              L     ^ round_key[2*i - 3];

      R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^
           DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^
           DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^
           DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)];
      }
   }

}

/*
* DES Encryption
*/
void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit T = (DES_IPTAB1[in[0]]     ) | (DES_IPTAB1[in[1]] << 1) |
                 (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) |
                 (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) |
                 (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]]     );

      u32bit L = static_cast<u32bit>(T >> 32);
      u32bit R = static_cast<u32bit>(T);

      des_encrypt(L, R, &round_key[0]);

      T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) |
          (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) |
          (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) |
          (DES_FPTAB1[get_byte(2, R)]     ) | (DES_FPTAB2[get_byte(3, R)]     );
      T = rotate_left(T, 32);

      store_be(T, out);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* DES Decryption
*/
void DES::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit T = (DES_IPTAB1[in[0]]     ) | (DES_IPTAB1[in[1]] << 1) |
                 (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) |
                 (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) |
                 (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]]     );

      u32bit L = static_cast<u32bit>(T >> 32);
      u32bit R = static_cast<u32bit>(T);

      des_decrypt(L, R, &round_key[0]);

      T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) |
          (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) |
          (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) |
          (DES_FPTAB1[get_byte(2, R)]     ) | (DES_FPTAB2[get_byte(3, R)]     );

      T = rotate_left(T, 32);

      store_be(T, out);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* DES Key Schedule
*/
void DES::key_schedule(const byte key[], size_t)
   {
   des_key_schedule(&round_key[0], key);
   }

/*
* TripleDES Encryption
*/
void TripleDES::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit T = (DES_IPTAB1[in[0]]     ) | (DES_IPTAB1[in[1]] << 1) |
                 (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) |
                 (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) |
                 (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]]     );

      u32bit L = static_cast<u32bit>(T >> 32);
      u32bit R = static_cast<u32bit>(T);

      des_encrypt(L, R, &round_key[0]);
      des_decrypt(R, L, &round_key[32]);
      des_encrypt(L, R, &round_key[64]);

      T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) |
          (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) |
          (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) |
          (DES_FPTAB1[get_byte(2, R)]     ) | (DES_FPTAB2[get_byte(3, R)]     );

      T = rotate_left(T, 32);

      store_be(T, out);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* TripleDES Decryption
*/
void TripleDES::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit T = (DES_IPTAB1[in[0]]     ) | (DES_IPTAB1[in[1]] << 1) |
                 (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) |
                 (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) |
                 (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]]     );

      u32bit L = static_cast<u32bit>(T >> 32);
      u32bit R = static_cast<u32bit>(T);

      des_decrypt(L, R, &round_key[64]);
      des_encrypt(R, L, &round_key[32]);
      des_decrypt(L, R, &round_key[0]);

      T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) |
          (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) |
          (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) |
          (DES_FPTAB1[get_byte(2, R)]     ) | (DES_FPTAB2[get_byte(3, R)]     );

      T = rotate_left(T, 32);

      store_be(T, out);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* TripleDES Key Schedule
*/
void TripleDES::key_schedule(const byte key[], size_t length)
   {
   des_key_schedule(&round_key[0], key);
   des_key_schedule(&round_key[32], key + 8);

   if(length == 24)
      des_key_schedule(&round_key[64], key + 16);
   else
      copy_mem(&round_key[64], &round_key[0], 32);
   }

}
/*
* Substitution/Permutation Tables for DES
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u32bit DES_SPBOX1[256] = {
   0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404,
   0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400,
   0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400,
   0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
   0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404,
   0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000,
   0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000,
   0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
   0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404,
   0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000,
   0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000,
   0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000,
   0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004,
   0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400,
   0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004,
   0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000,
   0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000,
   0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004,
   0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004,
   0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400,
   0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400,
   0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404,
   0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400,
   0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
   0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000,
   0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004,
   0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404,
   0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400,
   0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004,
   0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404,
   0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400,
   0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004,
   0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404,
   0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400,
   0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400,
   0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
   0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404,
   0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000,
   0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000,
   0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
   0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404,
   0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000,
   0x00010004, 0x00010400, 0x00000000, 0x01010004 };

const u32bit DES_SPBOX2[256] = {
   0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020,
   0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000,
   0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020,
   0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
   0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000,
   0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000,
   0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000,
   0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
   0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020,
   0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020,
   0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000,
   0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020,
   0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000,
   0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000,
   0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020,
   0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020,
   0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000,
   0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020,
   0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000,
   0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020,
   0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020,
   0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020,
   0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020,
   0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
   0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000,
   0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000,
   0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020,
   0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000,
   0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020,
   0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020,
   0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000,
   0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000,
   0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020,
   0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000,
   0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020,
   0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
   0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000,
   0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000,
   0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000,
   0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
   0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020,
   0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020,
   0x80000000, 0x80100020, 0x80108020, 0x00108000 };

const u32bit DES_SPBOX3[256] = {
   0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000,
   0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000,
   0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008,
   0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
   0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208,
   0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208,
   0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008,
   0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
   0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208,
   0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000,
   0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200,
   0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200,
   0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008,
   0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200,
   0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200,
   0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000,
   0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200,
   0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200,
   0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000,
   0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008,
   0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008,
   0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008,
   0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008,
   0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
   0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000,
   0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208,
   0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000,
   0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000,
   0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200,
   0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208,
   0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208,
   0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200,
   0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000,
   0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000,
   0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008,
   0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
   0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208,
   0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208,
   0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008,
   0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
   0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208,
   0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000,
   0x00020208, 0x00000008, 0x08020008, 0x00020200 };

const u32bit DES_SPBOX4[256] = {
   0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081,
   0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081,
   0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000,
   0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
   0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080,
   0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081,
   0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080,
   0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
   0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001,
   0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001,
   0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081,
   0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001,
   0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000,
   0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001,
   0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001,
   0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081,
   0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000,
   0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001,
   0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081,
   0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081,
   0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000,
   0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
   0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000,
   0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
   0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000,
   0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080,
   0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001,
   0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000,
   0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081,
   0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000,
   0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080,
   0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080,
   0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081,
   0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081,
   0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000,
   0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
   0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080,
   0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081,
   0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080,
   0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
   0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001,
   0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001,
   0x00000080, 0x00800000, 0x00002000, 0x00802080 };

const u32bit DES_SPBOX5[256] = {
   0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100,
   0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100,
   0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000,
   0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
   0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000,
   0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000,
   0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000,
   0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
   0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000,
   0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000,
   0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100,
   0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000,
   0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000,
   0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000,
   0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100,
   0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100,
   0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000,
   0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100,
   0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100,
   0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000,
   0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000,
   0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100,
   0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000,
   0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
   0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100,
   0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000,
   0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100,
   0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100,
   0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100,
   0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100,
   0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100,
   0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100,
   0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100,
   0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100,
   0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000,
   0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
   0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000,
   0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000,
   0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000,
   0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
   0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000,
   0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000,
   0x00000000, 0x40080000, 0x02080100, 0x40000100 };

const u32bit DES_SPBOX6[256] = {
   0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010,
   0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010,
   0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010,
   0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
   0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000,
   0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000,
   0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000,
   0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
   0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000,
   0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000,
   0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000,
   0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000,
   0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000,
   0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000,
   0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000,
   0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000,
   0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000,
   0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010,
   0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000,
   0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010,
   0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000,
   0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010,
   0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010,
   0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
   0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010,
   0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000,
   0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010,
   0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010,
   0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010,
   0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010,
   0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010,
   0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010,
   0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010,
   0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010,
   0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010,
   0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
   0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000,
   0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000,
   0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000,
   0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
   0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000,
   0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000,
   0x20404000, 0x20000000, 0x00400010, 0x20004010 };

const u32bit DES_SPBOX7[256] = {
   0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802,
   0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002,
   0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802,
   0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
   0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002,
   0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802,
   0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000,
   0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
   0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000,
   0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800,
   0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002,
   0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800,
   0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000,
   0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800,
   0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800,
   0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800,
   0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002,
   0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000,
   0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002,
   0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802,
   0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800,
   0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000,
   0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000,
   0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
   0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000,
   0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802,
   0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800,
   0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002,
   0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802,
   0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000,
   0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802,
   0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002,
   0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802,
   0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002,
   0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802,
   0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
   0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002,
   0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802,
   0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000,
   0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
   0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000,
   0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800,
   0x04000002, 0x04000800, 0x00000800, 0x00200002 };

const u32bit DES_SPBOX8[256] = {
   0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040,
   0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000,
   0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040,
   0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
   0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000,
   0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000,
   0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040,
   0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
   0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000,
   0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040,
   0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000,
   0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000,
   0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040,
   0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040,
   0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000,
   0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000,
   0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040,
   0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000,
   0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040,
   0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000,
   0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040,
   0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040,
   0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000,
   0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
   0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040,
   0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040,
   0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000,
   0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040,
   0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000,
   0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040,
   0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000,
   0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000,
   0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040,
   0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000,
   0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040,
   0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
   0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000,
   0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000,
   0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040,
   0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
   0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000,
   0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040,
   0x00001040, 0x00040040, 0x10000000, 0x10041000 };

const u64bit DES_IPTAB1[256] = {
0x0000000000000000ULL, 0x0000000200000000ULL, 0x0000000000000002ULL, 0x0000000200000002ULL,
0x0000020000000000ULL, 0x0000020200000000ULL, 0x0000020000000002ULL, 0x0000020200000002ULL,
0x0000000000000200ULL, 0x0000000200000200ULL, 0x0000000000000202ULL, 0x0000000200000202ULL,
0x0000020000000200ULL, 0x0000020200000200ULL, 0x0000020000000202ULL, 0x0000020200000202ULL,
0x0002000000000000ULL, 0x0002000200000000ULL, 0x0002000000000002ULL, 0x0002000200000002ULL,
0x0002020000000000ULL, 0x0002020200000000ULL, 0x0002020000000002ULL, 0x0002020200000002ULL,
0x0002000000000200ULL, 0x0002000200000200ULL, 0x0002000000000202ULL, 0x0002000200000202ULL,
0x0002020000000200ULL, 0x0002020200000200ULL, 0x0002020000000202ULL, 0x0002020200000202ULL,
0x0000000000020000ULL, 0x0000000200020000ULL, 0x0000000000020002ULL, 0x0000000200020002ULL,
0x0000020000020000ULL, 0x0000020200020000ULL, 0x0000020000020002ULL, 0x0000020200020002ULL,
0x0000000000020200ULL, 0x0000000200020200ULL, 0x0000000000020202ULL, 0x0000000200020202ULL,
0x0000020000020200ULL, 0x0000020200020200ULL, 0x0000020000020202ULL, 0x0000020200020202ULL,
0x0002000000020000ULL, 0x0002000200020000ULL, 0x0002000000020002ULL, 0x0002000200020002ULL,
0x0002020000020000ULL, 0x0002020200020000ULL, 0x0002020000020002ULL, 0x0002020200020002ULL,
0x0002000000020200ULL, 0x0002000200020200ULL, 0x0002000000020202ULL, 0x0002000200020202ULL,
0x0002020000020200ULL, 0x0002020200020200ULL, 0x0002020000020202ULL, 0x0002020200020202ULL,
0x0200000000000000ULL, 0x0200000200000000ULL, 0x0200000000000002ULL, 0x0200000200000002ULL,
0x0200020000000000ULL, 0x0200020200000000ULL, 0x0200020000000002ULL, 0x0200020200000002ULL,
0x0200000000000200ULL, 0x0200000200000200ULL, 0x0200000000000202ULL, 0x0200000200000202ULL,
0x0200020000000200ULL, 0x0200020200000200ULL, 0x0200020000000202ULL, 0x0200020200000202ULL,
0x0202000000000000ULL, 0x0202000200000000ULL, 0x0202000000000002ULL, 0x0202000200000002ULL,
0x0202020000000000ULL, 0x0202020200000000ULL, 0x0202020000000002ULL, 0x0202020200000002ULL,
0x0202000000000200ULL, 0x0202000200000200ULL, 0x0202000000000202ULL, 0x0202000200000202ULL,
0x0202020000000200ULL, 0x0202020200000200ULL, 0x0202020000000202ULL, 0x0202020200000202ULL,
0x0200000000020000ULL, 0x0200000200020000ULL, 0x0200000000020002ULL, 0x0200000200020002ULL,
0x0200020000020000ULL, 0x0200020200020000ULL, 0x0200020000020002ULL, 0x0200020200020002ULL,
0x0200000000020200ULL, 0x0200000200020200ULL, 0x0200000000020202ULL, 0x0200000200020202ULL,
0x0200020000020200ULL, 0x0200020200020200ULL, 0x0200020000020202ULL, 0x0200020200020202ULL,
0x0202000000020000ULL, 0x0202000200020000ULL, 0x0202000000020002ULL, 0x0202000200020002ULL,
0x0202020000020000ULL, 0x0202020200020000ULL, 0x0202020000020002ULL, 0x0202020200020002ULL,
0x0202000000020200ULL, 0x0202000200020200ULL, 0x0202000000020202ULL, 0x0202000200020202ULL,
0x0202020000020200ULL, 0x0202020200020200ULL, 0x0202020000020202ULL, 0x0202020200020202ULL,
0x0000000002000000ULL, 0x0000000202000000ULL, 0x0000000002000002ULL, 0x0000000202000002ULL,
0x0000020002000000ULL, 0x0000020202000000ULL, 0x0000020002000002ULL, 0x0000020202000002ULL,
0x0000000002000200ULL, 0x0000000202000200ULL, 0x0000000002000202ULL, 0x0000000202000202ULL,
0x0000020002000200ULL, 0x0000020202000200ULL, 0x0000020002000202ULL, 0x0000020202000202ULL,
0x0002000002000000ULL, 0x0002000202000000ULL, 0x0002000002000002ULL, 0x0002000202000002ULL,
0x0002020002000000ULL, 0x0002020202000000ULL, 0x0002020002000002ULL, 0x0002020202000002ULL,
0x0002000002000200ULL, 0x0002000202000200ULL, 0x0002000002000202ULL, 0x0002000202000202ULL,
0x0002020002000200ULL, 0x0002020202000200ULL, 0x0002020002000202ULL, 0x0002020202000202ULL,
0x0000000002020000ULL, 0x0000000202020000ULL, 0x0000000002020002ULL, 0x0000000202020002ULL,
0x0000020002020000ULL, 0x0000020202020000ULL, 0x0000020002020002ULL, 0x0000020202020002ULL,
0x0000000002020200ULL, 0x0000000202020200ULL, 0x0000000002020202ULL, 0x0000000202020202ULL,
0x0000020002020200ULL, 0x0000020202020200ULL, 0x0000020002020202ULL, 0x0000020202020202ULL,
0x0002000002020000ULL, 0x0002000202020000ULL, 0x0002000002020002ULL, 0x0002000202020002ULL,
0x0002020002020000ULL, 0x0002020202020000ULL, 0x0002020002020002ULL, 0x0002020202020002ULL,
0x0002000002020200ULL, 0x0002000202020200ULL, 0x0002000002020202ULL, 0x0002000202020202ULL,
0x0002020002020200ULL, 0x0002020202020200ULL, 0x0002020002020202ULL, 0x0002020202020202ULL,
0x0200000002000000ULL, 0x0200000202000000ULL, 0x0200000002000002ULL, 0x0200000202000002ULL,
0x0200020002000000ULL, 0x0200020202000000ULL, 0x0200020002000002ULL, 0x0200020202000002ULL,
0x0200000002000200ULL, 0x0200000202000200ULL, 0x0200000002000202ULL, 0x0200000202000202ULL,
0x0200020002000200ULL, 0x0200020202000200ULL, 0x0200020002000202ULL, 0x0200020202000202ULL,
0x0202000002000000ULL, 0x0202000202000000ULL, 0x0202000002000002ULL, 0x0202000202000002ULL,
0x0202020002000000ULL, 0x0202020202000000ULL, 0x0202020002000002ULL, 0x0202020202000002ULL,
0x0202000002000200ULL, 0x0202000202000200ULL, 0x0202000002000202ULL, 0x0202000202000202ULL,
0x0202020002000200ULL, 0x0202020202000200ULL, 0x0202020002000202ULL, 0x0202020202000202ULL,
0x0200000002020000ULL, 0x0200000202020000ULL, 0x0200000002020002ULL, 0x0200000202020002ULL,
0x0200020002020000ULL, 0x0200020202020000ULL, 0x0200020002020002ULL, 0x0200020202020002ULL,
0x0200000002020200ULL, 0x0200000202020200ULL, 0x0200000002020202ULL, 0x0200000202020202ULL,
0x0200020002020200ULL, 0x0200020202020200ULL, 0x0200020002020202ULL, 0x0200020202020202ULL,
0x0202000002020000ULL, 0x0202000202020000ULL, 0x0202000002020002ULL, 0x0202000202020002ULL,
0x0202020002020000ULL, 0x0202020202020000ULL, 0x0202020002020002ULL, 0x0202020202020002ULL,
0x0202000002020200ULL, 0x0202000202020200ULL, 0x0202000002020202ULL, 0x0202000202020202ULL,
0x0202020002020200ULL, 0x0202020202020200ULL, 0x0202020002020202ULL, 0x0202020202020202ULL };

const u64bit DES_IPTAB2[256] = {
0x0000000000000000ULL, 0x0000010000000000ULL, 0x0000000000000100ULL, 0x0000010000000100ULL,
0x0001000000000000ULL, 0x0001010000000000ULL, 0x0001000000000100ULL, 0x0001010000000100ULL,
0x0000000000010000ULL, 0x0000010000010000ULL, 0x0000000000010100ULL, 0x0000010000010100ULL,
0x0001000000010000ULL, 0x0001010000010000ULL, 0x0001000000010100ULL, 0x0001010000010100ULL,
0x0100000000000000ULL, 0x0100010000000000ULL, 0x0100000000000100ULL, 0x0100010000000100ULL,
0x0101000000000000ULL, 0x0101010000000000ULL, 0x0101000000000100ULL, 0x0101010000000100ULL,
0x0100000000010000ULL, 0x0100010000010000ULL, 0x0100000000010100ULL, 0x0100010000010100ULL,
0x0101000000010000ULL, 0x0101010000010000ULL, 0x0101000000010100ULL, 0x0101010000010100ULL,
0x0000000001000000ULL, 0x0000010001000000ULL, 0x0000000001000100ULL, 0x0000010001000100ULL,
0x0001000001000000ULL, 0x0001010001000000ULL, 0x0001000001000100ULL, 0x0001010001000100ULL,
0x0000000001010000ULL, 0x0000010001010000ULL, 0x0000000001010100ULL, 0x0000010001010100ULL,
0x0001000001010000ULL, 0x0001010001010000ULL, 0x0001000001010100ULL, 0x0001010001010100ULL,
0x0100000001000000ULL, 0x0100010001000000ULL, 0x0100000001000100ULL, 0x0100010001000100ULL,
0x0101000001000000ULL, 0x0101010001000000ULL, 0x0101000001000100ULL, 0x0101010001000100ULL,
0x0100000001010000ULL, 0x0100010001010000ULL, 0x0100000001010100ULL, 0x0100010001010100ULL,
0x0101000001010000ULL, 0x0101010001010000ULL, 0x0101000001010100ULL, 0x0101010001010100ULL,
0x0000000100000000ULL, 0x0000010100000000ULL, 0x0000000100000100ULL, 0x0000010100000100ULL,
0x0001000100000000ULL, 0x0001010100000000ULL, 0x0001000100000100ULL, 0x0001010100000100ULL,
0x0000000100010000ULL, 0x0000010100010000ULL, 0x0000000100010100ULL, 0x0000010100010100ULL,
0x0001000100010000ULL, 0x0001010100010000ULL, 0x0001000100010100ULL, 0x0001010100010100ULL,
0x0100000100000000ULL, 0x0100010100000000ULL, 0x0100000100000100ULL, 0x0100010100000100ULL,
0x0101000100000000ULL, 0x0101010100000000ULL, 0x0101000100000100ULL, 0x0101010100000100ULL,
0x0100000100010000ULL, 0x0100010100010000ULL, 0x0100000100010100ULL, 0x0100010100010100ULL,
0x0101000100010000ULL, 0x0101010100010000ULL, 0x0101000100010100ULL, 0x0101010100010100ULL,
0x0000000101000000ULL, 0x0000010101000000ULL, 0x0000000101000100ULL, 0x0000010101000100ULL,
0x0001000101000000ULL, 0x0001010101000000ULL, 0x0001000101000100ULL, 0x0001010101000100ULL,
0x0000000101010000ULL, 0x0000010101010000ULL, 0x0000000101010100ULL, 0x0000010101010100ULL,
0x0001000101010000ULL, 0x0001010101010000ULL, 0x0001000101010100ULL, 0x0001010101010100ULL,
0x0100000101000000ULL, 0x0100010101000000ULL, 0x0100000101000100ULL, 0x0100010101000100ULL,
0x0101000101000000ULL, 0x0101010101000000ULL, 0x0101000101000100ULL, 0x0101010101000100ULL,
0x0100000101010000ULL, 0x0100010101010000ULL, 0x0100000101010100ULL, 0x0100010101010100ULL,
0x0101000101010000ULL, 0x0101010101010000ULL, 0x0101000101010100ULL, 0x0101010101010100ULL,
0x0000000000000001ULL, 0x0000010000000001ULL, 0x0000000000000101ULL, 0x0000010000000101ULL,
0x0001000000000001ULL, 0x0001010000000001ULL, 0x0001000000000101ULL, 0x0001010000000101ULL,
0x0000000000010001ULL, 0x0000010000010001ULL, 0x0000000000010101ULL, 0x0000010000010101ULL,
0x0001000000010001ULL, 0x0001010000010001ULL, 0x0001000000010101ULL, 0x0001010000010101ULL,
0x0100000000000001ULL, 0x0100010000000001ULL, 0x0100000000000101ULL, 0x0100010000000101ULL,
0x0101000000000001ULL, 0x0101010000000001ULL, 0x0101000000000101ULL, 0x0101010000000101ULL,
0x0100000000010001ULL, 0x0100010000010001ULL, 0x0100000000010101ULL, 0x0100010000010101ULL,
0x0101000000010001ULL, 0x0101010000010001ULL, 0x0101000000010101ULL, 0x0101010000010101ULL,
0x0000000001000001ULL, 0x0000010001000001ULL, 0x0000000001000101ULL, 0x0000010001000101ULL,
0x0001000001000001ULL, 0x0001010001000001ULL, 0x0001000001000101ULL, 0x0001010001000101ULL,
0x0000000001010001ULL, 0x0000010001010001ULL, 0x0000000001010101ULL, 0x0000010001010101ULL,
0x0001000001010001ULL, 0x0001010001010001ULL, 0x0001000001010101ULL, 0x0001010001010101ULL,
0x0100000001000001ULL, 0x0100010001000001ULL, 0x0100000001000101ULL, 0x0100010001000101ULL,
0x0101000001000001ULL, 0x0101010001000001ULL, 0x0101000001000101ULL, 0x0101010001000101ULL,
0x0100000001010001ULL, 0x0100010001010001ULL, 0x0100000001010101ULL, 0x0100010001010101ULL,
0x0101000001010001ULL, 0x0101010001010001ULL, 0x0101000001010101ULL, 0x0101010001010101ULL,
0x0000000100000001ULL, 0x0000010100000001ULL, 0x0000000100000101ULL, 0x0000010100000101ULL,
0x0001000100000001ULL, 0x0001010100000001ULL, 0x0001000100000101ULL, 0x0001010100000101ULL,
0x0000000100010001ULL, 0x0000010100010001ULL, 0x0000000100010101ULL, 0x0000010100010101ULL,
0x0001000100010001ULL, 0x0001010100010001ULL, 0x0001000100010101ULL, 0x0001010100010101ULL,
0x0100000100000001ULL, 0x0100010100000001ULL, 0x0100000100000101ULL, 0x0100010100000101ULL,
0x0101000100000001ULL, 0x0101010100000001ULL, 0x0101000100000101ULL, 0x0101010100000101ULL,
0x0100000100010001ULL, 0x0100010100010001ULL, 0x0100000100010101ULL, 0x0100010100010101ULL,
0x0101000100010001ULL, 0x0101010100010001ULL, 0x0101000100010101ULL, 0x0101010100010101ULL,
0x0000000101000001ULL, 0x0000010101000001ULL, 0x0000000101000101ULL, 0x0000010101000101ULL,
0x0001000101000001ULL, 0x0001010101000001ULL, 0x0001000101000101ULL, 0x0001010101000101ULL,
0x0000000101010001ULL, 0x0000010101010001ULL, 0x0000000101010101ULL, 0x0000010101010101ULL,
0x0001000101010001ULL, 0x0001010101010001ULL, 0x0001000101010101ULL, 0x0001010101010101ULL,
0x0100000101000001ULL, 0x0100010101000001ULL, 0x0100000101000101ULL, 0x0100010101000101ULL,
0x0101000101000001ULL, 0x0101010101000001ULL, 0x0101000101000101ULL, 0x0101010101000101ULL,
0x0100000101010001ULL, 0x0100010101010001ULL, 0x0100000101010101ULL, 0x0100010101010101ULL,
0x0101000101010001ULL, 0x0101010101010001ULL, 0x0101000101010101ULL, 0x0101010101010101ULL };

const u64bit DES_FPTAB1[256] = {
0x0000000000000000ULL, 0x0000000100000000ULL, 0x0000000004000000ULL, 0x0000000104000000ULL,
0x0000000000040000ULL, 0x0000000100040000ULL, 0x0000000004040000ULL, 0x0000000104040000ULL,
0x0000000000000400ULL, 0x0000000100000400ULL, 0x0000000004000400ULL, 0x0000000104000400ULL,
0x0000000000040400ULL, 0x0000000100040400ULL, 0x0000000004040400ULL, 0x0000000104040400ULL,
0x0000000000000004ULL, 0x0000000100000004ULL, 0x0000000004000004ULL, 0x0000000104000004ULL,
0x0000000000040004ULL, 0x0000000100040004ULL, 0x0000000004040004ULL, 0x0000000104040004ULL,
0x0000000000000404ULL, 0x0000000100000404ULL, 0x0000000004000404ULL, 0x0000000104000404ULL,
0x0000000000040404ULL, 0x0000000100040404ULL, 0x0000000004040404ULL, 0x0000000104040404ULL,
0x0400000000000000ULL, 0x0400000100000000ULL, 0x0400000004000000ULL, 0x0400000104000000ULL,
0x0400000000040000ULL, 0x0400000100040000ULL, 0x0400000004040000ULL, 0x0400000104040000ULL,
0x0400000000000400ULL, 0x0400000100000400ULL, 0x0400000004000400ULL, 0x0400000104000400ULL,
0x0400000000040400ULL, 0x0400000100040400ULL, 0x0400000004040400ULL, 0x0400000104040400ULL,
0x0400000000000004ULL, 0x0400000100000004ULL, 0x0400000004000004ULL, 0x0400000104000004ULL,
0x0400000000040004ULL, 0x0400000100040004ULL, 0x0400000004040004ULL, 0x0400000104040004ULL,
0x0400000000000404ULL, 0x0400000100000404ULL, 0x0400000004000404ULL, 0x0400000104000404ULL,
0x0400000000040404ULL, 0x0400000100040404ULL, 0x0400000004040404ULL, 0x0400000104040404ULL,
0x0004000000000000ULL, 0x0004000100000000ULL, 0x0004000004000000ULL, 0x0004000104000000ULL,
0x0004000000040000ULL, 0x0004000100040000ULL, 0x0004000004040000ULL, 0x0004000104040000ULL,
0x0004000000000400ULL, 0x0004000100000400ULL, 0x0004000004000400ULL, 0x0004000104000400ULL,
0x0004000000040400ULL, 0x0004000100040400ULL, 0x0004000004040400ULL, 0x0004000104040400ULL,
0x0004000000000004ULL, 0x0004000100000004ULL, 0x0004000004000004ULL, 0x0004000104000004ULL,
0x0004000000040004ULL, 0x0004000100040004ULL, 0x0004000004040004ULL, 0x0004000104040004ULL,
0x0004000000000404ULL, 0x0004000100000404ULL, 0x0004000004000404ULL, 0x0004000104000404ULL,
0x0004000000040404ULL, 0x0004000100040404ULL, 0x0004000004040404ULL, 0x0004000104040404ULL,
0x0404000000000000ULL, 0x0404000100000000ULL, 0x0404000004000000ULL, 0x0404000104000000ULL,
0x0404000000040000ULL, 0x0404000100040000ULL, 0x0404000004040000ULL, 0x0404000104040000ULL,
0x0404000000000400ULL, 0x0404000100000400ULL, 0x0404000004000400ULL, 0x0404000104000400ULL,
0x0404000000040400ULL, 0x0404000100040400ULL, 0x0404000004040400ULL, 0x0404000104040400ULL,
0x0404000000000004ULL, 0x0404000100000004ULL, 0x0404000004000004ULL, 0x0404000104000004ULL,
0x0404000000040004ULL, 0x0404000100040004ULL, 0x0404000004040004ULL, 0x0404000104040004ULL,
0x0404000000000404ULL, 0x0404000100000404ULL, 0x0404000004000404ULL, 0x0404000104000404ULL,
0x0404000000040404ULL, 0x0404000100040404ULL, 0x0404000004040404ULL, 0x0404000104040404ULL,
0x0000040000000000ULL, 0x0000040100000000ULL, 0x0000040004000000ULL, 0x0000040104000000ULL,
0x0000040000040000ULL, 0x0000040100040000ULL, 0x0000040004040000ULL, 0x0000040104040000ULL,
0x0000040000000400ULL, 0x0000040100000400ULL, 0x0000040004000400ULL, 0x0000040104000400ULL,
0x0000040000040400ULL, 0x0000040100040400ULL, 0x0000040004040400ULL, 0x0000040104040400ULL,
0x0000040000000004ULL, 0x0000040100000004ULL, 0x0000040004000004ULL, 0x0000040104000004ULL,
0x0000040000040004ULL, 0x0000040100040004ULL, 0x0000040004040004ULL, 0x0000040104040004ULL,
0x0000040000000404ULL, 0x0000040100000404ULL, 0x0000040004000404ULL, 0x0000040104000404ULL,
0x0000040000040404ULL, 0x0000040100040404ULL, 0x0000040004040404ULL, 0x0000040104040404ULL,
0x0400040000000000ULL, 0x0400040100000000ULL, 0x0400040004000000ULL, 0x0400040104000000ULL,
0x0400040000040000ULL, 0x0400040100040000ULL, 0x0400040004040000ULL, 0x0400040104040000ULL,
0x0400040000000400ULL, 0x0400040100000400ULL, 0x0400040004000400ULL, 0x0400040104000400ULL,
0x0400040000040400ULL, 0x0400040100040400ULL, 0x0400040004040400ULL, 0x0400040104040400ULL,
0x0400040000000004ULL, 0x0400040100000004ULL, 0x0400040004000004ULL, 0x0400040104000004ULL,
0x0400040000040004ULL, 0x0400040100040004ULL, 0x0400040004040004ULL, 0x0400040104040004ULL,
0x0400040000000404ULL, 0x0400040100000404ULL, 0x0400040004000404ULL, 0x0400040104000404ULL,
0x0400040000040404ULL, 0x0400040100040404ULL, 0x0400040004040404ULL, 0x0400040104040404ULL,
0x0004040000000000ULL, 0x0004040100000000ULL, 0x0004040004000000ULL, 0x0004040104000000ULL,
0x0004040000040000ULL, 0x0004040100040000ULL, 0x0004040004040000ULL, 0x0004040104040000ULL,
0x0004040000000400ULL, 0x0004040100000400ULL, 0x0004040004000400ULL, 0x0004040104000400ULL,
0x0004040000040400ULL, 0x0004040100040400ULL, 0x0004040004040400ULL, 0x0004040104040400ULL,
0x0004040000000004ULL, 0x0004040100000004ULL, 0x0004040004000004ULL, 0x0004040104000004ULL,
0x0004040000040004ULL, 0x0004040100040004ULL, 0x0004040004040004ULL, 0x0004040104040004ULL,
0x0004040000000404ULL, 0x0004040100000404ULL, 0x0004040004000404ULL, 0x0004040104000404ULL,
0x0004040000040404ULL, 0x0004040100040404ULL, 0x0004040004040404ULL, 0x0004040104040404ULL,
0x0404040000000000ULL, 0x0404040100000000ULL, 0x0404040004000000ULL, 0x0404040104000000ULL,
0x0404040000040000ULL, 0x0404040100040000ULL, 0x0404040004040000ULL, 0x0404040104040000ULL,
0x0404040000000400ULL, 0x0404040100000400ULL, 0x0404040004000400ULL, 0x0404040104000400ULL,
0x0404040000040400ULL, 0x0404040100040400ULL, 0x0404040004040400ULL, 0x0404040104040400ULL,
0x0404040000000004ULL, 0x0404040100000004ULL, 0x0404040004000004ULL, 0x0404040104000004ULL,
0x0404040000040004ULL, 0x0404040100040004ULL, 0x0404040004040004ULL, 0x0404040104040004ULL,
0x0404040000000404ULL, 0x0404040100000404ULL, 0x0404040004000404ULL, 0x0404040104000404ULL,
0x0404040000040404ULL, 0x0404040100040404ULL, 0x0404040004040404ULL, 0x0404040104040404ULL };

const u64bit DES_FPTAB2[256] = {
0x0000000000000000ULL, 0x0000004000000000ULL, 0x0000000001000000ULL, 0x0000004001000000ULL,
0x0000000000010000ULL, 0x0000004000010000ULL, 0x0000000001010000ULL, 0x0000004001010000ULL,
0x0000000000000100ULL, 0x0000004000000100ULL, 0x0000000001000100ULL, 0x0000004001000100ULL,
0x0000000000010100ULL, 0x0000004000010100ULL, 0x0000000001010100ULL, 0x0000004001010100ULL,
0x0000000000000001ULL, 0x0000004000000001ULL, 0x0000000001000001ULL, 0x0000004001000001ULL,
0x0000000000010001ULL, 0x0000004000010001ULL, 0x0000000001010001ULL, 0x0000004001010001ULL,
0x0000000000000101ULL, 0x0000004000000101ULL, 0x0000000001000101ULL, 0x0000004001000101ULL,
0x0000000000010101ULL, 0x0000004000010101ULL, 0x0000000001010101ULL, 0x0000004001010101ULL,
0x0100000000000000ULL, 0x0100004000000000ULL, 0x0100000001000000ULL, 0x0100004001000000ULL,
0x0100000000010000ULL, 0x0100004000010000ULL, 0x0100000001010000ULL, 0x0100004001010000ULL,
0x0100000000000100ULL, 0x0100004000000100ULL, 0x0100000001000100ULL, 0x0100004001000100ULL,
0x0100000000010100ULL, 0x0100004000010100ULL, 0x0100000001010100ULL, 0x0100004001010100ULL,
0x0100000000000001ULL, 0x0100004000000001ULL, 0x0100000001000001ULL, 0x0100004001000001ULL,
0x0100000000010001ULL, 0x0100004000010001ULL, 0x0100000001010001ULL, 0x0100004001010001ULL,
0x0100000000000101ULL, 0x0100004000000101ULL, 0x0100000001000101ULL, 0x0100004001000101ULL,
0x0100000000010101ULL, 0x0100004000010101ULL, 0x0100000001010101ULL, 0x0100004001010101ULL,
0x0001000000000000ULL, 0x0001004000000000ULL, 0x0001000001000000ULL, 0x0001004001000000ULL,
0x0001000000010000ULL, 0x0001004000010000ULL, 0x0001000001010000ULL, 0x0001004001010000ULL,
0x0001000000000100ULL, 0x0001004000000100ULL, 0x0001000001000100ULL, 0x0001004001000100ULL,
0x0001000000010100ULL, 0x0001004000010100ULL, 0x0001000001010100ULL, 0x0001004001010100ULL,
0x0001000000000001ULL, 0x0001004000000001ULL, 0x0001000001000001ULL, 0x0001004001000001ULL,
0x0001000000010001ULL, 0x0001004000010001ULL, 0x0001000001010001ULL, 0x0001004001010001ULL,
0x0001000000000101ULL, 0x0001004000000101ULL, 0x0001000001000101ULL, 0x0001004001000101ULL,
0x0001000000010101ULL, 0x0001004000010101ULL, 0x0001000001010101ULL, 0x0001004001010101ULL,
0x0101000000000000ULL, 0x0101004000000000ULL, 0x0101000001000000ULL, 0x0101004001000000ULL,
0x0101000000010000ULL, 0x0101004000010000ULL, 0x0101000001010000ULL, 0x0101004001010000ULL,
0x0101000000000100ULL, 0x0101004000000100ULL, 0x0101000001000100ULL, 0x0101004001000100ULL,
0x0101000000010100ULL, 0x0101004000010100ULL, 0x0101000001010100ULL, 0x0101004001010100ULL,
0x0101000000000001ULL, 0x0101004000000001ULL, 0x0101000001000001ULL, 0x0101004001000001ULL,
0x0101000000010001ULL, 0x0101004000010001ULL, 0x0101000001010001ULL, 0x0101004001010001ULL,
0x0101000000000101ULL, 0x0101004000000101ULL, 0x0101000001000101ULL, 0x0101004001000101ULL,
0x0101000000010101ULL, 0x0101004000010101ULL, 0x0101000001010101ULL, 0x0101004001010101ULL,
0x0000010000000000ULL, 0x0000014000000000ULL, 0x0000010001000000ULL, 0x0000014001000000ULL,
0x0000010000010000ULL, 0x0000014000010000ULL, 0x0000010001010000ULL, 0x0000014001010000ULL,
0x0000010000000100ULL, 0x0000014000000100ULL, 0x0000010001000100ULL, 0x0000014001000100ULL,
0x0000010000010100ULL, 0x0000014000010100ULL, 0x0000010001010100ULL, 0x0000014001010100ULL,
0x0000010000000001ULL, 0x0000014000000001ULL, 0x0000010001000001ULL, 0x0000014001000001ULL,
0x0000010000010001ULL, 0x0000014000010001ULL, 0x0000010001010001ULL, 0x0000014001010001ULL,
0x0000010000000101ULL, 0x0000014000000101ULL, 0x0000010001000101ULL, 0x0000014001000101ULL,
0x0000010000010101ULL, 0x0000014000010101ULL, 0x0000010001010101ULL, 0x0000014001010101ULL,
0x0100010000000000ULL, 0x0100014000000000ULL, 0x0100010001000000ULL, 0x0100014001000000ULL,
0x0100010000010000ULL, 0x0100014000010000ULL, 0x0100010001010000ULL, 0x0100014001010000ULL,
0x0100010000000100ULL, 0x0100014000000100ULL, 0x0100010001000100ULL, 0x0100014001000100ULL,
0x0100010000010100ULL, 0x0100014000010100ULL, 0x0100010001010100ULL, 0x0100014001010100ULL,
0x0100010000000001ULL, 0x0100014000000001ULL, 0x0100010001000001ULL, 0x0100014001000001ULL,
0x0100010000010001ULL, 0x0100014000010001ULL, 0x0100010001010001ULL, 0x0100014001010001ULL,
0x0100010000000101ULL, 0x0100014000000101ULL, 0x0100010001000101ULL, 0x0100014001000101ULL,
0x0100010000010101ULL, 0x0100014000010101ULL, 0x0100010001010101ULL, 0x0100014001010101ULL,
0x0001010000000000ULL, 0x0001014000000000ULL, 0x0001010001000000ULL, 0x0001014001000000ULL,
0x0001010000010000ULL, 0x0001014000010000ULL, 0x0001010001010000ULL, 0x0001014001010000ULL,
0x0001010000000100ULL, 0x0001014000000100ULL, 0x0001010001000100ULL, 0x0001014001000100ULL,
0x0001010000010100ULL, 0x0001014000010100ULL, 0x0001010001010100ULL, 0x0001014001010100ULL,
0x0001010000000001ULL, 0x0001014000000001ULL, 0x0001010001000001ULL, 0x0001014001000001ULL,
0x0001010000010001ULL, 0x0001014000010001ULL, 0x0001010001010001ULL, 0x0001014001010001ULL,
0x0001010000000101ULL, 0x0001014000000101ULL, 0x0001010001000101ULL, 0x0001014001000101ULL,
0x0001010000010101ULL, 0x0001014000010101ULL, 0x0001010001010101ULL, 0x0001014001010101ULL,
0x0101010000000000ULL, 0x0101014000000000ULL, 0x0101010001000000ULL, 0x0101014001000000ULL,
0x0101010000010000ULL, 0x0101014000010000ULL, 0x0101010001010000ULL, 0x0101014001010000ULL,
0x0101010000000100ULL, 0x0101014000000100ULL, 0x0101010001000100ULL, 0x0101014001000100ULL,
0x0101010000010100ULL, 0x0101014000010100ULL, 0x0101010001010100ULL, 0x0101014001010100ULL,
0x0101010000000001ULL, 0x0101014000000001ULL, 0x0101010001000001ULL, 0x0101014001000001ULL,
0x0101010000010001ULL, 0x0101014000010001ULL, 0x0101010001010001ULL, 0x0101014001010001ULL,
0x0101010000000101ULL, 0x0101014000000101ULL, 0x0101010001000101ULL, 0x0101014001000101ULL,
0x0101010000010101ULL, 0x0101014000010101ULL, 0x0101010001010101ULL, 0x0101014001010101ULL };

}
/*
* DES
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* DESX Encryption
*/
void DESX::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      xor_buf(out, in, &K1[0], BLOCK_SIZE);
      des.encrypt(out);
      xor_buf(out, &K2[0], BLOCK_SIZE);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* DESX Decryption
*/
void DESX::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      xor_buf(out, in, &K2[0], BLOCK_SIZE);
      des.decrypt(out);
      xor_buf(out, &K1[0], BLOCK_SIZE);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* DESX Key Schedule
*/
void DESX::key_schedule(const byte key[], size_t)
   {
   K1.copy(key, 8);
   des.set_key(key + 8, 8);
   K2.copy(key + 16, 8);
   }

}
/*
* GOST 28147-89
* (C) 1999-2009,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

byte GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const
   {
   byte x = sboxes[4 * col + (row / 2)];

   return (row % 2 == 0) ? (x >> 4) : (x & 0x0F);
   }

GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : name(n)
   {
   // Encoded in the packed fromat from RFC 4357

   // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0)
   static const byte GOST_R_3411_TEST_PARAMS[64] = {
      0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A,
      0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38,
      0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62,
      0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3,
      0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C,
      0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC };

   // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1)
   static const byte GOST_R_3411_CRYPTOPRO_PARAMS[64] = {
      0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42,
      0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F,
      0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1,
      0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87,
      0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE,
      0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC };

   if(name == "R3411_94_TestParam")
      sboxes = GOST_R_3411_TEST_PARAMS;
   else if(name == "R3411_CryptoPro")
      sboxes = GOST_R_3411_CRYPTOPRO_PARAMS;
   else
      throw Invalid_Argument("GOST_28147_89_Params: Unknown " + name);
   }

/*
* GOST Constructor
*/
GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) :
   SBOX(1024), EK(8)
   {
   // Convert the parallel 4x4 sboxes into larger word-based sboxes
   for(size_t i = 0; i != 4; ++i)
      for(size_t j = 0; j != 256; ++j)
         {
         const u32bit T = (param.sbox_entry(2*i  , j % 16)) |
                          (param.sbox_entry(2*i+1, j / 16) << 4);
         SBOX[256*i+j] = rotate_left(T, (11+8*i) % 32);
         }
   }

std::string GOST_28147_89::name() const
   {
   /*
   'Guess' the right name for the sbox on the basis of the values.
   This would need to be updated if support for other sbox parameters
   is added. Preferably, we would just store the string value in the
   constructor, but can't break binary compat.
   */
   std::string sbox_name = "";
   if(SBOX[0] == 0x00072000)
      sbox_name = "R3411_94_TestParam";
   else if(SBOX[0] == 0x0002D000)
      sbox_name = "R3411_CryptoPro";
   else
      throw Internal_Error("GOST-28147 unrecognized sbox value");

   return "GOST-28147-89(" + sbox_name + ")";
   }

/*
* Two rounds of GOST
*/
#define GOST_2ROUND(N1, N2, R1, R2)   \
   do {                               \
   u32bit T0 = N1 + EK[R1];           \
   N2 ^= SBOX[get_byte(3, T0)] |      \
         SBOX[get_byte(2, T0)+256] |  \
         SBOX[get_byte(1, T0)+512] |  \
         SBOX[get_byte(0, T0)+768];   \
                                      \
   u32bit T1 = N2 + EK[R2];           \
   N1 ^= SBOX[get_byte(3, T1)] |      \
         SBOX[get_byte(2, T1)+256] |  \
         SBOX[get_byte(1, T1)+512] |  \
         SBOX[get_byte(0, T1)+768];   \
   } while(0)

/*
* GOST Encryption
*/
void GOST_28147_89::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit N1 = load_le<u32bit>(in, 0);
      u32bit N2 = load_le<u32bit>(in, 1);

      for(size_t j = 0; j != 3; ++j)
         {
         GOST_2ROUND(N1, N2, 0, 1);
         GOST_2ROUND(N1, N2, 2, 3);
         GOST_2ROUND(N1, N2, 4, 5);
         GOST_2ROUND(N1, N2, 6, 7);
         }

      GOST_2ROUND(N1, N2, 7, 6);
      GOST_2ROUND(N1, N2, 5, 4);
      GOST_2ROUND(N1, N2, 3, 2);
      GOST_2ROUND(N1, N2, 1, 0);

      store_le(out, N2, N1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* GOST Decryption
*/
void GOST_28147_89::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit N1 = load_le<u32bit>(in, 0);
      u32bit N2 = load_le<u32bit>(in, 1);

      GOST_2ROUND(N1, N2, 0, 1);
      GOST_2ROUND(N1, N2, 2, 3);
      GOST_2ROUND(N1, N2, 4, 5);
      GOST_2ROUND(N1, N2, 6, 7);

      for(size_t j = 0; j != 3; ++j)
         {
         GOST_2ROUND(N1, N2, 7, 6);
         GOST_2ROUND(N1, N2, 5, 4);
         GOST_2ROUND(N1, N2, 3, 2);
         GOST_2ROUND(N1, N2, 1, 0);
         }

      store_le(out, N2, N1);
      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* GOST Key Schedule
*/
void GOST_28147_89::key_schedule(const byte key[], size_t)
   {
   for(size_t i = 0; i != 8; ++i)
      EK[i] = load_le<u32bit>(key, i);
   }

}
/*
* IDEA
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Multiplication modulo 65537
*/
inline u16bit mul(u16bit x, u16bit y)
   {
   const u32bit P = static_cast<u32bit>(x) * y;

   // P ? 0xFFFF : 0
   const u16bit P_mask = !P - 1;

   const u32bit P_hi = P >> 16;
   const u32bit P_lo = P & 0xFFFF;

   const u16bit r_1 = (P_lo - P_hi) + (P_lo < P_hi);
   const u16bit r_2 = 1 - x - y;

   return (r_1 & P_mask) | (r_2 & ~P_mask);
   }

/*
* Find multiplicative inverses modulo 65537
*
* 65537 is prime; thus Fermat's little theorem tells us that
* x^65537 == x modulo 65537, which means
* x^(65537-2) == x^-1 modulo 65537 since
* x^(65537-2) * x == 1 mod 65537
*
* Do the exponentiation with a basic square and multiply: all bits are
* of exponent are 1 so we always multiply
*/
u16bit mul_inv(u16bit x)
   {
   u16bit y = x;

   for(size_t i = 0; i != 15; ++i)
      {
      y = mul(y, y); // square
      y = mul(y, x);
      }

   return y;
   }

/**
* IDEA is involutional, depending only on the key schedule
*/
void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52])
   {
   const size_t BLOCK_SIZE = 8;

   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit X1 = load_be<u16bit>(in, 0);
      u16bit X2 = load_be<u16bit>(in, 1);
      u16bit X3 = load_be<u16bit>(in, 2);
      u16bit X4 = load_be<u16bit>(in, 3);

      for(size_t j = 0; j != 8; ++j)
         {
         X1 = mul(X1, K[6*j+0]);
         X2 += K[6*j+1];
         X3 += K[6*j+2];
         X4 = mul(X4, K[6*j+3]);

         u16bit T0 = X3;
         X3 = mul(X3 ^ X1, K[6*j+4]);

         u16bit T1 = X2;
         X2 = mul((X2 ^ X4) + X3, K[6*j+5]);
         X3 += X2;

         X1 ^= X2;
         X4 ^= X3;
         X2 ^= T0;
         X3 ^= T1;
         }

      X1  = mul(X1, K[48]);
      X2 += K[50];
      X3 += K[49];
      X4  = mul(X4, K[51]);

      store_be(out, X1, X3, X2, X4);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

}

/*
* IDEA Encryption
*/
void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   idea_op(in, out, blocks, &EK[0]);
   }

/*
* IDEA Decryption
*/
void IDEA::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   idea_op(in, out, blocks, &DK[0]);
   }

/*
* IDEA Key Schedule
*/
void IDEA::key_schedule(const byte key[], size_t)
   {
   for(size_t i = 0; i != 8; ++i)
      EK[i] = load_be<u16bit>(key, i);

   for(size_t i = 1, j = 8, offset = 0; j != 52; i %= 8, ++i, ++j)
      {
      EK[i+7+offset] = static_cast<u16bit>((EK[(i     % 8) + offset] << 9) |
                                           (EK[((i+1) % 8) + offset] >> 7));
      offset += (i == 8) ? 8 : 0;
      }

   DK[51] = mul_inv(EK[3]);
   DK[50] = -EK[2];
   DK[49] = -EK[1];
   DK[48] = mul_inv(EK[0]);

   for(size_t i = 1, j = 4, counter = 47; i != 8; ++i, j += 6)
      {
      DK[counter--] = EK[j+1];
      DK[counter--] = EK[j];
      DK[counter--] = mul_inv(EK[j+5]);
      DK[counter--] = -EK[j+3];
      DK[counter--] = -EK[j+4];
      DK[counter--] = mul_inv(EK[j+2]);
      }

   DK[5] = EK[47];
   DK[4] = EK[46];
   DK[3] = mul_inv(EK[51]);
   DK[2] = -EK[50];
   DK[1] = -EK[49];
   DK[0] = mul_inv(EK[48]);
   }

}
/*
* KASUMI
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* KASUMI S-Boxes
*/
const byte KASUMI_SBOX_S7[128] = {
   0x36, 0x32, 0x3E, 0x38, 0x16, 0x22, 0x5E, 0x60, 0x26, 0x06, 0x3F, 0x5D,
   0x02, 0x12, 0x7B, 0x21, 0x37, 0x71, 0x27, 0x72, 0x15, 0x43, 0x41, 0x0C,
   0x2F, 0x49, 0x2E, 0x1B, 0x19, 0x6F, 0x7C, 0x51, 0x35, 0x09, 0x79, 0x4F,
   0x34, 0x3C, 0x3A, 0x30, 0x65, 0x7F, 0x28, 0x78, 0x68, 0x46, 0x47, 0x2B,
   0x14, 0x7A, 0x48, 0x3D, 0x17, 0x6D, 0x0D, 0x64, 0x4D, 0x01, 0x10, 0x07,
   0x52, 0x0A, 0x69, 0x62, 0x75, 0x74, 0x4C, 0x0B, 0x59, 0x6A, 0x00, 0x7D,
   0x76, 0x63, 0x56, 0x45, 0x1E, 0x39, 0x7E, 0x57, 0x70, 0x33, 0x11, 0x05,
   0x5F, 0x0E, 0x5A, 0x54, 0x5B, 0x08, 0x23, 0x67, 0x20, 0x61, 0x1C, 0x42,
   0x66, 0x1F, 0x1A, 0x2D, 0x4B, 0x04, 0x55, 0x5C, 0x25, 0x4A, 0x50, 0x31,
   0x44, 0x1D, 0x73, 0x2C, 0x40, 0x6B, 0x6C, 0x18, 0x6E, 0x53, 0x24, 0x4E,
   0x2A, 0x13, 0x0F, 0x29, 0x58, 0x77, 0x3B, 0x03 };

const u16bit KASUMI_SBOX_S9[512] = {
   0x00A7, 0x00EF, 0x00A1, 0x017B, 0x0187, 0x014E, 0x0009, 0x0152, 0x0026,
   0x00E2, 0x0030, 0x0166, 0x01C4, 0x0181, 0x005A, 0x018D, 0x00B7, 0x00FD,
   0x0093, 0x014B, 0x019F, 0x0154, 0x0033, 0x016A, 0x0132, 0x01F4, 0x0106,
   0x0052, 0x00D8, 0x009F, 0x0164, 0x00B1, 0x00AF, 0x00F1, 0x01E9, 0x0025,
   0x00CE, 0x0011, 0x0000, 0x014D, 0x002C, 0x00FE, 0x017A, 0x003A, 0x008F,
   0x00DC, 0x0051, 0x0190, 0x005F, 0x0003, 0x013B, 0x00F5, 0x0036, 0x00EB,
   0x00DA, 0x0195, 0x01D8, 0x0108, 0x00AC, 0x01EE, 0x0173, 0x0122, 0x018F,
   0x004C, 0x00A5, 0x00C5, 0x018B, 0x0079, 0x0101, 0x01E0, 0x01A7, 0x00D4,
   0x00F0, 0x001C, 0x01CE, 0x00B0, 0x0196, 0x01FB, 0x0120, 0x00DF, 0x01F5,
   0x0197, 0x00F9, 0x0109, 0x0059, 0x00BA, 0x00DD, 0x01AC, 0x00A4, 0x004A,
   0x01B8, 0x00C4, 0x01CA, 0x01A5, 0x015E, 0x00A3, 0x00E8, 0x009E, 0x0086,
   0x0162, 0x000D, 0x00FA, 0x01EB, 0x008E, 0x00BF, 0x0045, 0x00C1, 0x01A9,
   0x0098, 0x00E3, 0x016E, 0x0087, 0x0158, 0x012C, 0x0114, 0x00F2, 0x01B5,
   0x0140, 0x0071, 0x0116, 0x000B, 0x00F3, 0x0057, 0x013D, 0x0024, 0x005D,
   0x01F0, 0x001B, 0x01E7, 0x01BE, 0x01E2, 0x0029, 0x0044, 0x009C, 0x01C9,
   0x0083, 0x0146, 0x0193, 0x0153, 0x0014, 0x0027, 0x0073, 0x01BA, 0x007C,
   0x01DB, 0x0180, 0x01FC, 0x0035, 0x0070, 0x00AA, 0x01DF, 0x0097, 0x007E,
   0x00A9, 0x0049, 0x010C, 0x0117, 0x0141, 0x00A8, 0x016C, 0x016B, 0x0124,
   0x002E, 0x01F3, 0x0189, 0x0147, 0x0144, 0x0018, 0x01C8, 0x010B, 0x009D,
   0x01CC, 0x01E8, 0x01AA, 0x0135, 0x00E5, 0x01B7, 0x01FA, 0x00D0, 0x010F,
   0x015D, 0x0191, 0x01B2, 0x00EC, 0x0010, 0x00D1, 0x0167, 0x0034, 0x0038,
   0x0078, 0x00C7, 0x0115, 0x01D1, 0x01A0, 0x00FC, 0x011F, 0x00F6, 0x0006,
   0x0053, 0x0131, 0x01A4, 0x0159, 0x0099, 0x01F6, 0x0041, 0x003D, 0x00F4,
   0x011A, 0x00AD, 0x00DE, 0x01A2, 0x0043, 0x0182, 0x0170, 0x0105, 0x0065,
   0x01DC, 0x0123, 0x00C3, 0x01AE, 0x0031, 0x004F, 0x00A6, 0x014A, 0x0118,
   0x017F, 0x0175, 0x0080, 0x017E, 0x0198, 0x009B, 0x01EF, 0x016F, 0x0184,
   0x0112, 0x006B, 0x01CB, 0x01A1, 0x003E, 0x01C6, 0x0084, 0x00E1, 0x00CB,
   0x013C, 0x00EA, 0x000E, 0x012D, 0x005B, 0x01F7, 0x011E, 0x01A8, 0x00D3,
   0x015B, 0x0133, 0x008C, 0x0176, 0x0023, 0x0067, 0x007D, 0x01AB, 0x0013,
   0x00D6, 0x01C5, 0x0092, 0x01F2, 0x013A, 0x01BC, 0x00E6, 0x0100, 0x0149,
   0x00C6, 0x011D, 0x0032, 0x0074, 0x004E, 0x019A, 0x000A, 0x00CD, 0x01FE,
   0x00AB, 0x00E7, 0x002D, 0x008B, 0x01D3, 0x001D, 0x0056, 0x01F9, 0x0020,
   0x0048, 0x001A, 0x0156, 0x0096, 0x0139, 0x01EA, 0x01AF, 0x00EE, 0x019B,
   0x0145, 0x0095, 0x01D9, 0x0028, 0x0077, 0x00AE, 0x0163, 0x00B9, 0x00E9,
   0x0185, 0x0047, 0x01C0, 0x0111, 0x0174, 0x0037, 0x006E, 0x00B2, 0x0142,
   0x000C, 0x01D5, 0x0188, 0x0171, 0x00BE, 0x0001, 0x006D, 0x0177, 0x0089,
   0x00B5, 0x0058, 0x004B, 0x0134, 0x0104, 0x01E4, 0x0062, 0x0110, 0x0172,
   0x0113, 0x019C, 0x006F, 0x0150, 0x013E, 0x0004, 0x01F8, 0x01EC, 0x0103,
   0x0130, 0x004D, 0x0151, 0x01B3, 0x0015, 0x0165, 0x012F, 0x014C, 0x01E3,
   0x0012, 0x002F, 0x0055, 0x0019, 0x01F1, 0x01DA, 0x0121, 0x0064, 0x010D,
   0x0128, 0x01DE, 0x010E, 0x006A, 0x001F, 0x0068, 0x01B1, 0x0054, 0x019E,
   0x01E6, 0x018A, 0x0060, 0x0063, 0x009A, 0x01FF, 0x0094, 0x019D, 0x0169,
   0x0199, 0x00FF, 0x00A2, 0x00D7, 0x012E, 0x00C9, 0x010A, 0x015F, 0x0157,
   0x0090, 0x01B9, 0x016D, 0x006C, 0x012A, 0x00FB, 0x0022, 0x00B6, 0x01FD,
   0x008A, 0x00D2, 0x014F, 0x0085, 0x0137, 0x0160, 0x0148, 0x008D, 0x018C,
   0x015A, 0x007B, 0x013F, 0x01C2, 0x0119, 0x01AD, 0x00E4, 0x01BB, 0x01E1,
   0x005C, 0x0194, 0x01E5, 0x01A6, 0x00F8, 0x0129, 0x0017, 0x00D5, 0x0082,
   0x01D2, 0x0016, 0x00D9, 0x011B, 0x0046, 0x0126, 0x0168, 0x01A3, 0x007F,
   0x0138, 0x0179, 0x0007, 0x01D4, 0x00C2, 0x0002, 0x0075, 0x0127, 0x01CF,
   0x0102, 0x00E0, 0x01BF, 0x00F7, 0x00BB, 0x0050, 0x018E, 0x011C, 0x0161,
   0x0069, 0x0186, 0x012B, 0x01D7, 0x01D6, 0x00B8, 0x0039, 0x00C8, 0x015C,
   0x003F, 0x00CC, 0x00BC, 0x0021, 0x01C3, 0x0061, 0x001E, 0x0136, 0x00DB,
   0x005E, 0x00A0, 0x0081, 0x01ED, 0x0040, 0x00B3, 0x0107, 0x0066, 0x00BD,
   0x00CF, 0x0072, 0x0192, 0x01B6, 0x01DD, 0x0183, 0x007A, 0x00C0, 0x002A,
   0x017D, 0x0005, 0x0091, 0x0076, 0x00B4, 0x01C1, 0x0125, 0x0143, 0x0088,
   0x017C, 0x002B, 0x0042, 0x003C, 0x01C7, 0x0155, 0x01BD, 0x00CA, 0x01B0,
   0x0008, 0x00ED, 0x000F, 0x0178, 0x01B4, 0x01D0, 0x003B, 0x01CD };

/*
* KASUMI FI Function
*/
u16bit FI(u16bit I, u16bit K)
   {
   u16bit D9 = (I >> 7);
   byte D7 = (I & 0x7F);
   D9 = KASUMI_SBOX_S9[D9] ^ D7;
   D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F);

   D7 ^= (K >> 9);
   D9 = KASUMI_SBOX_S9[D9 ^ (K & 0x1FF)] ^ D7;
   D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F);
   return (D7 << 9) | D9;
   }

}

/*
* KASUMI Encryption
*/
void KASUMI::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit B0 = load_be<u16bit>(in, 0);
      u16bit B1 = load_be<u16bit>(in, 1);
      u16bit B2 = load_be<u16bit>(in, 2);
      u16bit B3 = load_be<u16bit>(in, 3);

      for(size_t j = 0; j != 8; j += 2)
         {
         const u16bit* K = &EK[8*j];

         u16bit R = B1 ^ (rotate_left(B0, 1) & K[0]);
         u16bit L = B0 ^ (rotate_left(R, 1) | K[1]);

         L = FI(L ^ K[ 2], K[ 3]) ^ R;
         R = FI(R ^ K[ 4], K[ 5]) ^ L;
         L = FI(L ^ K[ 6], K[ 7]) ^ R;

         R = B2 ^= R;
         L = B3 ^= L;

         R = FI(R ^ K[10], K[11]) ^ L;
         L = FI(L ^ K[12], K[13]) ^ R;
         R = FI(R ^ K[14], K[15]) ^ L;

         R ^= (rotate_left(L, 1) & K[8]);
         L ^= (rotate_left(R, 1) | K[9]);

         B0 ^= L;
         B1 ^= R;
         }

      store_be(out, B0, B1, B2, B3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* KASUMI Decryption
*/
void KASUMI::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit B0 = load_be<u16bit>(in, 0);
      u16bit B1 = load_be<u16bit>(in, 1);
      u16bit B2 = load_be<u16bit>(in, 2);
      u16bit B3 = load_be<u16bit>(in, 3);

      for(size_t j = 0; j != 8; j += 2)
         {
         const u16bit* K = &EK[8*(6-j)];

         u16bit L = B2, R = B3;

         L = FI(L ^ K[10], K[11]) ^ R;
         R = FI(R ^ K[12], K[13]) ^ L;
         L = FI(L ^ K[14], K[15]) ^ R;

         L ^= (rotate_left(R, 1) & K[8]);
         R ^= (rotate_left(L, 1) | K[9]);

         R = B0 ^= R;
         L = B1 ^= L;

         L ^= (rotate_left(R, 1) & K[0]);
         R ^= (rotate_left(L, 1) | K[1]);

         R = FI(R ^ K[2], K[3]) ^ L;
         L = FI(L ^ K[4], K[5]) ^ R;
         R = FI(R ^ K[6], K[7]) ^ L;

         B2 ^= L;
         B3 ^= R;
         }

      store_be(out, B0, B1, B2, B3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* KASUMI Key Schedule
*/
void KASUMI::key_schedule(const byte key[], size_t)
   {
   static const u16bit RC[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF,
                                0xFEDC, 0xBA98, 0x7654, 0x3210 };

   SecureVector<u16bit> K(16);
   for(size_t i = 0; i != 8; ++i)
      {
      K[i] = load_be<u16bit>(key, i);
      K[i+8] = K[i] ^ RC[i];
      }

   for(size_t i = 0; i != 8; ++i)
      {
      EK[8*i  ] = rotate_left(K[(i+0) % 8    ], 2);
      EK[8*i+1] = rotate_left(K[(i+2) % 8 + 8], 1);
      EK[8*i+2] = rotate_left(K[(i+1) % 8    ], 5);
      EK[8*i+3] = K[(i+4) % 8 + 8];
      EK[8*i+4] = rotate_left(K[(i+5) % 8    ], 8);
      EK[8*i+5] = K[(i+3) % 8 + 8];
      EK[8*i+6] = rotate_left(K[(i+6) % 8    ], 13);
      EK[8*i+7] = K[(i+7) % 8 + 8];
      }
   }

}
/*
* Lion
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Lion Encryption
*/
void Lion::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   SecureVector<byte> buffer_vec(LEFT_SIZE);
   byte* buffer = &buffer_vec[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      xor_buf(buffer, in, &key1[0], LEFT_SIZE);
      cipher->set_key(buffer, LEFT_SIZE);
      cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE);

      hash->update(out + LEFT_SIZE, RIGHT_SIZE);
      hash->final(buffer);
      xor_buf(out, in, buffer, LEFT_SIZE);

      xor_buf(buffer, out, &key2[0], LEFT_SIZE);
      cipher->set_key(buffer, LEFT_SIZE);
      cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Lion Decryption
*/
void Lion::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   SecureVector<byte> buffer_vec(LEFT_SIZE);
   byte* buffer = &buffer_vec[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      xor_buf(buffer, in, &key2[0], LEFT_SIZE);
      cipher->set_key(buffer, LEFT_SIZE);
      cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE);

      hash->update(out + LEFT_SIZE, RIGHT_SIZE);
      hash->final(buffer);
      xor_buf(out, in, buffer, LEFT_SIZE);

      xor_buf(buffer, out, &key1[0], LEFT_SIZE);
      cipher->set_key(buffer, LEFT_SIZE);
      cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Lion Key Schedule
*/
void Lion::key_schedule(const byte key[], size_t length)
   {
   clear();

   key1.copy(key,              length / 2);
   key2.copy(key + length / 2, length / 2);
   }

/*
* Return the name of this type
*/
std::string Lion::name() const
   {
   return "Lion(" + hash->name() + "," +
                    cipher->name() + "," +
                    to_string(BLOCK_SIZE) + ")";
   }

/*
* Return a clone of this object
*/
BlockCipher* Lion::clone() const
   {
   return new Lion(hash->clone(), cipher->clone(), BLOCK_SIZE);
   }

/*
* Clear memory of sensitive data
*/
void Lion::clear()
   {
   hash->clear();
   cipher->clear();
   zeroise(key1);
   zeroise(key2);
   }

/*
* Lion Constructor
*/
Lion::Lion(HashFunction* hash_in, StreamCipher* sc_in, size_t block_len) :
   BLOCK_SIZE(std::max<size_t>(2*hash_in->output_length() + 1, block_len)),
   LEFT_SIZE(hash_in->output_length()),
   RIGHT_SIZE(BLOCK_SIZE - LEFT_SIZE),
   hash(hash_in),
   cipher(sc_in)
   {
   if(2*LEFT_SIZE + 1 > BLOCK_SIZE)
      throw Invalid_Argument(name() + ": Chosen block size is too small");

   if(!cipher->valid_keylength(LEFT_SIZE))
      throw Invalid_Argument(name() + ": This stream/hash combo is invalid");

   key1.resize(LEFT_SIZE);
   key2.resize(LEFT_SIZE);
   }

}
/*
* Luby-Rackoff
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Luby-Rackoff Encryption
*/
void LubyRackoff::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t len = hash->output_length();

   SecureVector<byte> buffer_vec(len);
   byte* buffer = &buffer_vec[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      hash->update(K1);
      hash->update(in, len);
      hash->final(buffer);
      xor_buf(out + len, in + len, buffer, len);

      hash->update(K2);
      hash->update(out + len, len);
      hash->final(buffer);
      xor_buf(out, in, buffer, len);

      hash->update(K1);
      hash->update(out, len);
      hash->final(buffer);
      xor_buf(out + len, buffer, len);

      hash->update(K2);
      hash->update(out + len, len);
      hash->final(buffer);
      xor_buf(out, buffer, len);

      in += 2 * len;
      out += 2 * len;
      }
   }

/*
* Luby-Rackoff Decryption
*/
void LubyRackoff::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t len = hash->output_length();

   SecureVector<byte> buffer_vec(len);
   byte* buffer = &buffer_vec[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      hash->update(K2);
      hash->update(in + len, len);
      hash->final(buffer);
      xor_buf(out, in, buffer, len);

      hash->update(K1);
      hash->update(out, len);
      hash->final(buffer);
      xor_buf(out + len, in + len, buffer, len);

      hash->update(K2);
      hash->update(out + len, len);
      hash->final(buffer);
      xor_buf(out, buffer, len);

      hash->update(K1);
      hash->update(out, len);
      hash->final(buffer);
      xor_buf(out + len, buffer, len);

      in += 2 * len;
      out += 2 * len;
      }
   }

/*
* Luby-Rackoff Key Schedule
*/
void LubyRackoff::key_schedule(const byte key[], size_t length)
   {
   K1.resize(length / 2);
   K2.resize(length / 2);
   copy_mem(&K1[0], key             , length / 2);
   copy_mem(&K2[0], key + length / 2, length / 2);
   }

/*
* Clear memory of sensitive data
*/
void LubyRackoff::clear()
   {
   zeroise(K1);
   zeroise(K2);
   hash->clear();
   }

/*
* Return a clone of this object
*/
BlockCipher* LubyRackoff::clone() const
   {
   return new LubyRackoff(hash->clone());
   }

/*
* Return the name of this type
*/
std::string LubyRackoff::name() const
   {
   return "Luby-Rackoff(" + hash->name() + ")";
   }

/*
* Luby-Rackoff Constructor
*/
LubyRackoff::LubyRackoff(HashFunction* h) : hash(h)
   {
   }

}
/*
* MARS
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/**
* The MARS sbox
*/
const u32bit SBOX[512] = {
   0x09D0C479, 0x28C8FFE0, 0x84AA6C39, 0x9DAD7287, 0x7DFF9BE3, 0xD4268361,
   0xC96DA1D4, 0x7974CC93, 0x85D0582E, 0x2A4B5705, 0x1CA16A62, 0xC3BD279D,
   0x0F1F25E5, 0x5160372F, 0xC695C1FB, 0x4D7FF1E4, 0xAE5F6BF4, 0x0D72EE46,
   0xFF23DE8A, 0xB1CF8E83, 0xF14902E2, 0x3E981E42, 0x8BF53EB6, 0x7F4BF8AC,
   0x83631F83, 0x25970205, 0x76AFE784, 0x3A7931D4, 0x4F846450, 0x5C64C3F6,
   0x210A5F18, 0xC6986A26, 0x28F4E826, 0x3A60A81C, 0xD340A664, 0x7EA820C4,
   0x526687C5, 0x7EDDD12B, 0x32A11D1D, 0x9C9EF086, 0x80F6E831, 0xAB6F04AD,
   0x56FB9B53, 0x8B2E095C, 0xB68556AE, 0xD2250B0D, 0x294A7721, 0xE21FB253,
   0xAE136749, 0xE82AAE86, 0x93365104, 0x99404A66, 0x78A784DC, 0xB69BA84B,
   0x04046793, 0x23DB5C1E, 0x46CAE1D6, 0x2FE28134, 0x5A223942, 0x1863CD5B,
   0xC190C6E3, 0x07DFB846, 0x6EB88816, 0x2D0DCC4A, 0xA4CCAE59, 0x3798670D,
   0xCBFA9493, 0x4F481D45, 0xEAFC8CA8, 0xDB1129D6, 0xB0449E20, 0x0F5407FB,
   0x6167D9A8, 0xD1F45763, 0x4DAA96C3, 0x3BEC5958, 0xABABA014, 0xB6CCD201,
   0x38D6279F, 0x02682215, 0x8F376CD5, 0x092C237E, 0xBFC56593, 0x32889D2C,
   0x854B3E95, 0x05BB9B43, 0x7DCD5DCD, 0xA02E926C, 0xFAE527E5, 0x36A1C330,
   0x3412E1AE, 0xF257F462, 0x3C4F1D71, 0x30A2E809, 0x68E5F551, 0x9C61BA44,
   0x5DED0AB8, 0x75CE09C8, 0x9654F93E, 0x698C0CCA, 0x243CB3E4, 0x2B062B97,
   0x0F3B8D9E, 0x00E050DF, 0xFC5D6166, 0xE35F9288, 0xC079550D, 0x0591AEE8,
   0x8E531E74, 0x75FE3578, 0x2F6D829A, 0xF60B21AE, 0x95E8EB8D, 0x6699486B,
   0x901D7D9B, 0xFD6D6E31, 0x1090ACEF, 0xE0670DD8, 0xDAB2E692, 0xCD6D4365,
   0xE5393514, 0x3AF345F0, 0x6241FC4D, 0x460DA3A3, 0x7BCF3729, 0x8BF1D1E0,
   0x14AAC070, 0x1587ED55, 0x3AFD7D3E, 0xD2F29E01, 0x29A9D1F6, 0xEFB10C53,
   0xCF3B870F, 0xB414935C, 0x664465ED, 0x024ACAC7, 0x59A744C1, 0x1D2936A7,
   0xDC580AA6, 0xCF574CA8, 0x040A7A10, 0x6CD81807, 0x8A98BE4C, 0xACCEA063,
   0xC33E92B5, 0xD1E0E03D, 0xB322517E, 0x2092BD13, 0x386B2C4A, 0x52E8DD58,
   0x58656DFB, 0x50820371, 0x41811896, 0xE337EF7E, 0xD39FB119, 0xC97F0DF6,
   0x68FEA01B, 0xA150A6E5, 0x55258962, 0xEB6FF41B, 0xD7C9CD7A, 0xA619CD9E,
   0xBCF09576, 0x2672C073, 0xF003FB3C, 0x4AB7A50B, 0x1484126A, 0x487BA9B1,
   0xA64FC9C6, 0xF6957D49, 0x38B06A75, 0xDD805FCD, 0x63D094CF, 0xF51C999E,
   0x1AA4D343, 0xB8495294, 0xCE9F8E99, 0xBFFCD770, 0xC7C275CC, 0x378453A7,
   0x7B21BE33, 0x397F41BD, 0x4E94D131, 0x92CC1F98, 0x5915EA51, 0x99F861B7,
   0xC9980A88, 0x1D74FD5F, 0xB0A495F8, 0x614DEED0, 0xB5778EEA, 0x5941792D,
   0xFA90C1F8, 0x33F824B4, 0xC4965372, 0x3FF6D550, 0x4CA5FEC0, 0x8630E964,
   0x5B3FBBD6, 0x7DA26A48, 0xB203231A, 0x04297514, 0x2D639306, 0x2EB13149,
   0x16A45272, 0x532459A0, 0x8E5F4872, 0xF966C7D9, 0x07128DC0, 0x0D44DB62,
   0xAFC8D52D, 0x06316131, 0xD838E7CE, 0x1BC41D00, 0x3A2E8C0F, 0xEA83837E,
   0xB984737D, 0x13BA4891, 0xC4F8B949, 0xA6D6ACB3, 0xA215CDCE, 0x8359838B,
   0x6BD1AA31, 0xF579DD52, 0x21B93F93, 0xF5176781, 0x187DFDDE, 0xE94AEB76,
   0x2B38FD54, 0x431DE1DA, 0xAB394825, 0x9AD3048F, 0xDFEA32AA, 0x659473E3,
   0x623F7863, 0xF3346C59, 0xAB3AB685, 0x3346A90B, 0x6B56443E, 0xC6DE01F8,
   0x8D421FC0, 0x9B0ED10C, 0x88F1A1E9, 0x54C1F029, 0x7DEAD57B, 0x8D7BA426,
   0x4CF5178A, 0x551A7CCA, 0x1A9A5F08, 0xFCD651B9, 0x25605182, 0xE11FC6C3,
   0xB6FD9676, 0x337B3027, 0xB7C8EB14, 0x9E5FD030, 0x6B57E354, 0xAD913CF7,
   0x7E16688D, 0x58872A69, 0x2C2FC7DF, 0xE389CCC6, 0x30738DF1, 0x0824A734,
   0xE1797A8B, 0xA4A8D57B, 0x5B5D193B, 0xC8A8309B, 0x73F9A978, 0x73398D32,
   0x0F59573E, 0xE9DF2B03, 0xE8A5B6C8, 0x848D0704, 0x98DF93C2, 0x720A1DC3,
   0x684F259A, 0x943BA848, 0xA6370152, 0x863B5EA3, 0xD17B978B, 0x6D9B58EF,
   0x0A700DD4, 0xA73D36BF, 0x8E6A0829, 0x8695BC14, 0xE35B3447, 0x933AC568,
   0x8894B022, 0x2F511C27, 0xDDFBCC3C, 0x006662B6, 0x117C83FE, 0x4E12B414,
   0xC2BCA766, 0x3A2FEC10, 0xF4562420, 0x55792E2A, 0x46F5D857, 0xCEDA25CE,
   0xC3601D3B, 0x6C00AB46, 0xEFAC9C28, 0xB3C35047, 0x611DFEE3, 0x257C3207,
   0xFDD58482, 0x3B14D84F, 0x23BECB64, 0xA075F3A3, 0x088F8EAD, 0x07ADF158,
   0x7796943C, 0xFACABF3D, 0xC09730CD, 0xF7679969, 0xDA44E9ED, 0x2C854C12,
   0x35935FA3, 0x2F057D9F, 0x690624F8, 0x1CB0BAFD, 0x7B0DBDC6, 0x810F23BB,
   0xFA929A1A, 0x6D969A17, 0x6742979B, 0x74AC7D05, 0x010E65C4, 0x86A3D963,
   0xF907B5A0, 0xD0042BD3, 0x158D7D03, 0x287A8255, 0xBBA8366F, 0x096EDC33,
   0x21916A7B, 0x77B56B86, 0x951622F9, 0xA6C5E650, 0x8CEA17D1, 0xCD8C62BC,
   0xA3D63433, 0x358A68FD, 0x0F9B9D3C, 0xD6AA295B, 0xFE33384A, 0xC000738E,
   0xCD67EB2F, 0xE2EB6DC2, 0x97338B02, 0x06C9F246, 0x419CF1AD, 0x2B83C045,
   0x3723F18A, 0xCB5B3089, 0x160BEAD7, 0x5D494656, 0x35F8A74B, 0x1E4E6C9E,
   0x000399BD, 0x67466880, 0xB4174831, 0xACF423B2, 0xCA815AB3, 0x5A6395E7,
   0x302A67C5, 0x8BDB446B, 0x108F8FA4, 0x10223EDA, 0x92B8B48B, 0x7F38D0EE,
   0xAB2701D4, 0x0262D415, 0xAF224A30, 0xB3D88ABA, 0xF8B2C3AF, 0xDAF7EF70,
   0xCC97D3B7, 0xE9614B6C, 0x2BAEBFF4, 0x70F687CF, 0x386C9156, 0xCE092EE5,
   0x01E87DA6, 0x6CE91E6A, 0xBB7BCC84, 0xC7922C20, 0x9D3B71FD, 0x060E41C6,
   0xD7590F15, 0x4E03BB47, 0x183C198E, 0x63EEB240, 0x2DDBF49A, 0x6D5CBA54,
   0x923750AF, 0xF9E14236, 0x7838162B, 0x59726C72, 0x81B66760, 0xBB2926C1,
   0x48A0CE0D, 0xA6C0496D, 0xAD43507B, 0x718D496A, 0x9DF057AF, 0x44B1BDE6,
   0x054356DC, 0xDE7CED35, 0xD51A138B, 0x62088CC9, 0x35830311, 0xC96EFCA2,
   0x686F86EC, 0x8E77CB68, 0x63E1D6B8, 0xC80F9778, 0x79C491FD, 0x1B4C67F2,
   0x72698D7D, 0x5E368C31, 0xF7D95E2E, 0xA1D3493F, 0xDCD9433E, 0x896F1552,
   0x4BC4CA7A, 0xA6D1BAF4, 0xA5A96DCC, 0x0BEF8B46, 0xA169FDA7, 0x74DF40B7,
   0x4E208804, 0x9A756607, 0x038E87C8, 0x20211E44, 0x8B7AD4BF, 0xC6403F35,
   0x1848E36D, 0x80BDB038, 0x1E62891C, 0x643D2107, 0xBF04D6F8, 0x21092C8C,
   0xF644F389, 0x0778404E, 0x7B78ADB8, 0xA2C52D53, 0x42157ABE, 0xA2253E2E,
   0x7BF3F4AE, 0x80F594F9, 0x953194E7, 0x77EB92ED, 0xB3816930, 0xDA8D9336,
   0xBF447469, 0xF26D9483, 0xEE6FAED5, 0x71371235, 0xDE425F73, 0xB4E59F43,
   0x7DBE2D4E, 0x2D37B185, 0x49DC9A63, 0x98C39D98, 0x1301C9A2, 0x389B1BBF,
   0x0C18588D, 0xA421C1BA, 0x7AA3865C, 0x71E08558, 0x3C5CFCAA, 0x7D239CA4,
   0x0297D9DD, 0xD7DC2830, 0x4B37802B, 0x7428AB54, 0xAEEE0347, 0x4B3FBB85,
   0x692F2F08, 0x134E578E, 0x36D9E0BF, 0xAE8B5FCF, 0xEDB93ECF, 0x2B27248E,
   0x170EB1EF, 0x7DC57FD6, 0x1E760F16, 0xB1136601, 0x864E1B9B, 0xD7EA7319,
   0x3AB871BD, 0xCFA4D76F, 0xE31BD782, 0x0DBEB469, 0xABB96061, 0x5370F85D,
   0xFFB07E37, 0xDA30D0FB, 0xEBC977B6, 0x0B98B40F, 0x3A4D0FE6, 0xDF4FC26B,
   0x159CF22A, 0xC298D6E2, 0x2B78EF6A, 0x61A94AC0, 0xAB561187, 0x14EEA0F0,
   0xDF0D4164, 0x19AF70EE };

/*
* MARS Encryption Round
*/
inline void encrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D,
                          u32bit EK1, u32bit EK2)
   {
   const u32bit X = A + EK1;
   A  = rotate_left(A, 13);
   u32bit Y = A * EK2;
   u32bit Z = SBOX[X % 512];

   Y  = rotate_left(Y, 5);
   Z ^= Y;
   C += rotate_left(X, Y % 32);
   Y  = rotate_left(Y, 5);
   Z ^= Y;
   D ^= Y;
   B += rotate_left(Z, Y % 32);
   }

/*
* MARS Decryption Round
*/
inline void decrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D,
                          u32bit EK1, u32bit EK2)
   {
   u32bit Y = A * EK1;
   A = rotate_right(A, 13);
   const u32bit X = A + EK2;
   u32bit Z = SBOX[X % 512];

   Y  = rotate_left(Y, 5);
   Z ^= Y;
   C -= rotate_left(X, Y % 32);
   Y  = rotate_left(Y, 5);
   Z ^= Y;
   D ^= Y;
   B -= rotate_left(Z, Y % 32);
   }

/*
* MARS Forward Mixing Operation
*/
void forward_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D)
   {
   for(size_t j = 0; j != 2; ++j)
      {
      B ^= SBOX[get_byte(3, A)]; B += SBOX[get_byte(2, A) + 256];
      C += SBOX[get_byte(1, A)]; D ^= SBOX[get_byte(0, A) + 256];
      A = rotate_right(A, 24) + D;

      C ^= SBOX[get_byte(3, B)]; C += SBOX[get_byte(2, B) + 256];
      D += SBOX[get_byte(1, B)]; A ^= SBOX[get_byte(0, B) + 256];
      B = rotate_right(B, 24) + C;

      D ^= SBOX[get_byte(3, C)]; D += SBOX[get_byte(2, C) + 256];
      A += SBOX[get_byte(1, C)]; B ^= SBOX[get_byte(0, C) + 256];
      C = rotate_right(C, 24);

      A ^= SBOX[get_byte(3, D)]; A += SBOX[get_byte(2, D) + 256];
      B += SBOX[get_byte(1, D)]; C ^= SBOX[get_byte(0, D) + 256];
      D = rotate_right(D, 24);
      }
   }

/*
* MARS Reverse Mixing Operation
*/
void reverse_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D)
   {
   for(size_t j = 0; j != 2; ++j)
      {
      B ^= SBOX[get_byte(3, A) + 256]; C -= SBOX[get_byte(0, A)];
      D -= SBOX[get_byte(1, A) + 256]; D ^= SBOX[get_byte(2, A)];
      A = rotate_left(A, 24);

      C ^= SBOX[get_byte(3, B) + 256]; D -= SBOX[get_byte(0, B)];
      A -= SBOX[get_byte(1, B) + 256]; A ^= SBOX[get_byte(2, B)];
      C -= (B = rotate_left(B, 24));

      D ^= SBOX[get_byte(3, C) + 256]; A -= SBOX[get_byte(0, C)];
      B -= SBOX[get_byte(1, C) + 256]; B ^= SBOX[get_byte(2, C)];
      C = rotate_left(C, 24);
      D -= A;

      A ^= SBOX[get_byte(3, D) + 256]; B -= SBOX[get_byte(0, D)];
      C -= SBOX[get_byte(1, D) + 256]; C ^= SBOX[get_byte(2, D)];
      D = rotate_left(D, 24);
      }
   }

/*
* Generate a mask for runs of bits
*/
u32bit gen_mask(u32bit input)
   {
   u32bit mask = 0;

   for(u32bit j = 2; j != 31; ++j)
      {
      const u32bit region = (input >> (j-1)) & 0x07;

      if(region == 0x00 || region == 0x07)
         {
         const u32bit low = (j < 9) ? 0 : (j - 9);
         const u32bit high = (j < 23) ? j : 23;

         for(u32bit k = low; k != high; ++k)
            {
            const u32bit value = (input >> k) & 0x3FF;

            if(value == 0 || value == 0x3FF)
               {
               mask |= 1 << j;
               break;
               }
            }
         }
      }

   return mask;
   }

}

/*
* MARS Encryption
*/
void MARS::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0) + EK[0];
      u32bit B = load_le<u32bit>(in, 1) + EK[1];
      u32bit C = load_le<u32bit>(in, 2) + EK[2];
      u32bit D = load_le<u32bit>(in, 3) + EK[3];

      forward_mix(A, B, C, D);

      encrypt_round(A, B, C, D, EK[ 4], EK[ 5]);
      encrypt_round(B, C, D, A, EK[ 6], EK[ 7]);
      encrypt_round(C, D, A, B, EK[ 8], EK[ 9]);
      encrypt_round(D, A, B, C, EK[10], EK[11]);
      encrypt_round(A, B, C, D, EK[12], EK[13]);
      encrypt_round(B, C, D, A, EK[14], EK[15]);
      encrypt_round(C, D, A, B, EK[16], EK[17]);
      encrypt_round(D, A, B, C, EK[18], EK[19]);

      encrypt_round(A, D, C, B, EK[20], EK[21]);
      encrypt_round(B, A, D, C, EK[22], EK[23]);
      encrypt_round(C, B, A, D, EK[24], EK[25]);
      encrypt_round(D, C, B, A, EK[26], EK[27]);
      encrypt_round(A, D, C, B, EK[28], EK[29]);
      encrypt_round(B, A, D, C, EK[30], EK[31]);
      encrypt_round(C, B, A, D, EK[32], EK[33]);
      encrypt_round(D, C, B, A, EK[34], EK[35]);

      reverse_mix(A, B, C, D);

      A -= EK[36]; B -= EK[37]; C -= EK[38]; D -= EK[39];

      store_le(out, A, B, C, D);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* MARS Decryption
*/
void MARS::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 3) + EK[39];
      u32bit B = load_le<u32bit>(in, 2) + EK[38];
      u32bit C = load_le<u32bit>(in, 1) + EK[37];
      u32bit D = load_le<u32bit>(in, 0) + EK[36];

      forward_mix(A, B, C, D);

      decrypt_round(A, B, C, D, EK[35], EK[34]);
      decrypt_round(B, C, D, A, EK[33], EK[32]);
      decrypt_round(C, D, A, B, EK[31], EK[30]);
      decrypt_round(D, A, B, C, EK[29], EK[28]);
      decrypt_round(A, B, C, D, EK[27], EK[26]);
      decrypt_round(B, C, D, A, EK[25], EK[24]);
      decrypt_round(C, D, A, B, EK[23], EK[22]);
      decrypt_round(D, A, B, C, EK[21], EK[20]);

      decrypt_round(A, D, C, B, EK[19], EK[18]);
      decrypt_round(B, A, D, C, EK[17], EK[16]);
      decrypt_round(C, B, A, D, EK[15], EK[14]);
      decrypt_round(D, C, B, A, EK[13], EK[12]);
      decrypt_round(A, D, C, B, EK[11], EK[10]);
      decrypt_round(B, A, D, C, EK[ 9], EK[ 8]);
      decrypt_round(C, B, A, D, EK[ 7], EK[ 6]);
      decrypt_round(D, C, B, A, EK[ 5], EK[ 4]);

      reverse_mix(A, B, C, D);

      A -= EK[3]; B -= EK[2]; C -= EK[1]; D -= EK[0];

      store_le(out, D, C, B, A);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* MARS Key Schedule
*/
void MARS::key_schedule(const byte key[], size_t length)
   {
   SecureVector<u32bit> T(15);
   for(size_t i = 0; i != length / 4; ++i)
      T[i] = load_le<u32bit>(key, i);

   T[length / 4] = static_cast<u32bit>(length) / 4;

   for(u32bit i = 0; i != 4; ++i)
      {
      T[ 0] ^= rotate_left(T[ 8] ^ T[13], 3) ^ (i     );
      T[ 1] ^= rotate_left(T[ 9] ^ T[14], 3) ^ (i +  4);
      T[ 2] ^= rotate_left(T[10] ^ T[ 0], 3) ^ (i +  8);
      T[ 3] ^= rotate_left(T[11] ^ T[ 1], 3) ^ (i + 12);
      T[ 4] ^= rotate_left(T[12] ^ T[ 2], 3) ^ (i + 16);
      T[ 5] ^= rotate_left(T[13] ^ T[ 3], 3) ^ (i + 20);
      T[ 6] ^= rotate_left(T[14] ^ T[ 4], 3) ^ (i + 24);
      T[ 7] ^= rotate_left(T[ 0] ^ T[ 5], 3) ^ (i + 28);
      T[ 8] ^= rotate_left(T[ 1] ^ T[ 6], 3) ^ (i + 32);
      T[ 9] ^= rotate_left(T[ 2] ^ T[ 7], 3) ^ (i + 36);
      T[10] ^= rotate_left(T[ 3] ^ T[ 8], 3) ^ (i + 40);
      T[11] ^= rotate_left(T[ 4] ^ T[ 9], 3) ^ (i + 44);
      T[12] ^= rotate_left(T[ 5] ^ T[10], 3) ^ (i + 48);
      T[13] ^= rotate_left(T[ 6] ^ T[11], 3) ^ (i + 52);
      T[14] ^= rotate_left(T[ 7] ^ T[12], 3) ^ (i + 56);

      for(size_t j = 0; j != 4; ++j)
         {
         T[ 0] = rotate_left(T[ 0] + SBOX[T[14] % 512], 9);
         T[ 1] = rotate_left(T[ 1] + SBOX[T[ 0] % 512], 9);
         T[ 2] = rotate_left(T[ 2] + SBOX[T[ 1] % 512], 9);
         T[ 3] = rotate_left(T[ 3] + SBOX[T[ 2] % 512], 9);
         T[ 4] = rotate_left(T[ 4] + SBOX[T[ 3] % 512], 9);
         T[ 5] = rotate_left(T[ 5] + SBOX[T[ 4] % 512], 9);
         T[ 6] = rotate_left(T[ 6] + SBOX[T[ 5] % 512], 9);
         T[ 7] = rotate_left(T[ 7] + SBOX[T[ 6] % 512], 9);
         T[ 8] = rotate_left(T[ 8] + SBOX[T[ 7] % 512], 9);
         T[ 9] = rotate_left(T[ 9] + SBOX[T[ 8] % 512], 9);
         T[10] = rotate_left(T[10] + SBOX[T[ 9] % 512], 9);
         T[11] = rotate_left(T[11] + SBOX[T[10] % 512], 9);
         T[12] = rotate_left(T[12] + SBOX[T[11] % 512], 9);
         T[13] = rotate_left(T[13] + SBOX[T[12] % 512], 9);
         T[14] = rotate_left(T[14] + SBOX[T[13] % 512], 9);
         }

      EK[10*i + 0] = T[ 0];
      EK[10*i + 1] = T[ 4];
      EK[10*i + 2] = T[ 8];
      EK[10*i + 3] = T[12];
      EK[10*i + 4] = T[ 1];
      EK[10*i + 5] = T[ 5];
      EK[10*i + 6] = T[ 9];
      EK[10*i + 7] = T[13];
      EK[10*i + 8] = T[ 2];
      EK[10*i + 9] = T[ 6];
      }

   for(size_t i = 5; i != 37; i += 2)
      {
      const u32bit key3 = EK[i] & 3;
      EK[i] |= 3;
      EK[i] ^= rotate_left(SBOX[265 + key3], EK[i-1] % 32) & gen_mask(EK[i]);
      }
   }

}
/*
* MISTY1
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

static const byte MISTY1_SBOX_S7[128] = {
   0x1B, 0x32, 0x33, 0x5A, 0x3B, 0x10, 0x17, 0x54, 0x5B, 0x1A, 0x72, 0x73,
   0x6B, 0x2C, 0x66, 0x49, 0x1F, 0x24, 0x13, 0x6C, 0x37, 0x2E, 0x3F, 0x4A,
   0x5D, 0x0F, 0x40, 0x56, 0x25, 0x51, 0x1C, 0x04, 0x0B, 0x46, 0x20, 0x0D,
   0x7B, 0x35, 0x44, 0x42, 0x2B, 0x1E, 0x41, 0x14, 0x4B, 0x79, 0x15, 0x6F,
   0x0E, 0x55, 0x09, 0x36, 0x74, 0x0C, 0x67, 0x53, 0x28, 0x0A, 0x7E, 0x38,
   0x02, 0x07, 0x60, 0x29, 0x19, 0x12, 0x65, 0x2F, 0x30, 0x39, 0x08, 0x68,
   0x5F, 0x78, 0x2A, 0x4C, 0x64, 0x45, 0x75, 0x3D, 0x59, 0x48, 0x03, 0x57,
   0x7C, 0x4F, 0x62, 0x3C, 0x1D, 0x21, 0x5E, 0x27, 0x6A, 0x70, 0x4D, 0x3A,
   0x01, 0x6D, 0x6E, 0x63, 0x18, 0x77, 0x23, 0x05, 0x26, 0x76, 0x00, 0x31,
   0x2D, 0x7A, 0x7F, 0x61, 0x50, 0x22, 0x11, 0x06, 0x47, 0x16, 0x52, 0x4E,
   0x71, 0x3E, 0x69, 0x43, 0x34, 0x5C, 0x58, 0x7D };

static const u16bit MISTY1_SBOX_S9[512] = {
   0x01C3, 0x00CB, 0x0153, 0x019F, 0x01E3, 0x00E9, 0x00FB, 0x0035, 0x0181,
   0x00B9, 0x0117, 0x01EB, 0x0133, 0x0009, 0x002D, 0x00D3, 0x00C7, 0x014A,
   0x0037, 0x007E, 0x00EB, 0x0164, 0x0193, 0x01D8, 0x00A3, 0x011E, 0x0055,
   0x002C, 0x001D, 0x01A2, 0x0163, 0x0118, 0x014B, 0x0152, 0x01D2, 0x000F,
   0x002B, 0x0030, 0x013A, 0x00E5, 0x0111, 0x0138, 0x018E, 0x0063, 0x00E3,
   0x00C8, 0x01F4, 0x001B, 0x0001, 0x009D, 0x00F8, 0x01A0, 0x016D, 0x01F3,
   0x001C, 0x0146, 0x007D, 0x00D1, 0x0082, 0x01EA, 0x0183, 0x012D, 0x00F4,
   0x019E, 0x01D3, 0x00DD, 0x01E2, 0x0128, 0x01E0, 0x00EC, 0x0059, 0x0091,
   0x0011, 0x012F, 0x0026, 0x00DC, 0x00B0, 0x018C, 0x010F, 0x01F7, 0x00E7,
   0x016C, 0x00B6, 0x00F9, 0x00D8, 0x0151, 0x0101, 0x014C, 0x0103, 0x00B8,
   0x0154, 0x012B, 0x01AE, 0x0017, 0x0071, 0x000C, 0x0047, 0x0058, 0x007F,
   0x01A4, 0x0134, 0x0129, 0x0084, 0x015D, 0x019D, 0x01B2, 0x01A3, 0x0048,
   0x007C, 0x0051, 0x01CA, 0x0023, 0x013D, 0x01A7, 0x0165, 0x003B, 0x0042,
   0x00DA, 0x0192, 0x00CE, 0x00C1, 0x006B, 0x009F, 0x01F1, 0x012C, 0x0184,
   0x00FA, 0x0196, 0x01E1, 0x0169, 0x017D, 0x0031, 0x0180, 0x010A, 0x0094,
   0x01DA, 0x0186, 0x013E, 0x011C, 0x0060, 0x0175, 0x01CF, 0x0067, 0x0119,
   0x0065, 0x0068, 0x0099, 0x0150, 0x0008, 0x0007, 0x017C, 0x00B7, 0x0024,
   0x0019, 0x00DE, 0x0127, 0x00DB, 0x00E4, 0x01A9, 0x0052, 0x0109, 0x0090,
   0x019C, 0x01C1, 0x0028, 0x01B3, 0x0135, 0x016A, 0x0176, 0x00DF, 0x01E5,
   0x0188, 0x00C5, 0x016E, 0x01DE, 0x01B1, 0x00C3, 0x01DF, 0x0036, 0x00EE,
   0x01EE, 0x00F0, 0x0093, 0x0049, 0x009A, 0x01B6, 0x0069, 0x0081, 0x0125,
   0x000B, 0x005E, 0x00B4, 0x0149, 0x01C7, 0x0174, 0x003E, 0x013B, 0x01B7,
   0x008E, 0x01C6, 0x00AE, 0x0010, 0x0095, 0x01EF, 0x004E, 0x00F2, 0x01FD,
   0x0085, 0x00FD, 0x00F6, 0x00A0, 0x016F, 0x0083, 0x008A, 0x0156, 0x009B,
   0x013C, 0x0107, 0x0167, 0x0098, 0x01D0, 0x01E9, 0x0003, 0x01FE, 0x00BD,
   0x0122, 0x0089, 0x00D2, 0x018F, 0x0012, 0x0033, 0x006A, 0x0142, 0x00ED,
   0x0170, 0x011B, 0x00E2, 0x014F, 0x0158, 0x0131, 0x0147, 0x005D, 0x0113,
   0x01CD, 0x0079, 0x0161, 0x01A5, 0x0179, 0x009E, 0x01B4, 0x00CC, 0x0022,
   0x0132, 0x001A, 0x00E8, 0x0004, 0x0187, 0x01ED, 0x0197, 0x0039, 0x01BF,
   0x01D7, 0x0027, 0x018B, 0x00C6, 0x009C, 0x00D0, 0x014E, 0x006C, 0x0034,
   0x01F2, 0x006E, 0x00CA, 0x0025, 0x00BA, 0x0191, 0x00FE, 0x0013, 0x0106,
   0x002F, 0x01AD, 0x0172, 0x01DB, 0x00C0, 0x010B, 0x01D6, 0x00F5, 0x01EC,
   0x010D, 0x0076, 0x0114, 0x01AB, 0x0075, 0x010C, 0x01E4, 0x0159, 0x0054,
   0x011F, 0x004B, 0x00C4, 0x01BE, 0x00F7, 0x0029, 0x00A4, 0x000E, 0x01F0,
   0x0077, 0x004D, 0x017A, 0x0086, 0x008B, 0x00B3, 0x0171, 0x00BF, 0x010E,
   0x0104, 0x0097, 0x015B, 0x0160, 0x0168, 0x00D7, 0x00BB, 0x0066, 0x01CE,
   0x00FC, 0x0092, 0x01C5, 0x006F, 0x0016, 0x004A, 0x00A1, 0x0139, 0x00AF,
   0x00F1, 0x0190, 0x000A, 0x01AA, 0x0143, 0x017B, 0x0056, 0x018D, 0x0166,
   0x00D4, 0x01FB, 0x014D, 0x0194, 0x019A, 0x0087, 0x01F8, 0x0123, 0x00A7,
   0x01B8, 0x0141, 0x003C, 0x01F9, 0x0140, 0x002A, 0x0155, 0x011A, 0x01A1,
   0x0198, 0x00D5, 0x0126, 0x01AF, 0x0061, 0x012E, 0x0157, 0x01DC, 0x0072,
   0x018A, 0x00AA, 0x0096, 0x0115, 0x00EF, 0x0045, 0x007B, 0x008D, 0x0145,
   0x0053, 0x005F, 0x0178, 0x00B2, 0x002E, 0x0020, 0x01D5, 0x003F, 0x01C9,
   0x01E7, 0x01AC, 0x0044, 0x0038, 0x0014, 0x00B1, 0x016B, 0x00AB, 0x00B5,
   0x005A, 0x0182, 0x01C8, 0x01D4, 0x0018, 0x0177, 0x0064, 0x00CF, 0x006D,
   0x0100, 0x0199, 0x0130, 0x015A, 0x0005, 0x0120, 0x01BB, 0x01BD, 0x00E0,
   0x004F, 0x00D6, 0x013F, 0x01C4, 0x012A, 0x0015, 0x0006, 0x00FF, 0x019B,
   0x00A6, 0x0043, 0x0088, 0x0050, 0x015F, 0x01E8, 0x0121, 0x0073, 0x017E,
   0x00BC, 0x00C2, 0x00C9, 0x0173, 0x0189, 0x01F5, 0x0074, 0x01CC, 0x01E6,
   0x01A8, 0x0195, 0x001F, 0x0041, 0x000D, 0x01BA, 0x0032, 0x003D, 0x01D1,
   0x0080, 0x00A8, 0x0057, 0x01B9, 0x0162, 0x0148, 0x00D9, 0x0105, 0x0062,
   0x007A, 0x0021, 0x01FF, 0x0112, 0x0108, 0x01C0, 0x00A9, 0x011D, 0x01B0,
   0x01A6, 0x00CD, 0x00F3, 0x005C, 0x0102, 0x005B, 0x01D9, 0x0144, 0x01F6,
   0x00AD, 0x00A5, 0x003A, 0x01CB, 0x0136, 0x017F, 0x0046, 0x00E1, 0x001E,
   0x01DD, 0x00E6, 0x0137, 0x01FA, 0x0185, 0x008C, 0x008F, 0x0040, 0x01B5,
   0x00BE, 0x0078, 0x0000, 0x00AC, 0x0110, 0x015E, 0x0124, 0x0002, 0x01BC,
   0x00A2, 0x00EA, 0x0070, 0x01FC, 0x0116, 0x015C, 0x004C, 0x01C2 };

/*
* MISTY1 FI Function
*/
u16bit FI(u16bit input, u16bit key7, u16bit key9)
   {
   u16bit D9 = input >> 7, D7 = input & 0x7F;
   D9 = MISTY1_SBOX_S9[D9] ^ D7;
   D7 = (MISTY1_SBOX_S7[D7] ^ key7 ^ D9) & 0x7F;
   D9 = MISTY1_SBOX_S9[D9 ^ key9] ^ D7;
   return static_cast<u16bit>((D7 << 9) | D9);
   }

}

/*
* MISTY1 Encryption
*/
void MISTY1::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit B0 = load_be<u16bit>(in, 0);
      u16bit B1 = load_be<u16bit>(in, 1);
      u16bit B2 = load_be<u16bit>(in, 2);
      u16bit B3 = load_be<u16bit>(in, 3);

      for(size_t j = 0; j != 12; j += 3)
         {
         const u16bit* RK = &EK[8 * j];

         B1 ^= B0 & RK[0];
         B0 ^= B1 | RK[1];
         B3 ^= B2 & RK[2];
         B2 ^= B3 | RK[3];

         u32bit T0, T1;

         T0  = FI(B0 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B1;
         T1  = FI(B1 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0;
         T0  = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1;

         B2 ^= T1 ^ RK[13];
         B3 ^= T0;

         T0  = FI(B2 ^ RK[14], RK[15], RK[16]) ^ B3;
         T1  = FI(B3 ^ RK[17], RK[18], RK[19]) ^ T0;
         T0  = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1;

         B0 ^= T1 ^ RK[23];
         B1 ^= T0;
         }

      B1 ^= B0 & EK[96];
      B0 ^= B1 | EK[97];
      B3 ^= B2 & EK[98];
      B2 ^= B3 | EK[99];

      store_be(out, B2, B3, B0, B1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* MISTY1 Decryption
*/
void MISTY1::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit B0 = load_be<u16bit>(in, 2);
      u16bit B1 = load_be<u16bit>(in, 3);
      u16bit B2 = load_be<u16bit>(in, 0);
      u16bit B3 = load_be<u16bit>(in, 1);

      for(size_t j = 0; j != 12; j += 3)
         {
         const u16bit* RK = &DK[8 * j];

         B2 ^= B3 | RK[0];
         B3 ^= B2 & RK[1];
         B0 ^= B1 | RK[2];
         B1 ^= B0 & RK[3];

         u32bit T0, T1;

         T0  = FI(B2 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B3;
         T1  = FI(B3 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0;
         T0  = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1;

         B0 ^= T1 ^ RK[13];
         B1 ^= T0;

         T0  = FI(B0 ^ RK[14], RK[15], RK[16]) ^ B1;
         T1  = FI(B1 ^ RK[17], RK[18], RK[19]) ^ T0;
         T0  = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1;

         B2 ^= T1 ^ RK[23];
         B3 ^= T0;
         }

      B2 ^= B3 | DK[96];
      B3 ^= B2 & DK[97];
      B0 ^= B1 | DK[98];
      B1 ^= B0 & DK[99];

      store_be(out, B0, B1, B2, B3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* MISTY1 Key Schedule
*/
void MISTY1::key_schedule(const byte key[], size_t length)
   {
   SecureVector<u16bit> KS(32);
   for(size_t i = 0; i != length / 2; ++i)
      KS[i] = load_be<u16bit>(key, i);

   for(size_t i = 0; i != 8; ++i)
      {
      KS[i+ 8] = FI(KS[i], KS[(i+1) % 8] >> 9, KS[(i+1) % 8] & 0x1FF);
      KS[i+16] = KS[i+8] >> 9;
      KS[i+24] = KS[i+8] & 0x1FF;
      }

   /*
   * Precomputed indexes for the orderings of the subkeys (MISTY1 reuses
   * values)
   */
   static const byte EK_ORDER[100] = {
      0x00, 0x0E, 0x0A, 0x04, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13,
      0x1B, 0x04, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05,
      0x01, 0x0F, 0x0B, 0x05, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15,
      0x1D, 0x06, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07,
      0x02, 0x08, 0x0C, 0x06, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17,
      0x1F, 0x00, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01,
      0x03, 0x09, 0x0D, 0x07, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11,
      0x19, 0x02, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03,
      0x04, 0x0A, 0x0E, 0x00 };

   static const byte DK_ORDER[100] = {
      0x00, 0x0E, 0x0A, 0x04, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12,
      0x1A, 0x03, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02,
      0x07, 0x0D, 0x09, 0x03, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10,
      0x18, 0x01, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00,
      0x06, 0x0C, 0x08, 0x02, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16,
      0x1E, 0x07, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06,
      0x05, 0x0B, 0x0F, 0x01, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14,
      0x1C, 0x05, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04,
      0x04, 0x0A, 0x0E, 0x00 };

   for(size_t i = 0; i != 100; ++i)
      {
      EK[i] = KS[EK_ORDER[i]];
      DK[i] = KS[DK_ORDER[i]];
      }
   }

/*
* MISTY1 Constructor
*/
MISTY1::MISTY1(size_t rounds) : EK(100), DK(100)
   {
   if(rounds != 8)
      throw Invalid_Argument("MISTY1: Invalid number of rounds: "
                             + to_string(rounds));
   }

}
/*
* Noekeon
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


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);
   }

}
/*
* Noekeon in SIMD
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Noekeon's Theta Operation
*/
#define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3)  \
   do {                                                 \
      SIMD_32 T = A0 ^ A2;                              \
      SIMD_32 T_l8 = T;                                 \
      SIMD_32 T_r8 = T;                                 \
      T_l8.rotate_left(8);                              \
      T_r8.rotate_right(8);                             \
      T ^= T_l8;                                        \
      T ^= T_r8;                                        \
      A1 ^= T;                                          \
      A3 ^= T;                                          \
                                                        \
      A0 ^= K0;                                         \
      A1 ^= K1;                                         \
      A2 ^= K2;                                         \
      A3 ^= K3;                                         \
                                                        \
      T = A1 ^ A3;                                      \
      T_l8 = T;                                         \
      T_r8 = T;                                         \
      T_l8.rotate_left(8);                              \
      T_r8.rotate_right(8);                             \
      T ^= T_l8;                                        \
      T ^= T_r8;                                        \
      A0 ^= T;                                          \
      A2 ^= T;                                          \
      } while(0)

/*
* Noekeon's Gamma S-Box Layer
*/
#define NOK_SIMD_GAMMA(A0, A1, A2, A3)                                  \
   do                                                                   \
      {                                                                 \
      A1 ^= A3.andc(~A2);                                               \
      A0 ^= A2 & A1;                                                    \
                                                                        \
      SIMD_32 T = A3;                                                   \
      A3 = A0;                                                          \
      A0 = T;                                                           \
                                                                        \
      A2 ^= A0 ^ A1 ^ A3;                                               \
                                                                        \
      A1 ^= A3.andc(~A2);                                               \
      A0 ^= A2 & A1;                                                    \
      } while(0)

/*
* Noekeon Encryption
*/
void Noekeon_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const SecureVector<u32bit>& EK = this->get_EK();

   SIMD_32 K0 = SIMD_32(EK[0]);
   SIMD_32 K1 = SIMD_32(EK[1]);
   SIMD_32 K2 = SIMD_32(EK[2]);
   SIMD_32 K3 = SIMD_32(EK[3]);

   while(blocks >= 4)
      {
      SIMD_32 A0 = SIMD_32::load_be(in     );
      SIMD_32 A1 = SIMD_32::load_be(in + 16);
      SIMD_32 A2 = SIMD_32::load_be(in + 32);
      SIMD_32 A3 = SIMD_32::load_be(in + 48);

      SIMD_32::transpose(A0, A1, A2, A3);

      for(size_t i = 0; i != 16; ++i)
         {
         A0 ^= SIMD_32(RC[i]);

         NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3);

         A1.rotate_left(1);
         A2.rotate_left(5);
         A3.rotate_left(2);

         NOK_SIMD_GAMMA(A0, A1, A2, A3);

         A1.rotate_right(1);
         A2.rotate_right(5);
         A3.rotate_right(2);
         }

      A0 ^= SIMD_32(RC[16]);
      NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3);

      SIMD_32::transpose(A0, A1, A2, A3);

      A0.store_be(out);
      A1.store_be(out + 16);
      A2.store_be(out + 32);
      A3.store_be(out + 48);

      in += 64;
      out += 64;
      blocks -= 4;
      }

   if(blocks)
     Noekeon::encrypt_n(in, out, blocks);
   }

/*
* Noekeon Encryption
*/
void Noekeon_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const SecureVector<u32bit>& DK = this->get_DK();

   SIMD_32 K0 = SIMD_32(DK[0]);
   SIMD_32 K1 = SIMD_32(DK[1]);
   SIMD_32 K2 = SIMD_32(DK[2]);
   SIMD_32 K3 = SIMD_32(DK[3]);

   while(blocks >= 4)
      {
      SIMD_32 A0 = SIMD_32::load_be(in     );
      SIMD_32 A1 = SIMD_32::load_be(in + 16);
      SIMD_32 A2 = SIMD_32::load_be(in + 32);
      SIMD_32 A3 = SIMD_32::load_be(in + 48);

      SIMD_32::transpose(A0, A1, A2, A3);

      for(size_t i = 0; i != 16; ++i)
         {
         NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3);

         A0 ^= SIMD_32(RC[16-i]);

         A1.rotate_left(1);
         A2.rotate_left(5);
         A3.rotate_left(2);

         NOK_SIMD_GAMMA(A0, A1, A2, A3);

         A1.rotate_right(1);
         A2.rotate_right(5);
         A3.rotate_right(2);
         }

      NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3);
      A0 ^= SIMD_32(RC[0]);

      SIMD_32::transpose(A0, A1, A2, A3);

      A0.store_be(out);
      A1.store_be(out + 16);
      A2.store_be(out + 32);
      A3.store_be(out + 48);

      in += 64;
      out += 64;
      blocks -= 4;
      }

   if(blocks)
     Noekeon::decrypt_n(in, out, blocks);
   }

}
/*
* RC2
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* RC2 Encryption
*/
void RC2::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit R0 = load_le<u16bit>(in, 0);
      u16bit R1 = load_le<u16bit>(in, 1);
      u16bit R2 = load_le<u16bit>(in, 2);
      u16bit R3 = load_le<u16bit>(in, 3);

      for(size_t j = 0; j != 16; ++j)
         {
         R0 += (R1 & ~R3) + (R2 & R3) + K[4*j];
         R0 = rotate_left(R0, 1);

         R1 += (R2 & ~R0) + (R3 & R0) + K[4*j + 1];
         R1 = rotate_left(R1, 2);

         R2 += (R3 & ~R1) + (R0 & R1) + K[4*j + 2];
         R2 = rotate_left(R2, 3);

         R3 += (R0 & ~R2) + (R1 & R2) + K[4*j + 3];
         R3 = rotate_left(R3, 5);

         if(j == 4 || j == 10)
            {
            R0 += K[R3 % 64];
            R1 += K[R0 % 64];
            R2 += K[R1 % 64];
            R3 += K[R2 % 64];
            }
         }

      store_le(out, R0, R1, R2, R3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC2 Decryption
*/
void RC2::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit R0 = load_le<u16bit>(in, 0);
      u16bit R1 = load_le<u16bit>(in, 1);
      u16bit R2 = load_le<u16bit>(in, 2);
      u16bit R3 = load_le<u16bit>(in, 3);

      for(size_t j = 0; j != 16; ++j)
         {
         R3 = rotate_right(R3, 5);
         R3 -= (R0 & ~R2) + (R1 & R2) + K[63 - (4*j + 0)];

         R2 = rotate_right(R2, 3);
         R2 -= (R3 & ~R1) + (R0 & R1) + K[63 - (4*j + 1)];

         R1 = rotate_right(R1, 2);
         R1 -= (R2 & ~R0) + (R3 & R0) + K[63 - (4*j + 2)];

         R0 = rotate_right(R0, 1);
         R0 -= (R1 & ~R3) + (R2 & R3) + K[63 - (4*j + 3)];

         if(j == 4 || j == 10)
            {
            R3 -= K[R2 % 64];
            R2 -= K[R1 % 64];
            R1 -= K[R0 % 64];
            R0 -= K[R3 % 64];
            }
         }

      store_le(out, R0, R1, R2, R3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC2 Key Schedule
*/
void RC2::key_schedule(const byte key[], size_t length)
   {
   static const byte TABLE[256] = {
      0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79,
      0x4A, 0xA0, 0xD8, 0x9D, 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
      0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 0x17, 0x9A, 0x59, 0xF5,
      0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
      0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22,
      0x5C, 0x6B, 0x4E, 0x82, 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
      0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 0x12, 0x75, 0xCA, 0x1F,
      0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
      0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B,
      0xBC, 0x94, 0x43, 0x03, 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
      0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 0x08, 0xE8, 0xEA, 0xDE,
      0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
      0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E,
      0x04, 0x18, 0xA4, 0xEC, 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
      0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 0x99, 0x7C, 0x3A, 0x85,
      0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
      0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10,
      0x67, 0x6C, 0xBA, 0xC9, 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
      0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 0x0D, 0x38, 0x34, 0x1B,
      0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
      0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68,
      0xFE, 0x7F, 0xC1, 0xAD };

   SecureVector<byte> L(128);
   L.copy(key, length);

   for(size_t i = length; i != 128; ++i)
      L[i] = TABLE[(L[i-1] + L[i-length]) % 256];

   L[128-length] = TABLE[L[128-length]];

   for(s32bit i = 127-length; i >= 0; --i)
      L[i] = TABLE[L[i+1] ^ L[i+length]];

   load_le<u16bit>(&K[0], &L[0], 64);
   }

/*
* Return the code of the effective key bits
*/
byte RC2::EKB_code(size_t ekb)
   {
   const byte EKB[256] = {
      0xBD, 0x56, 0xEA, 0xF2, 0xA2, 0xF1, 0xAC, 0x2A, 0xB0, 0x93, 0xD1, 0x9C,
      0x1B, 0x33, 0xFD, 0xD0, 0x30, 0x04, 0xB6, 0xDC, 0x7D, 0xDF, 0x32, 0x4B,
      0xF7, 0xCB, 0x45, 0x9B, 0x31, 0xBB, 0x21, 0x5A, 0x41, 0x9F, 0xE1, 0xD9,
      0x4A, 0x4D, 0x9E, 0xDA, 0xA0, 0x68, 0x2C, 0xC3, 0x27, 0x5F, 0x80, 0x36,
      0x3E, 0xEE, 0xFB, 0x95, 0x1A, 0xFE, 0xCE, 0xA8, 0x34, 0xA9, 0x13, 0xF0,
      0xA6, 0x3F, 0xD8, 0x0C, 0x78, 0x24, 0xAF, 0x23, 0x52, 0xC1, 0x67, 0x17,
      0xF5, 0x66, 0x90, 0xE7, 0xE8, 0x07, 0xB8, 0x60, 0x48, 0xE6, 0x1E, 0x53,
      0xF3, 0x92, 0xA4, 0x72, 0x8C, 0x08, 0x15, 0x6E, 0x86, 0x00, 0x84, 0xFA,
      0xF4, 0x7F, 0x8A, 0x42, 0x19, 0xF6, 0xDB, 0xCD, 0x14, 0x8D, 0x50, 0x12,
      0xBA, 0x3C, 0x06, 0x4E, 0xEC, 0xB3, 0x35, 0x11, 0xA1, 0x88, 0x8E, 0x2B,
      0x94, 0x99, 0xB7, 0x71, 0x74, 0xD3, 0xE4, 0xBF, 0x3A, 0xDE, 0x96, 0x0E,
      0xBC, 0x0A, 0xED, 0x77, 0xFC, 0x37, 0x6B, 0x03, 0x79, 0x89, 0x62, 0xC6,
      0xD7, 0xC0, 0xD2, 0x7C, 0x6A, 0x8B, 0x22, 0xA3, 0x5B, 0x05, 0x5D, 0x02,
      0x75, 0xD5, 0x61, 0xE3, 0x18, 0x8F, 0x55, 0x51, 0xAD, 0x1F, 0x0B, 0x5E,
      0x85, 0xE5, 0xC2, 0x57, 0x63, 0xCA, 0x3D, 0x6C, 0xB4, 0xC5, 0xCC, 0x70,
      0xB2, 0x91, 0x59, 0x0D, 0x47, 0x20, 0xC8, 0x4F, 0x58, 0xE0, 0x01, 0xE2,
      0x16, 0x38, 0xC4, 0x6F, 0x3B, 0x0F, 0x65, 0x46, 0xBE, 0x7E, 0x2D, 0x7B,
      0x82, 0xF9, 0x40, 0xB5, 0x1D, 0x73, 0xF8, 0xEB, 0x26, 0xC7, 0x87, 0x97,
      0x25, 0x54, 0xB1, 0x28, 0xAA, 0x98, 0x9D, 0xA5, 0x64, 0x6D, 0x7A, 0xD4,
      0x10, 0x81, 0x44, 0xEF, 0x49, 0xD6, 0xAE, 0x2E, 0xDD, 0x76, 0x5C, 0x2F,
      0xA7, 0x1C, 0xC9, 0x09, 0x69, 0x9A, 0x83, 0xCF, 0x29, 0x39, 0xB9, 0xE9,
      0x4C, 0xFF, 0x43, 0xAB };

   if(ekb < 256)
      return EKB[ekb];
   else
      throw Encoding_Error("RC2::EKB_code: EKB is too large");
   }

}
/*
* RC5
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* RC5 Encryption
*/
void RC5::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t rounds = (S.size() - 2) / 2;

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0);
      u32bit B = load_le<u32bit>(in, 1);

      A += S[0]; B += S[1];
      for(size_t j = 0; j != rounds; j += 4)
         {
         A = rotate_left(A ^ B, B % 32) + S[2*j+2];
         B = rotate_left(B ^ A, A % 32) + S[2*j+3];

         A = rotate_left(A ^ B, B % 32) + S[2*j+4];
         B = rotate_left(B ^ A, A % 32) + S[2*j+5];

         A = rotate_left(A ^ B, B % 32) + S[2*j+6];
         B = rotate_left(B ^ A, A % 32) + S[2*j+7];

         A = rotate_left(A ^ B, B % 32) + S[2*j+8];
         B = rotate_left(B ^ A, A % 32) + S[2*j+9];
         }

      store_le(out, A, B);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC5 Decryption
*/
void RC5::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t rounds = (S.size() - 2) / 2;

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0);
      u32bit B = load_le<u32bit>(in, 1);

      for(size_t j = rounds; j != 0; j -= 4)
         {
         B = rotate_right(B - S[2*j+1], A % 32) ^ A;
         A = rotate_right(A - S[2*j  ], B % 32) ^ B;

         B = rotate_right(B - S[2*j-1], A % 32) ^ A;
         A = rotate_right(A - S[2*j-2], B % 32) ^ B;

         B = rotate_right(B - S[2*j-3], A % 32) ^ A;
         A = rotate_right(A - S[2*j-4], B % 32) ^ B;

         B = rotate_right(B - S[2*j-5], A % 32) ^ A;
         A = rotate_right(A - S[2*j-6], B % 32) ^ B;
         }
      B -= S[1]; A -= S[0];

      store_le(out, A, B);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC5 Key Schedule
*/
void RC5::key_schedule(const byte key[], size_t length)
   {
   const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1);
   const size_t MIX_ROUNDS     = 3 * std::max(WORD_KEYLENGTH, S.size());

   S[0] = 0xB7E15163;
   for(size_t i = 1; i != S.size(); ++i)
      S[i] = S[i-1] + 0x9E3779B9;

   SecureVector<u32bit> K(8);

   for(s32bit i = length-1; i >= 0; --i)
      K[i/4] = (K[i/4] << 8) + key[i];

   u32bit A = 0, B = 0;

   for(size_t i = 0; i != MIX_ROUNDS; ++i)
      {
      A = rotate_left(S[i % S.size()] + A + B, 3);
      B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32);
      S[i % S.size()] = A;
      K[i % WORD_KEYLENGTH] = B;
      }
   }

/*
* Return the name of this type
*/
std::string RC5::name() const
   {
   return "RC5(" + to_string(get_rounds()) + ")";
   }

/*
* RC5 Constructor
*/
RC5::RC5(size_t rounds)
   {
   if(rounds < 8 || rounds > 32 || (rounds % 4 != 0))
      throw Invalid_Argument("RC5: Invalid number of rounds " +
                             to_string(rounds));

   S.resize(2*rounds + 2);
   }

}
/*
* RC6
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* RC6 Encryption
*/
void RC6::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0);
      u32bit B = load_le<u32bit>(in, 1);
      u32bit C = load_le<u32bit>(in, 2);
      u32bit D = load_le<u32bit>(in, 3);

      B += S[0]; D += S[1];

      for(size_t j = 0; j != 20; j += 4)
         {
         u32bit T1, T2;

         T1 = rotate_left(B*(2*B+1), 5);
         T2 = rotate_left(D*(2*D+1), 5);
         A = rotate_left(A ^ T1, T2 % 32) + S[2*j+2];
         C = rotate_left(C ^ T2, T1 % 32) + S[2*j+3];

         T1 = rotate_left(C*(2*C+1), 5);
         T2 = rotate_left(A*(2*A+1), 5);
         B = rotate_left(B ^ T1, T2 % 32) + S[2*j+4];
         D = rotate_left(D ^ T2, T1 % 32) + S[2*j+5];

         T1 = rotate_left(D*(2*D+1), 5);
         T2 = rotate_left(B*(2*B+1), 5);
         C = rotate_left(C ^ T1, T2 % 32) + S[2*j+6];
         A = rotate_left(A ^ T2, T1 % 32) + S[2*j+7];

         T1 = rotate_left(A*(2*A+1), 5);
         T2 = rotate_left(C*(2*C+1), 5);
         D = rotate_left(D ^ T1, T2 % 32) + S[2*j+8];
         B = rotate_left(B ^ T2, T1 % 32) + S[2*j+9];
         }

      A += S[42]; C += S[43];

      store_le(out, A, B, C, D);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC6 Decryption
*/
void RC6::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0);
      u32bit B = load_le<u32bit>(in, 1);
      u32bit C = load_le<u32bit>(in, 2);
      u32bit D = load_le<u32bit>(in, 3);

      C -= S[43]; A -= S[42];

      for(size_t j = 0; j != 20; j += 4)
         {
         u32bit T1, T2;

         T1 = rotate_left(A*(2*A+1), 5);
         T2 = rotate_left(C*(2*C+1), 5);
         B = rotate_right(B - S[41 - 2*j], T1 % 32) ^ T2;
         D = rotate_right(D - S[40 - 2*j], T2 % 32) ^ T1;

         T1 = rotate_left(D*(2*D+1), 5);
         T2 = rotate_left(B*(2*B+1), 5);
         A = rotate_right(A - S[39 - 2*j], T1 % 32) ^ T2;
         C = rotate_right(C - S[38 - 2*j], T2 % 32) ^ T1;

         T1 = rotate_left(C*(2*C+1), 5);
         T2 = rotate_left(A*(2*A+1), 5);
         D = rotate_right(D - S[37 - 2*j], T1 % 32) ^ T2;
         B = rotate_right(B - S[36 - 2*j], T2 % 32) ^ T1;

         T1 = rotate_left(B*(2*B+1), 5);
         T2 = rotate_left(D*(2*D+1), 5);
         C = rotate_right(C - S[35 - 2*j], T1 % 32) ^ T2;
         A = rotate_right(A - S[34 - 2*j], T2 % 32) ^ T1;
         }

      D -= S[1]; B -= S[0];

      store_le(out, A, B, C, D);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* RC6 Key Schedule
*/
void RC6::key_schedule(const byte key[], size_t length)
   {
   const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1);
   const size_t MIX_ROUNDS     = 3 * std::max(WORD_KEYLENGTH, S.size());

   S[0] = 0xB7E15163;
   for(size_t i = 1; i != S.size(); ++i)
      S[i] = S[i-1] + 0x9E3779B9;

   SecureVector<u32bit> K(8);

   for(s32bit i = length-1; i >= 0; --i)
      K[i/4] = (K[i/4] << 8) + key[i];

   u32bit A = 0, B = 0;
   for(size_t i = 0; i != MIX_ROUNDS; ++i)
      {
      A = rotate_left(S[i % S.size()] + A + B, 3);
      B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32);
      S[i % S.size()] = A;
      K[i % WORD_KEYLENGTH] = B;
      }
   }

}
/*
* SAFER-SK
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

const byte EXP[256] = {
   0x01, 0x2D, 0xE2, 0x93, 0xBE, 0x45, 0x15, 0xAE, 0x78, 0x03, 0x87, 0xA4,
   0xB8, 0x38, 0xCF, 0x3F, 0x08, 0x67, 0x09, 0x94, 0xEB, 0x26, 0xA8, 0x6B,
   0xBD, 0x18, 0x34, 0x1B, 0xBB, 0xBF, 0x72, 0xF7, 0x40, 0x35, 0x48, 0x9C,
   0x51, 0x2F, 0x3B, 0x55, 0xE3, 0xC0, 0x9F, 0xD8, 0xD3, 0xF3, 0x8D, 0xB1,
   0xFF, 0xA7, 0x3E, 0xDC, 0x86, 0x77, 0xD7, 0xA6, 0x11, 0xFB, 0xF4, 0xBA,
   0x92, 0x91, 0x64, 0x83, 0xF1, 0x33, 0xEF, 0xDA, 0x2C, 0xB5, 0xB2, 0x2B,
   0x88, 0xD1, 0x99, 0xCB, 0x8C, 0x84, 0x1D, 0x14, 0x81, 0x97, 0x71, 0xCA,
   0x5F, 0xA3, 0x8B, 0x57, 0x3C, 0x82, 0xC4, 0x52, 0x5C, 0x1C, 0xE8, 0xA0,
   0x04, 0xB4, 0x85, 0x4A, 0xF6, 0x13, 0x54, 0xB6, 0xDF, 0x0C, 0x1A, 0x8E,
   0xDE, 0xE0, 0x39, 0xFC, 0x20, 0x9B, 0x24, 0x4E, 0xA9, 0x98, 0x9E, 0xAB,
   0xF2, 0x60, 0xD0, 0x6C, 0xEA, 0xFA, 0xC7, 0xD9, 0x00, 0xD4, 0x1F, 0x6E,
   0x43, 0xBC, 0xEC, 0x53, 0x89, 0xFE, 0x7A, 0x5D, 0x49, 0xC9, 0x32, 0xC2,
   0xF9, 0x9A, 0xF8, 0x6D, 0x16, 0xDB, 0x59, 0x96, 0x44, 0xE9, 0xCD, 0xE6,
   0x46, 0x42, 0x8F, 0x0A, 0xC1, 0xCC, 0xB9, 0x65, 0xB0, 0xD2, 0xC6, 0xAC,
   0x1E, 0x41, 0x62, 0x29, 0x2E, 0x0E, 0x74, 0x50, 0x02, 0x5A, 0xC3, 0x25,
   0x7B, 0x8A, 0x2A, 0x5B, 0xF0, 0x06, 0x0D, 0x47, 0x6F, 0x70, 0x9D, 0x7E,
   0x10, 0xCE, 0x12, 0x27, 0xD5, 0x4C, 0x4F, 0xD6, 0x79, 0x30, 0x68, 0x36,
   0x75, 0x7D, 0xE4, 0xED, 0x80, 0x6A, 0x90, 0x37, 0xA2, 0x5E, 0x76, 0xAA,
   0xC5, 0x7F, 0x3D, 0xAF, 0xA5, 0xE5, 0x19, 0x61, 0xFD, 0x4D, 0x7C, 0xB7,
   0x0B, 0xEE, 0xAD, 0x4B, 0x22, 0xF5, 0xE7, 0x73, 0x23, 0x21, 0xC8, 0x05,
   0xE1, 0x66, 0xDD, 0xB3, 0x58, 0x69, 0x63, 0x56, 0x0F, 0xA1, 0x31, 0x95,
   0x17, 0x07, 0x3A, 0x28 };

const byte LOG[512] = {
   0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD, 0x10, 0x12, 0x9F, 0xE4,
   0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65, 0x4F, 0x06, 0x94, 0xFC,
   0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82, 0x70, 0xED, 0xE8, 0xEC,
   0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47, 0x44, 0x01, 0xAC, 0x25,
   0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3, 0x0D, 0x6E, 0xFE, 0x26,
   0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84, 0x98, 0x05, 0x9C, 0xBB,
   0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6, 0xAF, 0x24, 0x5B, 0x87,
   0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7, 0x5C, 0x8B, 0xD5, 0x54,
   0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11, 0xCA, 0xF5, 0xD1, 0x17,
   0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB, 0xAE, 0xCC, 0xD6, 0x35,
   0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9, 0xD0, 0x50, 0x59, 0x3F,
   0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56, 0x4C, 0x2E, 0x6B, 0x9E,
   0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51, 0x75, 0x4A, 0x91, 0x71,
   0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55, 0x0B, 0xDC, 0x37, 0x31,
   0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB, 0xA4, 0x2F, 0x46, 0xF3,
   0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C, 0x85, 0x18, 0x04, 0x1D,
   0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E, 0xEE, 0x8D, 0x53, 0x4B,
   0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C, 0x81, 0xC4, 0xC7, 0x36,
   0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68, 0x6D, 0xF0, 0x02, 0x28,
   0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14, 0x86, 0xCF, 0xE5, 0x42,
   0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F, 0x92, 0x90, 0x7D, 0x39,
   0x6F, 0xE0, 0x89, 0x30, 0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD,
   0x10, 0x12, 0x9F, 0xE4, 0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65,
   0x4F, 0x06, 0x94, 0xFC, 0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82,
   0x70, 0xED, 0xE8, 0xEC, 0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47,
   0x44, 0x01, 0xAC, 0x25, 0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3,
   0x0D, 0x6E, 0xFE, 0x26, 0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84,
   0x98, 0x05, 0x9C, 0xBB, 0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6,
   0xAF, 0x24, 0x5B, 0x87, 0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7,
   0x5C, 0x8B, 0xD5, 0x54, 0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11,
   0xCA, 0xF5, 0xD1, 0x17, 0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB,
   0xAE, 0xCC, 0xD6, 0x35, 0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9,
   0xD0, 0x50, 0x59, 0x3F, 0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56,
   0x4C, 0x2E, 0x6B, 0x9E, 0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51,
   0x75, 0x4A, 0x91, 0x71, 0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55,
   0x0B, 0xDC, 0x37, 0x31, 0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB,
   0xA4, 0x2F, 0x46, 0xF3, 0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C,
   0x85, 0x18, 0x04, 0x1D, 0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E,
   0xEE, 0x8D, 0x53, 0x4B, 0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C,
   0x81, 0xC4, 0xC7, 0x36, 0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68,
   0x6D, 0xF0, 0x02, 0x28, 0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14,
   0x86, 0xCF, 0xE5, 0x42, 0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F,
   0x92, 0x90, 0x7D, 0x39, 0x6F, 0xE0, 0x89, 0x30 };

}

/*
* SAFER-SK Encryption
*/
void SAFER_SK::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t rounds = get_rounds();

   for(size_t i = 0; i != blocks; ++i)
      {
      byte A = in[0], B = in[1], C = in[2], D = in[3],
           E = in[4], F = in[5], G = in[6], H = in[7], X, Y;

      for(size_t j = 0; j != 16*rounds; j += 16)
         {
         A = EXP[A ^ EK[j  ]]; B = LOG[B + EK[j+1]];
         C = LOG[C + EK[j+2]]; D = EXP[D ^ EK[j+3]];
         E = EXP[E ^ EK[j+4]]; F = LOG[F + EK[j+5]];
         G = LOG[G + EK[j+6]]; H = EXP[H ^ EK[j+7]];

         A += EK[j+ 8]; B ^= EK[j+ 9]; C ^= EK[j+10]; D += EK[j+11];
         E += EK[j+12]; F ^= EK[j+13]; G ^= EK[j+14]; H += EK[j+15];

         B += A; D += C; F += E; H += G; A += B; C += D; E += F; G += H;
         C += A; G += E; D += B; H += F; A += C; E += G; B += D; F += H;
         H += D; Y = D + H; D = B + F; X = B + D; B = A + E;
         A += B; F = C + G; E = C + F; C = X; G = Y;
         }

      out[0] = A ^ EK[16*rounds+0]; out[1] = B + EK[16*rounds+1];
      out[2] = C + EK[16*rounds+2]; out[3] = D ^ EK[16*rounds+3];
      out[4] = E ^ EK[16*rounds+4]; out[5] = F + EK[16*rounds+5];
      out[6] = G + EK[16*rounds+6]; out[7] = H ^ EK[16*rounds+7];

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* SAFER-SK Decryption
*/
void SAFER_SK::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const size_t rounds = get_rounds();

   for(size_t i = 0; i != blocks; ++i)
      {
      byte A = in[0], B = in[1], C = in[2], D = in[3],
           E = in[4], F = in[5], G = in[6], H = in[7];

      A ^= EK[16*rounds+0]; B -= EK[16*rounds+1]; C -= EK[16*rounds+2];
      D ^= EK[16*rounds+3]; E ^= EK[16*rounds+4]; F -= EK[16*rounds+5];
      G -= EK[16*rounds+6]; H ^= EK[16*rounds+7];

      for(s32bit j = 16*(rounds-1); j >= 0; j -= 16)
         {
         byte T = E; E = B; B = C; C = T; T = F; F = D; D = G; G = T;
         A -= E; B -= F; C -= G; D -= H; E -= A; F -= B; G -= C; H -= D;
         A -= C; E -= G; B -= D; F -= H; C -= A; G -= E; D -= B; H -= F;
         A -= B; C -= D; E -= F; G -= H; B -= A; D -= C; F -= E; H -= G;

         A = LOG[A - EK[j+8 ] + 256]; B = EXP[B ^ EK[j+9 ]];
         C = EXP[C ^ EK[j+10]];       D = LOG[D - EK[j+11] + 256];
         E = LOG[E - EK[j+12] + 256]; F = EXP[F ^ EK[j+13]];
         G = EXP[G ^ EK[j+14]];       H = LOG[H - EK[j+15] + 256];

         A ^= EK[j+0]; B -= EK[j+1]; C -= EK[j+2]; D ^= EK[j+3];
         E ^= EK[j+4]; F -= EK[j+5]; G -= EK[j+6]; H ^= EK[j+7];
         }

      out[0] = A; out[1] = B; out[2] = C; out[3] = D;
      out[4] = E; out[5] = F; out[6] = G; out[7] = H;

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* SAFER-SK Key Schedule
*/
void SAFER_SK::key_schedule(const byte key[], size_t)
   {
   const byte BIAS[208] = {
      0x16, 0x73, 0x3B, 0x1E, 0x8E, 0x70, 0xBD, 0x86, 0x47, 0x7E, 0x24, 0x56,
      0xF1, 0x77, 0x88, 0x46, 0xB1, 0xBA, 0xA3, 0xB7, 0x10, 0x0A, 0xC5, 0x37,
      0xC9, 0x5A, 0x28, 0xAC, 0x64, 0xA5, 0xEC, 0xAB, 0xC6, 0x67, 0x95, 0x58,
      0x0D, 0xF8, 0x9A, 0xF6, 0x66, 0xDC, 0x05, 0x3D, 0xD3, 0x8A, 0xC3, 0xD8,
      0x6A, 0xE9, 0x36, 0x49, 0x43, 0xBF, 0xEB, 0xD4, 0x9B, 0x68, 0xA0, 0x65,
      0x5D, 0x57, 0x92, 0x1F, 0x71, 0x5C, 0xBB, 0x22, 0xC1, 0xBE, 0x7B, 0xBC,
      0x63, 0x94, 0x5F, 0x2A, 0x61, 0xB8, 0x34, 0x32, 0xFD, 0xFB, 0x17, 0x40,
      0xE6, 0x51, 0x1D, 0x41, 0x8F, 0x29, 0xDD, 0x04, 0x80, 0xDE, 0xE7, 0x31,
      0x7F, 0x01, 0xA2, 0xF7, 0x39, 0xDA, 0x6F, 0x23, 0xFE, 0x3A, 0xD0, 0x1C,
      0xD1, 0x30, 0x3E, 0x12, 0xCD, 0x0F, 0xE0, 0xA8, 0xAF, 0x82, 0x59, 0x2C,
      0x7D, 0xAD, 0xB2, 0xEF, 0xC2, 0x87, 0xCE, 0x75, 0x13, 0x02, 0x90, 0x4F,
      0x2E, 0x72, 0x33, 0x85, 0x8D, 0xCF, 0xA9, 0x81, 0xE2, 0xC4, 0x27, 0x2F,
      0x7A, 0x9F, 0x52, 0xE1, 0x15, 0x38, 0x2B, 0xFC, 0x42, 0xC7, 0x08, 0xE4,
      0x09, 0x55, 0x5E, 0x8C, 0x76, 0x60, 0xFF, 0xDF, 0xD7, 0x98, 0xFA, 0x0B,
      0x00, 0x1A, 0xF9, 0xA6, 0xB9, 0xE8, 0x9E, 0x62, 0xD9, 0x91, 0x50, 0xD2,
      0xEE, 0x18, 0xB4, 0x07, 0xEA, 0x5B, 0xA4, 0xC8, 0x0E, 0xCB, 0x48, 0x69,
      0x4E, 0x9C, 0x35, 0x79, 0x45, 0x4D, 0x54, 0xE5, 0x3C, 0x0C, 0x4A, 0x8B,
      0x3F, 0xCC, 0xA7, 0xDB };

   const byte KEY_INDEX[208] = {
      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E,
      0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01,
      0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08,
      0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
      0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B,
      0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
      0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x02, 0x03, 0x04, 0x05,
      0x06, 0x07, 0x08, 0x00, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A,
      0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x0E, 0x0F, 0x10, 0x11,
      0x09, 0x0A, 0x0B, 0x0C, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04,
      0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x08, 0x00, 0x01, 0x02,
      0x03, 0x04, 0x05, 0x06, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E,
      0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01,
      0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08,
      0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
      0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B,
      0x0C, 0x0D, 0x0E, 0x0F };

   SecureVector<byte> KB(18);

   for(size_t i = 0; i != 8; ++i)
      {
      KB[ 8] ^= KB[i] = rotate_left(key[i], 5);
      KB[17] ^= KB[i+9] = EK[i] = key[i+8];
      }

   for(size_t i = 0; i != get_rounds(); ++i)
      {
      for(size_t j = 0; j != 18; ++j)
         KB[j] = rotate_left(KB[j], 6);
      for(size_t j = 0; j != 16; ++j)
         EK[16*i+j+8] = KB[KEY_INDEX[16*i+j]] + BIAS[16*i+j];
      }
   }

/*
* Return the name of this type
*/
std::string SAFER_SK::name() const
   {
   return "SAFER-SK(" + to_string(get_rounds()) + ")";
   }

/*
* Return a clone of this object
*/
BlockCipher* SAFER_SK::clone() const
   {
   return new SAFER_SK(get_rounds());
   }

/*
* SAFER-SK Constructor
*/
SAFER_SK::SAFER_SK(size_t rounds)
   {
   if(rounds > 13 || rounds == 0)
      throw Invalid_Argument(name() + ": Invalid number of rounds");

   EK.resize(16 * rounds + 8);
   }

}
/*
* SEED
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* SEED G Function
*/
u32bit SEED::G_FUNC::operator()(u32bit X) const
   {
   return (S0[get_byte(3, X)] ^ S1[get_byte(2, X)] ^
           S2[get_byte(1, X)] ^ S3[get_byte(0, X)]);
   }

/*
* SEED Encryption
*/
void SEED::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0 = load_be<u32bit>(in, 0);
      u32bit B1 = load_be<u32bit>(in, 1);
      u32bit B2 = load_be<u32bit>(in, 2);
      u32bit B3 = load_be<u32bit>(in, 3);

      G_FUNC G;

      for(size_t j = 0; j != 16; j += 2)
         {
         u32bit T0, T1;

         T0 = B2 ^ K[2*j];
         T1 = G(B2 ^ B3 ^ K[2*j+1]);
         T0 = G(T1 + T0);
         T1 = G(T1 + T0);
         B1 ^= T1;
         B0 ^= T0 + T1;

         T0 = B0 ^ K[2*j+2];
         T1 = G(B0 ^ B1 ^ K[2*j+3]);
         T0 = G(T1 + T0);
         T1 = G(T1 + T0);
         B3 ^= T1;
         B2 ^= T0 + T1;
         }

      store_be(out, B2, B3, B0, B1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* SEED Decryption
*/
void SEED::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0 = load_be<u32bit>(in, 0);
      u32bit B1 = load_be<u32bit>(in, 1);
      u32bit B2 = load_be<u32bit>(in, 2);
      u32bit B3 = load_be<u32bit>(in, 3);

      G_FUNC G;

      for(size_t j = 0; j != 16; j += 2)
         {
         u32bit T0, T1;

         T0 = B2 ^ K[30-2*j];
         T1 = G(B2 ^ B3 ^ K[31-2*j]);
         T0 = G(T1 + T0);
         T1 = G(T1 + T0);
         B1 ^= T1;
         B0 ^= T0 + T1;

         T0 = B0 ^ K[28-2*j];
         T1 = G(B0 ^ B1 ^ K[29-2*j]);
         T0 = G(T1 + T0);
         T1 = G(T1 + T0);
         B3 ^= T1;
         B2 ^= T0 + T1;
         }

      store_be(out, B2, B3, B0, B1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* SEED Key Schedule
*/
void SEED::key_schedule(const byte key[], size_t)
   {
   const u32bit RC[16] = {
      0x9E3779B9, 0x3C6EF373, 0x78DDE6E6, 0xF1BBCDCC,
      0xE3779B99, 0xC6EF3733, 0x8DDE6E67, 0x1BBCDCCF,
      0x3779B99E, 0x6EF3733C, 0xDDE6E678, 0xBBCDCCF1,
      0x779B99E3, 0xEF3733C6, 0xDE6E678D, 0xBCDCCF1B
   };

   SecureVector<u32bit> WK(4);

   for(size_t i = 0; i != 4; ++i)
      WK[i] = load_be<u32bit>(key, i);

   G_FUNC G;

   for(size_t i = 0; i != 16; i += 2)
      {
      K[2*i  ] = G(WK[0] + WK[2] - RC[i]);
      K[2*i+1] = G(WK[1] - WK[3] + RC[i]) ^ K[2*i];

      byte T = get_byte(3, WK[0]);
      WK[0] = (WK[0] >> 8) | (get_byte(3, WK[1]) << 24);
      WK[1] = (WK[1] >> 8) | (T << 24);

      K[2*i+2] = G(WK[0] + WK[2] - RC[i+1]);
      K[2*i+3] = G(WK[1] - WK[3] + RC[i+1]) ^ K[2*i+2];

      T = get_byte(0, WK[3]);
      WK[3] = (WK[3] << 8) | get_byte(0, WK[2]);
      WK[2] = (WK[2] << 8) | T;
      }
   }

}
/*
* S-Box Tables for SEED
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u32bit SEED::G_FUNC::S0[256] = {
   0x2989A1A8, 0x05858184, 0x16C6D2D4, 0x13C3D3D0, 0x14445054, 0x1D0D111C,
   0x2C8CA0AC, 0x25052124, 0x1D4D515C, 0x03434340, 0x18081018, 0x1E0E121C,
   0x11415150, 0x3CCCF0FC, 0x0ACAC2C8, 0x23436360, 0x28082028, 0x04444044,
   0x20002020, 0x1D8D919C, 0x20C0E0E0, 0x22C2E2E0, 0x08C8C0C8, 0x17071314,
   0x2585A1A4, 0x0F8F838C, 0x03030300, 0x3B4B7378, 0x3B8BB3B8, 0x13031310,
   0x12C2D2D0, 0x2ECEE2EC, 0x30407070, 0x0C8C808C, 0x3F0F333C, 0x2888A0A8,
   0x32023230, 0x1DCDD1DC, 0x36C6F2F4, 0x34447074, 0x2CCCE0EC, 0x15859194,
   0x0B0B0308, 0x17475354, 0x1C4C505C, 0x1B4B5358, 0x3D8DB1BC, 0x01010100,
   0x24042024, 0x1C0C101C, 0x33437370, 0x18889098, 0x10001010, 0x0CCCC0CC,
   0x32C2F2F0, 0x19C9D1D8, 0x2C0C202C, 0x27C7E3E4, 0x32427270, 0x03838380,
   0x1B8B9398, 0x11C1D1D0, 0x06868284, 0x09C9C1C8, 0x20406060, 0x10405050,
   0x2383A3A0, 0x2BCBE3E8, 0x0D0D010C, 0x3686B2B4, 0x1E8E929C, 0x0F4F434C,
   0x3787B3B4, 0x1A4A5258, 0x06C6C2C4, 0x38487078, 0x2686A2A4, 0x12021210,
   0x2F8FA3AC, 0x15C5D1D4, 0x21416160, 0x03C3C3C0, 0x3484B0B4, 0x01414140,
   0x12425250, 0x3D4D717C, 0x0D8D818C, 0x08080008, 0x1F0F131C, 0x19899198,
   0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37C7F3F4, 0x21C1E1E0,
   0x3DCDF1FC, 0x36467274, 0x2F0F232C, 0x27072324, 0x3080B0B0, 0x0B8B8388,
   0x0E0E020C, 0x2B8BA3A8, 0x2282A2A0, 0x2E4E626C, 0x13839390, 0x0D4D414C,
   0x29496168, 0x3C4C707C, 0x09090108, 0x0A0A0208, 0x3F8FB3BC, 0x2FCFE3EC,
   0x33C3F3F0, 0x05C5C1C4, 0x07878384, 0x14041014, 0x3ECEF2FC, 0x24446064,
   0x1ECED2DC, 0x2E0E222C, 0x0B4B4348, 0x1A0A1218, 0x06060204, 0x21012120,
   0x2B4B6368, 0x26466264, 0x02020200, 0x35C5F1F4, 0x12829290, 0x0A8A8288,
   0x0C0C000C, 0x3383B3B0, 0x3E4E727C, 0x10C0D0D0, 0x3A4A7278, 0x07474344,
   0x16869294, 0x25C5E1E4, 0x26062224, 0x00808080, 0x2D8DA1AC, 0x1FCFD3DC,
   0x2181A1A0, 0x30003030, 0x37073334, 0x2E8EA2AC, 0x36063234, 0x15051114,
   0x22022220, 0x38083038, 0x34C4F0F4, 0x2787A3A4, 0x05454144, 0x0C4C404C,
   0x01818180, 0x29C9E1E8, 0x04848084, 0x17879394, 0x35053134, 0x0BCBC3C8,
   0x0ECEC2CC, 0x3C0C303C, 0x31417170, 0x11011110, 0x07C7C3C4, 0x09898188,
   0x35457174, 0x3BCBF3F8, 0x1ACAD2D8, 0x38C8F0F8, 0x14849094, 0x19495158,
   0x02828280, 0x04C4C0C4, 0x3FCFF3FC, 0x09494148, 0x39093138, 0x27476364,
   0x00C0C0C0, 0x0FCFC3CC, 0x17C7D3D4, 0x3888B0B8, 0x0F0F030C, 0x0E8E828C,
   0x02424240, 0x23032320, 0x11819190, 0x2C4C606C, 0x1BCBD3D8, 0x2484A0A4,
   0x34043034, 0x31C1F1F0, 0x08484048, 0x02C2C2C0, 0x2F4F636C, 0x3D0D313C,
   0x2D0D212C, 0x00404040, 0x3E8EB2BC, 0x3E0E323C, 0x3C8CB0BC, 0x01C1C1C0,
   0x2A8AA2A8, 0x3A8AB2B8, 0x0E4E424C, 0x15455154, 0x3B0B3338, 0x1CCCD0DC,
   0x28486068, 0x3F4F737C, 0x1C8C909C, 0x18C8D0D8, 0x0A4A4248, 0x16465254,
   0x37477374, 0x2080A0A0, 0x2DCDE1EC, 0x06464244, 0x3585B1B4, 0x2B0B2328,
   0x25456164, 0x3ACAF2F8, 0x23C3E3E0, 0x3989B1B8, 0x3181B1B0, 0x1F8F939C,
   0x1E4E525C, 0x39C9F1F8, 0x26C6E2E4, 0x3282B2B0, 0x31013130, 0x2ACAE2E8,
   0x2D4D616C, 0x1F4F535C, 0x24C4E0E4, 0x30C0F0F0, 0x0DCDC1CC, 0x08888088,
   0x16061214, 0x3A0A3238, 0x18485058, 0x14C4D0D4, 0x22426260, 0x29092128,
   0x07070304, 0x33033330, 0x28C8E0E8, 0x1B0B1318, 0x05050104, 0x39497178,
   0x10809090, 0x2A4A6268, 0x2A0A2228, 0x1A8A9298 };

const u32bit SEED::G_FUNC::S1[256] = {
   0x38380830, 0xE828C8E0, 0x2C2D0D21, 0xA42686A2, 0xCC0FCFC3, 0xDC1ECED2,
   0xB03383B3, 0xB83888B0, 0xAC2F8FA3, 0x60204060, 0x54154551, 0xC407C7C3,
   0x44044440, 0x6C2F4F63, 0x682B4B63, 0x581B4B53, 0xC003C3C3, 0x60224262,
   0x30330333, 0xB43585B1, 0x28290921, 0xA02080A0, 0xE022C2E2, 0xA42787A3,
   0xD013C3D3, 0x90118191, 0x10110111, 0x04060602, 0x1C1C0C10, 0xBC3C8CB0,
   0x34360632, 0x480B4B43, 0xEC2FCFE3, 0x88088880, 0x6C2C4C60, 0xA82888A0,
   0x14170713, 0xC404C4C0, 0x14160612, 0xF434C4F0, 0xC002C2C2, 0x44054541,
   0xE021C1E1, 0xD416C6D2, 0x3C3F0F33, 0x3C3D0D31, 0x8C0E8E82, 0x98188890,
   0x28280820, 0x4C0E4E42, 0xF436C6F2, 0x3C3E0E32, 0xA42585A1, 0xF839C9F1,
   0x0C0D0D01, 0xDC1FCFD3, 0xD818C8D0, 0x282B0B23, 0x64264662, 0x783A4A72,
   0x24270723, 0x2C2F0F23, 0xF031C1F1, 0x70324272, 0x40024242, 0xD414C4D0,
   0x40014141, 0xC000C0C0, 0x70334373, 0x64274763, 0xAC2C8CA0, 0x880B8B83,
   0xF437C7F3, 0xAC2D8DA1, 0x80008080, 0x1C1F0F13, 0xC80ACAC2, 0x2C2C0C20,
   0xA82A8AA2, 0x34340430, 0xD012C2D2, 0x080B0B03, 0xEC2ECEE2, 0xE829C9E1,
   0x5C1D4D51, 0x94148490, 0x18180810, 0xF838C8F0, 0x54174753, 0xAC2E8EA2,
   0x08080800, 0xC405C5C1, 0x10130313, 0xCC0DCDC1, 0x84068682, 0xB83989B1,
   0xFC3FCFF3, 0x7C3D4D71, 0xC001C1C1, 0x30310131, 0xF435C5F1, 0x880A8A82,
   0x682A4A62, 0xB03181B1, 0xD011C1D1, 0x20200020, 0xD417C7D3, 0x00020202,
   0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xD81BCBD3,
   0x9C1D8D91, 0x98198991, 0x60214161, 0xBC3E8EB2, 0xE426C6E2, 0x58194951,
   0xDC1DCDD1, 0x50114151, 0x90108090, 0xDC1CCCD0, 0x981A8A92, 0xA02383A3,
   0xA82B8BA3, 0xD010C0D0, 0x80018181, 0x0C0F0F03, 0x44074743, 0x181A0A12,
   0xE023C3E3, 0xEC2CCCE0, 0x8C0D8D81, 0xBC3F8FB3, 0x94168692, 0x783B4B73,
   0x5C1C4C50, 0xA02282A2, 0xA02181A1, 0x60234363, 0x20230323, 0x4C0D4D41,
   0xC808C8C0, 0x9C1E8E92, 0x9C1C8C90, 0x383A0A32, 0x0C0C0C00, 0x2C2E0E22,
   0xB83A8AB2, 0x6C2E4E62, 0x9C1F8F93, 0x581A4A52, 0xF032C2F2, 0x90128292,
   0xF033C3F3, 0x48094941, 0x78384870, 0xCC0CCCC0, 0x14150511, 0xF83BCBF3,
   0x70304070, 0x74354571, 0x7C3F4F73, 0x34350531, 0x10100010, 0x00030303,
   0x64244460, 0x6C2D4D61, 0xC406C6C2, 0x74344470, 0xD415C5D1, 0xB43484B0,
   0xE82ACAE2, 0x08090901, 0x74364672, 0x18190911, 0xFC3ECEF2, 0x40004040,
   0x10120212, 0xE020C0E0, 0xBC3D8DB1, 0x04050501, 0xF83ACAF2, 0x00010101,
   0xF030C0F0, 0x282A0A22, 0x5C1E4E52, 0xA82989A1, 0x54164652, 0x40034343,
   0x84058581, 0x14140410, 0x88098981, 0x981B8B93, 0xB03080B0, 0xE425C5E1,
   0x48084840, 0x78394971, 0x94178793, 0xFC3CCCF0, 0x1C1E0E12, 0x80028282,
   0x20210121, 0x8C0C8C80, 0x181B0B13, 0x5C1F4F53, 0x74374773, 0x54144450,
   0xB03282B2, 0x1C1D0D11, 0x24250521, 0x4C0F4F43, 0x00000000, 0x44064642,
   0xEC2DCDE1, 0x58184850, 0x50124252, 0xE82BCBE3, 0x7C3E4E72, 0xD81ACAD2,
   0xC809C9C1, 0xFC3DCDF1, 0x30300030, 0x94158591, 0x64254561, 0x3C3C0C30,
   0xB43686B2, 0xE424C4E0, 0xB83B8BB3, 0x7C3C4C70, 0x0C0E0E02, 0x50104050,
   0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
   0x34370733, 0xE427C7E3, 0x24240420, 0xA42484A0, 0xC80BCBC3, 0x50134353,
   0x080A0A02, 0x84078783, 0xD819C9D1, 0x4C0C4C40, 0x80038383, 0x8C0F8F83,
   0xCC0ECEC2, 0x383B0B33, 0x480A4A42, 0xB43787B3 };

const u32bit SEED::G_FUNC::S2[256] = {
   0xA1A82989, 0x81840585, 0xD2D416C6, 0xD3D013C3, 0x50541444, 0x111C1D0D,
   0xA0AC2C8C, 0x21242505, 0x515C1D4D, 0x43400343, 0x10181808, 0x121C1E0E,
   0x51501141, 0xF0FC3CCC, 0xC2C80ACA, 0x63602343, 0x20282808, 0x40440444,
   0x20202000, 0x919C1D8D, 0xE0E020C0, 0xE2E022C2, 0xC0C808C8, 0x13141707,
   0xA1A42585, 0x838C0F8F, 0x03000303, 0x73783B4B, 0xB3B83B8B, 0x13101303,
   0xD2D012C2, 0xE2EC2ECE, 0x70703040, 0x808C0C8C, 0x333C3F0F, 0xA0A82888,
   0x32303202, 0xD1DC1DCD, 0xF2F436C6, 0x70743444, 0xE0EC2CCC, 0x91941585,
   0x03080B0B, 0x53541747, 0x505C1C4C, 0x53581B4B, 0xB1BC3D8D, 0x01000101,
   0x20242404, 0x101C1C0C, 0x73703343, 0x90981888, 0x10101000, 0xC0CC0CCC,
   0xF2F032C2, 0xD1D819C9, 0x202C2C0C, 0xE3E427C7, 0x72703242, 0x83800383,
   0x93981B8B, 0xD1D011C1, 0x82840686, 0xC1C809C9, 0x60602040, 0x50501040,
   0xA3A02383, 0xE3E82BCB, 0x010C0D0D, 0xB2B43686, 0x929C1E8E, 0x434C0F4F,
   0xB3B43787, 0x52581A4A, 0xC2C406C6, 0x70783848, 0xA2A42686, 0x12101202,
   0xA3AC2F8F, 0xD1D415C5, 0x61602141, 0xC3C003C3, 0xB0B43484, 0x41400141,
   0x52501242, 0x717C3D4D, 0x818C0D8D, 0x00080808, 0x131C1F0F, 0x91981989,
   0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xF3F437C7, 0xE1E021C1,
   0xF1FC3DCD, 0x72743646, 0x232C2F0F, 0x23242707, 0xB0B03080, 0x83880B8B,
   0x020C0E0E, 0xA3A82B8B, 0xA2A02282, 0x626C2E4E, 0x93901383, 0x414C0D4D,
   0x61682949, 0x707C3C4C, 0x01080909, 0x02080A0A, 0xB3BC3F8F, 0xE3EC2FCF,
   0xF3F033C3, 0xC1C405C5, 0x83840787, 0x10141404, 0xF2FC3ECE, 0x60642444,
   0xD2DC1ECE, 0x222C2E0E, 0x43480B4B, 0x12181A0A, 0x02040606, 0x21202101,
   0x63682B4B, 0x62642646, 0x02000202, 0xF1F435C5, 0x92901282, 0x82880A8A,
   0x000C0C0C, 0xB3B03383, 0x727C3E4E, 0xD0D010C0, 0x72783A4A, 0x43440747,
   0x92941686, 0xE1E425C5, 0x22242606, 0x80800080, 0xA1AC2D8D, 0xD3DC1FCF,
   0xA1A02181, 0x30303000, 0x33343707, 0xA2AC2E8E, 0x32343606, 0x11141505,
   0x22202202, 0x30383808, 0xF0F434C4, 0xA3A42787, 0x41440545, 0x404C0C4C,
   0x81800181, 0xE1E829C9, 0x80840484, 0x93941787, 0x31343505, 0xC3C80BCB,
   0xC2CC0ECE, 0x303C3C0C, 0x71703141, 0x11101101, 0xC3C407C7, 0x81880989,
   0x71743545, 0xF3F83BCB, 0xD2D81ACA, 0xF0F838C8, 0x90941484, 0x51581949,
   0x82800282, 0xC0C404C4, 0xF3FC3FCF, 0x41480949, 0x31383909, 0x63642747,
   0xC0C000C0, 0xC3CC0FCF, 0xD3D417C7, 0xB0B83888, 0x030C0F0F, 0x828C0E8E,
   0x42400242, 0x23202303, 0x91901181, 0x606C2C4C, 0xD3D81BCB, 0xA0A42484,
   0x30343404, 0xF1F031C1, 0x40480848, 0xC2C002C2, 0x636C2F4F, 0x313C3D0D,
   0x212C2D0D, 0x40400040, 0xB2BC3E8E, 0x323C3E0E, 0xB0BC3C8C, 0xC1C001C1,
   0xA2A82A8A, 0xB2B83A8A, 0x424C0E4E, 0x51541545, 0x33383B0B, 0xD0DC1CCC,
   0x60682848, 0x737C3F4F, 0x909C1C8C, 0xD0D818C8, 0x42480A4A, 0x52541646,
   0x73743747, 0xA0A02080, 0xE1EC2DCD, 0x42440646, 0xB1B43585, 0x23282B0B,
   0x61642545, 0xF2F83ACA, 0xE3E023C3, 0xB1B83989, 0xB1B03181, 0x939C1F8F,
   0x525C1E4E, 0xF1F839C9, 0xE2E426C6, 0xB2B03282, 0x31303101, 0xE2E82ACA,
   0x616C2D4D, 0x535C1F4F, 0xE0E424C4, 0xF0F030C0, 0xC1CC0DCD, 0x80880888,
   0x12141606, 0x32383A0A, 0x50581848, 0xD0D414C4, 0x62602242, 0x21282909,
   0x03040707, 0x33303303, 0xE0E828C8, 0x13181B0B, 0x01040505, 0x71783949,
   0x90901080, 0x62682A4A, 0x22282A0A, 0x92981A8A };

const u32bit SEED::G_FUNC::S3[256] = {
   0x08303838, 0xC8E0E828, 0x0D212C2D, 0x86A2A426, 0xCFC3CC0F, 0xCED2DC1E,
   0x83B3B033, 0x88B0B838, 0x8FA3AC2F, 0x40606020, 0x45515415, 0xC7C3C407,
   0x44404404, 0x4F636C2F, 0x4B63682B, 0x4B53581B, 0xC3C3C003, 0x42626022,
   0x03333033, 0x85B1B435, 0x09212829, 0x80A0A020, 0xC2E2E022, 0x87A3A427,
   0xC3D3D013, 0x81919011, 0x01111011, 0x06020406, 0x0C101C1C, 0x8CB0BC3C,
   0x06323436, 0x4B43480B, 0xCFE3EC2F, 0x88808808, 0x4C606C2C, 0x88A0A828,
   0x07131417, 0xC4C0C404, 0x06121416, 0xC4F0F434, 0xC2C2C002, 0x45414405,
   0xC1E1E021, 0xC6D2D416, 0x0F333C3F, 0x0D313C3D, 0x8E828C0E, 0x88909818,
   0x08202828, 0x4E424C0E, 0xC6F2F436, 0x0E323C3E, 0x85A1A425, 0xC9F1F839,
   0x0D010C0D, 0xCFD3DC1F, 0xC8D0D818, 0x0B23282B, 0x46626426, 0x4A72783A,
   0x07232427, 0x0F232C2F, 0xC1F1F031, 0x42727032, 0x42424002, 0xC4D0D414,
   0x41414001, 0xC0C0C000, 0x43737033, 0x47636427, 0x8CA0AC2C, 0x8B83880B,
   0xC7F3F437, 0x8DA1AC2D, 0x80808000, 0x0F131C1F, 0xCAC2C80A, 0x0C202C2C,
   0x8AA2A82A, 0x04303434, 0xC2D2D012, 0x0B03080B, 0xCEE2EC2E, 0xC9E1E829,
   0x4D515C1D, 0x84909414, 0x08101818, 0xC8F0F838, 0x47535417, 0x8EA2AC2E,
   0x08000808, 0xC5C1C405, 0x03131013, 0xCDC1CC0D, 0x86828406, 0x89B1B839,
   0xCFF3FC3F, 0x4D717C3D, 0xC1C1C001, 0x01313031, 0xC5F1F435, 0x8A82880A,
   0x4A62682A, 0x81B1B031, 0xC1D1D011, 0x00202020, 0xC7D3D417, 0x02020002,
   0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xCBD3D81B,
   0x8D919C1D, 0x89919819, 0x41616021, 0x8EB2BC3E, 0xC6E2E426, 0x49515819,
   0xCDD1DC1D, 0x41515011, 0x80909010, 0xCCD0DC1C, 0x8A92981A, 0x83A3A023,
   0x8BA3A82B, 0xC0D0D010, 0x81818001, 0x0F030C0F, 0x47434407, 0x0A12181A,
   0xC3E3E023, 0xCCE0EC2C, 0x8D818C0D, 0x8FB3BC3F, 0x86929416, 0x4B73783B,
   0x4C505C1C, 0x82A2A022, 0x81A1A021, 0x43636023, 0x03232023, 0x4D414C0D,
   0xC8C0C808, 0x8E929C1E, 0x8C909C1C, 0x0A32383A, 0x0C000C0C, 0x0E222C2E,
   0x8AB2B83A, 0x4E626C2E, 0x8F939C1F, 0x4A52581A, 0xC2F2F032, 0x82929012,
   0xC3F3F033, 0x49414809, 0x48707838, 0xCCC0CC0C, 0x05111415, 0xCBF3F83B,
   0x40707030, 0x45717435, 0x4F737C3F, 0x05313435, 0x00101010, 0x03030003,
   0x44606424, 0x4D616C2D, 0xC6C2C406, 0x44707434, 0xC5D1D415, 0x84B0B434,
   0xCAE2E82A, 0x09010809, 0x46727436, 0x09111819, 0xCEF2FC3E, 0x40404000,
   0x02121012, 0xC0E0E020, 0x8DB1BC3D, 0x05010405, 0xCAF2F83A, 0x01010001,
   0xC0F0F030, 0x0A22282A, 0x4E525C1E, 0x89A1A829, 0x46525416, 0x43434003,
   0x85818405, 0x04101414, 0x89818809, 0x8B93981B, 0x80B0B030, 0xC5E1E425,
   0x48404808, 0x49717839, 0x87939417, 0xCCF0FC3C, 0x0E121C1E, 0x82828002,
   0x01212021, 0x8C808C0C, 0x0B13181B, 0x4F535C1F, 0x47737437, 0x44505414,
   0x82B2B032, 0x0D111C1D, 0x05212425, 0x4F434C0F, 0x00000000, 0x46424406,
   0xCDE1EC2D, 0x48505818, 0x42525012, 0xCBE3E82B, 0x4E727C3E, 0xCAD2D81A,
   0xC9C1C809, 0xCDF1FC3D, 0x00303030, 0x85919415, 0x45616425, 0x0C303C3C,
   0x86B2B436, 0xC4E0E424, 0x8BB3B83B, 0x4C707C3C, 0x0E020C0E, 0x40505010,
   0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
   0x07333437, 0xC7E3E427, 0x04202424, 0x84A0A424, 0xCBC3C80B, 0x43535013,
   0x0A02080A, 0x87838407, 0xC9D1D819, 0x4C404C0C, 0x83838003, 0x8F838C0F,
   0xCEC2CC0E, 0x0B33383B, 0x4A42480A, 0x87B3B437 };

}
/*
* Serpent
* (C) 1999-2007 Jack Lloyd
*
* The sbox expressions used here were discovered by Dag Arne Osvik and
* are described in his paper "Speeding Up Serpent".
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Serpent Encryption S-Box 1
*/
inline void SBoxE1(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T3 ^= T0; T4  = T1; T1 &= T3; T4 ^= T2; T1 ^= T0; T0 |= T3; T0 ^= T4;
   T4 ^= T3; T3 ^= T2; T2 |= T1; T2 ^= T4; T4 = ~T4; T4 |= T1; T1 ^= T3;
   T1 ^= T4; T3 |= T0; T1 ^= T3; T4 ^= T3;
   B0 = T1; B1 = T4; B2 = T2; B3 = T0;
   }

/*
* Serpent Encryption S-Box 2
*/
inline void SBoxE2(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T0 = ~T0; T2 = ~T2; T4  = T0; T0 &= T1; T2 ^= T0; T0 |= T3; T3 ^= T2;
   T1 ^= T0; T0 ^= T4; T4 |= T1; T1 ^= T3; T2 |= T0; T2 &= T4; T0 ^= T1;
   T1 &= T2; T1 ^= T0; T0 &= T2; T0 ^= T4;
   B0 = T2; B1 = T0; B2 = T3; B3 = T1;
   }

/*
* Serpent Encryption S-Box 3
*/
inline void SBoxE3(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T0; T0 &= T2; T0 ^= T3; T2 ^= T1; T2 ^= T0; T3 |= T4; T3 ^= T1;
   T4 ^= T2; T1  = T3; T3 |= T4; T3 ^= T0; T0 &= T1; T4 ^= T0; T1 ^= T3;
   T1 ^= T4; T4 = ~T4;
   B0 = T2; B1 = T3; B2 = T1; B3 = T4;
   }

/*
* Serpent Encryption S-Box 4
*/
inline void SBoxE4(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T0; T0 |= T3; T3 ^= T1; T1 &= T4; T4 ^= T2; T2 ^= T3; T3 &= T0;
   T4 |= T1; T3 ^= T4; T0 ^= T1; T4 &= T0; T1 ^= T3; T4 ^= T2; T1 |= T0;
   T1 ^= T2; T0 ^= T3; T2  = T1; T1 |= T3; T1 ^= T0;
   B0 = T1; B1 = T2; B2 = T3; B3 = T4;
   }

/*
* Serpent Encryption S-Box 5
*/
inline void SBoxE5(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T1 ^= T3; T3 = ~T3; T2 ^= T3; T3 ^= T0; T4  = T1; T1 &= T3; T1 ^= T2;
   T4 ^= T3; T0 ^= T4; T2 &= T4; T2 ^= T0; T0 &= T1; T3 ^= T0; T4 |= T1;
   T4 ^= T0; T0 |= T3; T0 ^= T2; T2 &= T3; T0 = ~T0; T4 ^= T2;
   B0 = T1; B1 = T4; B2 = T0; B3 = T3;
   }

/*
* Serpent Encryption S-Box 6
*/
inline void SBoxE6(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T0 ^= T1; T1 ^= T3; T3 = ~T3; T4  = T1; T1 &= T0; T2 ^= T3; T1 ^= T2;
   T2 |= T4; T4 ^= T3; T3 &= T1; T3 ^= T0; T4 ^= T1; T4 ^= T2; T2 ^= T0;
   T0 &= T3; T2 = ~T2; T0 ^= T4; T4 |= T3; T2 ^= T4;
   B0 = T1; B1 = T3; B2 = T0; B3 = T2;
   }

/*
* Serpent Encryption S-Box 7
*/
inline void SBoxE7(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T2 = ~T2; T4  = T3; T3 &= T0; T0 ^= T4; T3 ^= T2; T2 |= T4; T1 ^= T3;
   T2 ^= T0; T0 |= T1; T2 ^= T1; T4 ^= T0; T0 |= T3; T0 ^= T2; T4 ^= T3;
   T4 ^= T0; T3 = ~T3; T2 &= T4; T2 ^= T3;
   B0 = T0; B1 = T1; B2 = T4; B3 = T2;
   }

/*
* Serpent Encryption S-Box 8
*/
inline void SBoxE8(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T1; T1 |= T2; T1 ^= T3; T4 ^= T2; T2 ^= T1; T3 |= T4; T3 &= T0;
   T4 ^= T2; T3 ^= T1; T1 |= T4; T1 ^= T0; T0 |= T4; T0 ^= T2; T1 ^= T4;
   T2 ^= T1; T1 &= T0; T1 ^= T4; T2 = ~T2; T2 |= T0; T4 ^= T2;
   B0 = T4; B1 = T3; B2 = T1; B3 = T0;
   }

/*
* Serpent Decryption S-Box 1
*/
inline void SBoxD1(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T2 = ~T2; T4  = T1; T1 |= T0; T4 = ~T4; T1 ^= T2; T2 |= T4; T1 ^= T3;
   T0 ^= T4; T2 ^= T0; T0 &= T3; T4 ^= T0; T0 |= T1; T0 ^= T2; T3 ^= T4;
   T2 ^= T1; T3 ^= T0; T3 ^= T1; T2 &= T3; T4 ^= T2;
   B0 = T0; B1 = T4; B2 = T1; B3 = T3;
   }

/*
* Serpent Decryption S-Box 2
*/
inline void SBoxD2(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T1; T1 ^= T3; T3 &= T1; T4 ^= T2; T3 ^= T0; T0 |= T1; T2 ^= T3;
   T0 ^= T4; T0 |= T2; T1 ^= T3; T0 ^= T1; T1 |= T3; T1 ^= T0; T4 = ~T4;
   T4 ^= T1; T1 |= T0; T1 ^= T0; T1 |= T4; T3 ^= T1;
   B0 = T4; B1 = T0; B2 = T3; B3 = T2;
   }

/*
* Serpent Decryption S-Box 3
*/
inline void SBoxD3(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T2 ^= T3; T3 ^= T0; T4  = T3; T3 &= T2; T3 ^= T1; T1 |= T2; T1 ^= T4;
   T4 &= T3; T2 ^= T3; T4 &= T0; T4 ^= T2; T2 &= T1; T2 |= T0; T3 = ~T3;
   T2 ^= T3; T0 ^= T3; T0 &= T1; T3 ^= T4; T3 ^= T0;
   B0 = T1; B1 = T4; B2 = T2; B3 = T3;
   }

/*
* Serpent Decryption S-Box 4
*/
inline void SBoxD4(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T2; T2 ^= T1; T0 ^= T2; T4 &= T2; T4 ^= T0; T0 &= T1; T1 ^= T3;
   T3 |= T4; T2 ^= T3; T0 ^= T3; T1 ^= T4; T3 &= T2; T3 ^= T1; T1 ^= T0;
   T1 |= T2; T0 ^= T3; T1 ^= T4; T0 ^= T1;
   B0 = T2; B1 = T1; B2 = T3; B3 = T0;
   }

/*
* Serpent Decryption S-Box 5
*/
inline void SBoxD5(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T2; T2 &= T3; T2 ^= T1; T1 |= T3; T1 &= T0; T4 ^= T2; T4 ^= T1;
   T1 &= T2; T0 = ~T0; T3 ^= T4; T1 ^= T3; T3 &= T0; T3 ^= T2; T0 ^= T1;
   T2 &= T0; T3 ^= T0; T2 ^= T4; T2 |= T3; T3 ^= T0; T2 ^= T1;
   B0 = T0; B1 = T3; B2 = T2; B3 = T4;
   }

/*
* Serpent Decryption S-Box 6
*/
inline void SBoxD6(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T1 = ~T1; T4  = T3; T2 ^= T1; T3 |= T0; T3 ^= T2; T2 |= T1; T2 &= T0;
   T4 ^= T3; T2 ^= T4; T4 |= T0; T4 ^= T1; T1 &= T2; T1 ^= T3; T4 ^= T2;
   T3 &= T4; T4 ^= T1; T3 ^= T4; T4 = ~T4; T3 ^= T0;
   B0 = T1; B1 = T4; B2 = T3; B3 = T2;
   }

/*
* Serpent Decryption S-Box 7
*/
inline void SBoxD7(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T0 ^= T2; T4  = T2; T2 &= T0; T4 ^= T3; T2 = ~T2; T3 ^= T1; T2 ^= T3;
   T4 |= T0; T0 ^= T2; T3 ^= T4; T4 ^= T1; T1 &= T3; T1 ^= T0; T0 ^= T3;
   T0 |= T2; T3 ^= T1; T4 ^= T0;
   B0 = T1; B1 = T2; B2 = T4; B3 = T3;
   }

/*
* Serpent Decryption S-Box 8
*/
inline void SBoxD8(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4;
   T4  = T2; T2 ^= T0; T0 &= T3; T4 |= T3; T2 = ~T2; T3 ^= T1; T1 |= T0;
   T0 ^= T2; T2 &= T4; T3 &= T4; T1 ^= T2; T2 ^= T0; T0 |= T2; T4 ^= T1;
   T0 ^= T3; T3 ^= T4; T4 |= T0; T3 ^= T2; T4 ^= T2;
   B0 = T3; B1 = T0; B2 = T1; B3 = T4;
   }

/*
* Serpent's Linear Transformation
*/
inline void transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   B0  = rotate_left(B0, 13);   B2  = rotate_left(B2, 3);
   B1 ^= B0 ^ B2;               B3 ^= B2 ^ (B0 << 3);
   B1  = rotate_left(B1, 1);    B3  = rotate_left(B3, 7);
   B0 ^= B1 ^ B3;               B2 ^= B3 ^ (B1 << 7);
   B0  = rotate_left(B0, 5);    B2  = rotate_left(B2, 22);
   }

/*
* Serpent's Inverse Linear Transformation
*/
inline void i_transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3)
   {
   B2  = rotate_right(B2, 22);  B0  = rotate_right(B0, 5);
   B2 ^= B3 ^ (B1 << 7);        B0 ^= B1 ^ B3;
   B3  = rotate_right(B3, 7);   B1  = rotate_right(B1, 1);
   B3 ^= B2 ^ (B0 << 3);        B1 ^= B0 ^ B2;
   B2  = rotate_right(B2, 3);   B0  = rotate_right(B0, 13);
   }

}

/*
* XOR a key block with a data block
*/
#define key_xor(round, B0, B1, B2, B3) \
   B0 ^= round_key[4*round  ]; \
   B1 ^= round_key[4*round+1]; \
   B2 ^= round_key[4*round+2]; \
   B3 ^= round_key[4*round+3];

/*
* Serpent Encryption
*/
void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0 = load_le<u32bit>(in, 0);
      u32bit B1 = load_le<u32bit>(in, 1);
      u32bit B2 = load_le<u32bit>(in, 2);
      u32bit B3 = load_le<u32bit>(in, 3);

      key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
      key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3);

      store_le(out, B0, B1, B2, B3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Serpent Decryption
*/
void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0 = load_le<u32bit>(in, 0);
      u32bit B1 = load_le<u32bit>(in, 1);
      u32bit B2 = load_le<u32bit>(in, 2);
      u32bit B3 = load_le<u32bit>(in, 3);

      key_xor(32,B0,B1,B2,B3);  SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3);
      i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3);

      store_le(out, B0, B1, B2, B3);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

#undef key_xor
#undef transform
#undef i_transform

/*
* Serpent Key Schedule
*/
void Serpent::key_schedule(const byte key[], size_t length)
   {
   const u32bit PHI = 0x9E3779B9;

   SecureVector<u32bit> W(140);
   for(size_t i = 0; i != length / 4; ++i)
      W[i] = load_le<u32bit>(key, i);

   W[length / 4] |= u32bit(1) << ((length%4)*8);

   for(size_t i = 8; i != 140; ++i)
      {
      u32bit wi = W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ u32bit(i-8);
      W[i] = rotate_left(wi, 11);
      }

   SBoxE4(W[  8],W[  9],W[ 10],W[ 11]); SBoxE3(W[ 12],W[ 13],W[ 14],W[ 15]);
   SBoxE2(W[ 16],W[ 17],W[ 18],W[ 19]); SBoxE1(W[ 20],W[ 21],W[ 22],W[ 23]);
   SBoxE8(W[ 24],W[ 25],W[ 26],W[ 27]); SBoxE7(W[ 28],W[ 29],W[ 30],W[ 31]);
   SBoxE6(W[ 32],W[ 33],W[ 34],W[ 35]); SBoxE5(W[ 36],W[ 37],W[ 38],W[ 39]);
   SBoxE4(W[ 40],W[ 41],W[ 42],W[ 43]); SBoxE3(W[ 44],W[ 45],W[ 46],W[ 47]);
   SBoxE2(W[ 48],W[ 49],W[ 50],W[ 51]); SBoxE1(W[ 52],W[ 53],W[ 54],W[ 55]);
   SBoxE8(W[ 56],W[ 57],W[ 58],W[ 59]); SBoxE7(W[ 60],W[ 61],W[ 62],W[ 63]);
   SBoxE6(W[ 64],W[ 65],W[ 66],W[ 67]); SBoxE5(W[ 68],W[ 69],W[ 70],W[ 71]);
   SBoxE4(W[ 72],W[ 73],W[ 74],W[ 75]); SBoxE3(W[ 76],W[ 77],W[ 78],W[ 79]);
   SBoxE2(W[ 80],W[ 81],W[ 82],W[ 83]); SBoxE1(W[ 84],W[ 85],W[ 86],W[ 87]);
   SBoxE8(W[ 88],W[ 89],W[ 90],W[ 91]); SBoxE7(W[ 92],W[ 93],W[ 94],W[ 95]);
   SBoxE6(W[ 96],W[ 97],W[ 98],W[ 99]); SBoxE5(W[100],W[101],W[102],W[103]);
   SBoxE4(W[104],W[105],W[106],W[107]); SBoxE3(W[108],W[109],W[110],W[111]);
   SBoxE2(W[112],W[113],W[114],W[115]); SBoxE1(W[116],W[117],W[118],W[119]);
   SBoxE8(W[120],W[121],W[122],W[123]); SBoxE7(W[124],W[125],W[126],W[127]);
   SBoxE6(W[128],W[129],W[130],W[131]); SBoxE5(W[132],W[133],W[134],W[135]);
   SBoxE4(W[136],W[137],W[138],W[139]);
   round_key.copy(&W[8], 132);
   }

}
/*
* Serpent (SIMD)
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

#define SBoxE1(B0, B1, B2, B3)                    \
   do {                                           \
      B3 ^= B0;                                   \
      SIMD_32 B4 = B1;                            \
      B1 &= B3;                                   \
      B4 ^= B2;                                   \
      B1 ^= B0;                                   \
      B0 |= B3;                                   \
      B0 ^= B4;                                   \
      B4 ^= B3;                                   \
      B3 ^= B2;                                   \
      B2 |= B1;                                   \
      B2 ^= B4;                                   \
      B4 = ~B4;                                   \
      B4 |= B1;                                   \
      B1 ^= B3;                                   \
      B1 ^= B4;                                   \
      B3 |= B0;                                   \
      B1 ^= B3;                                   \
      B4 ^= B3;                                   \
      B3 = B0;                                    \
      B0 = B1;                                    \
      B1 = B4;                                    \
   } while(0);

#define SBoxE2(B0, B1, B2, B3)                    \
   do {                                           \
      B0 = ~B0;                                   \
      B2 = ~B2;                                   \
      SIMD_32 B4 = B0;                            \
      B0 &= B1;                                   \
      B2 ^= B0;                                   \
      B0 |= B3;                                   \
      B3 ^= B2;                                   \
      B1 ^= B0;                                   \
      B0 ^= B4;                                   \
      B4 |= B1;                                   \
      B1 ^= B3;                                   \
      B2 |= B0;                                   \
      B2 &= B4;                                   \
      B0 ^= B1;                                   \
      B1 &= B2;                                   \
      B1 ^= B0;                                   \
      B0 &= B2;                                   \
      B4 ^= B0;                                   \
      B0 = B2;                                    \
      B2 = B3;                                    \
      B3 = B1;                                    \
      B1 = B4;                                    \
   } while(0);

#define SBoxE3(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B0;                            \
      B0 &= B2;                                   \
      B0 ^= B3;                                   \
      B2 ^= B1;                                   \
      B2 ^= B0;                                   \
      B3 |= B4;                                   \
      B3 ^= B1;                                   \
      B4 ^= B2;                                   \
      B1 = B3;                                    \
      B3 |= B4;                                   \
      B3 ^= B0;                                   \
      B0 &= B1;                                   \
      B4 ^= B0;                                   \
      B1 ^= B3;                                   \
      B1 ^= B4;                                   \
      B0 = B2;                                    \
      B2 = B1;                                    \
      B1 = B3;                                    \
      B3 = ~B4;                                   \
   } while(0);

#define SBoxE4(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B0;                            \
      B0 |= B3;                                   \
      B3 ^= B1;                                   \
      B1 &= B4;                                   \
      B4 ^= B2;                                   \
      B2 ^= B3;                                   \
      B3 &= B0;                                   \
      B4 |= B1;                                   \
      B3 ^= B4;                                   \
      B0 ^= B1;                                   \
      B4 &= B0;                                   \
      B1 ^= B3;                                   \
      B4 ^= B2;                                   \
      B1 |= B0;                                   \
      B1 ^= B2;                                   \
      B0 ^= B3;                                   \
      B2 = B1;                                    \
      B1 |= B3;                                   \
      B0 ^= B1;                                   \
      B1 = B2;                                    \
      B2 = B3;                                    \
      B3 = B4;                                    \
   } while(0);

#define SBoxE5(B0, B1, B2, B3)                    \
   do {                                           \
      B1 ^= B3;                                   \
      B3 = ~B3;                                   \
      B2 ^= B3;                                   \
      B3 ^= B0;                                   \
      SIMD_32 B4 = B1;                            \
      B1 &= B3;                                   \
      B1 ^= B2;                                   \
      B4 ^= B3;                                   \
      B0 ^= B4;                                   \
      B2 &= B4;                                   \
      B2 ^= B0;                                   \
      B0 &= B1;                                   \
      B3 ^= B0;                                   \
      B4 |= B1;                                   \
      B4 ^= B0;                                   \
      B0 |= B3;                                   \
      B0 ^= B2;                                   \
      B2 &= B3;                                   \
      B0 = ~B0;                                   \
      B4 ^= B2;                                   \
      B2 = B0;                                    \
      B0 = B1;                                    \
      B1 = B4;                                    \
   } while(0);

#define SBoxE6(B0, B1, B2, B3)                    \
   do {                                           \
      B0 ^= B1;                                   \
      B1 ^= B3;                                   \
      B3 = ~B3;                                   \
      SIMD_32 B4 = B1;                            \
      B1 &= B0;                                   \
      B2 ^= B3;                                   \
      B1 ^= B2;                                   \
      B2 |= B4;                                   \
      B4 ^= B3;                                   \
      B3 &= B1;                                   \
      B3 ^= B0;                                   \
      B4 ^= B1;                                   \
      B4 ^= B2;                                   \
      B2 ^= B0;                                   \
      B0 &= B3;                                   \
      B2 = ~B2;                                   \
      B0 ^= B4;                                   \
      B4 |= B3;                                   \
      B4 ^= B2;                                   \
      B2 = B0;                                    \
      B0 = B1;                                    \
      B1 = B3;                                    \
      B3 = B4;                                    \
   } while(0);

#define SBoxE7(B0, B1, B2, B3)                    \
   do {                                           \
      B2 = ~B2;                                   \
      SIMD_32 B4 = B3;                            \
      B3 &= B0;                                   \
      B0 ^= B4;                                   \
      B3 ^= B2;                                   \
      B2 |= B4;                                   \
      B1 ^= B3;                                   \
      B2 ^= B0;                                   \
      B0 |= B1;                                   \
      B2 ^= B1;                                   \
      B4 ^= B0;                                   \
      B0 |= B3;                                   \
      B0 ^= B2;                                   \
      B4 ^= B3;                                   \
      B4 ^= B0;                                   \
      B3 = ~B3;                                   \
      B2 &= B4;                                   \
      B3 ^= B2;                                   \
      B2 = B4;                                    \
   } while(0);

#define SBoxE8(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B1;                            \
      B1 |= B2;                                   \
      B1 ^= B3;                                   \
      B4 ^= B2;                                   \
      B2 ^= B1;                                   \
      B3 |= B4;                                   \
      B3 &= B0;                                   \
      B4 ^= B2;                                   \
      B3 ^= B1;                                   \
      B1 |= B4;                                   \
      B1 ^= B0;                                   \
      B0 |= B4;                                   \
      B0 ^= B2;                                   \
      B1 ^= B4;                                   \
      B2 ^= B1;                                   \
      B1 &= B0;                                   \
      B1 ^= B4;                                   \
      B2 = ~B2;                                   \
      B2 |= B0;                                   \
      B4 ^= B2;                                   \
      B2 = B1;                                    \
      B1 = B3;                                    \
      B3 = B0;                                    \
      B0 = B4;                                    \
   } while(0);

#define SBoxD1(B0, B1, B2, B3)                    \
   do {                                           \
      B2 = ~B2;                                   \
      SIMD_32 B4 = B1;                            \
      B1 |= B0;                                   \
      B4 = ~B4;                                   \
      B1 ^= B2;                                   \
      B2 |= B4;                                   \
      B1 ^= B3;                                   \
      B0 ^= B4;                                   \
      B2 ^= B0;                                   \
      B0 &= B3;                                   \
      B4 ^= B0;                                   \
      B0 |= B1;                                   \
      B0 ^= B2;                                   \
      B3 ^= B4;                                   \
      B2 ^= B1;                                   \
      B3 ^= B0;                                   \
      B3 ^= B1;                                   \
      B2 &= B3;                                   \
      B4 ^= B2;                                   \
      B2 = B1;                                    \
      B1 = B4;                                    \
      } while(0);

#define SBoxD2(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B1;                            \
      B1 ^= B3;                                   \
      B3 &= B1;                                   \
      B4 ^= B2;                                   \
      B3 ^= B0;                                   \
      B0 |= B1;                                   \
      B2 ^= B3;                                   \
      B0 ^= B4;                                   \
      B0 |= B2;                                   \
      B1 ^= B3;                                   \
      B0 ^= B1;                                   \
      B1 |= B3;                                   \
      B1 ^= B0;                                   \
      B4 = ~B4;                                   \
      B4 ^= B1;                                   \
      B1 |= B0;                                   \
      B1 ^= B0;                                   \
      B1 |= B4;                                   \
      B3 ^= B1;                                   \
      B1 = B0;                                    \
      B0 = B4;                                    \
      B4 = B2;                                    \
      B2 = B3;                                    \
      B3 = B4;                                    \
      } while(0);

#define SBoxD3(B0, B1, B2, B3)                    \
   do {                                           \
      B2 ^= B3;                                   \
      B3 ^= B0;                                   \
      SIMD_32 B4 = B3;                            \
      B3 &= B2;                                   \
      B3 ^= B1;                                   \
      B1 |= B2;                                   \
      B1 ^= B4;                                   \
      B4 &= B3;                                   \
      B2 ^= B3;                                   \
      B4 &= B0;                                   \
      B4 ^= B2;                                   \
      B2 &= B1;                                   \
      B2 |= B0;                                   \
      B3 = ~B3;                                   \
      B2 ^= B3;                                   \
      B0 ^= B3;                                   \
      B0 &= B1;                                   \
      B3 ^= B4;                                   \
      B3 ^= B0;                                   \
      B0 = B1;                                    \
      B1 = B4;                                    \
      } while(0);

#define SBoxD4(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B2;                            \
      B2 ^= B1;                                   \
      B0 ^= B2;                                   \
      B4 &= B2;                                   \
      B4 ^= B0;                                   \
      B0 &= B1;                                   \
      B1 ^= B3;                                   \
      B3 |= B4;                                   \
      B2 ^= B3;                                   \
      B0 ^= B3;                                   \
      B1 ^= B4;                                   \
      B3 &= B2;                                   \
      B3 ^= B1;                                   \
      B1 ^= B0;                                   \
      B1 |= B2;                                   \
      B0 ^= B3;                                   \
      B1 ^= B4;                                   \
      B0 ^= B1;                                   \
      B4 = B0;                                    \
      B0 = B2;                                    \
      B2 = B3;                                    \
      B3 = B4;                                    \
      } while(0);

#define SBoxD5(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B2;                            \
      B2 &= B3;                                   \
      B2 ^= B1;                                   \
      B1 |= B3;                                   \
      B1 &= B0;                                   \
      B4 ^= B2;                                   \
      B4 ^= B1;                                   \
      B1 &= B2;                                   \
      B0 = ~B0;                                   \
      B3 ^= B4;                                   \
      B1 ^= B3;                                   \
      B3 &= B0;                                   \
      B3 ^= B2;                                   \
      B0 ^= B1;                                   \
      B2 &= B0;                                   \
      B3 ^= B0;                                   \
      B2 ^= B4;                                   \
      B2 |= B3;                                   \
      B3 ^= B0;                                   \
      B2 ^= B1;                                   \
      B1 = B3;                                    \
      B3 = B4;                                    \
      } while(0);

#define SBoxD6(B0, B1, B2, B3)                    \
   do {                                           \
      B1 = ~B1;                                   \
      SIMD_32 B4 = B3;                            \
      B2 ^= B1;                                   \
      B3 |= B0;                                   \
      B3 ^= B2;                                   \
      B2 |= B1;                                   \
      B2 &= B0;                                   \
      B4 ^= B3;                                   \
      B2 ^= B4;                                   \
      B4 |= B0;                                   \
      B4 ^= B1;                                   \
      B1 &= B2;                                   \
      B1 ^= B3;                                   \
      B4 ^= B2;                                   \
      B3 &= B4;                                   \
      B4 ^= B1;                                   \
      B3 ^= B4;                                   \
      B4 = ~B4;                                   \
      B3 ^= B0;                                   \
      B0 = B1;                                    \
      B1 = B4;                                    \
      B4 = B3;                                    \
      B3 = B2;                                    \
      B2 = B4;                                    \
      } while(0);

#define SBoxD7(B0, B1, B2, B3)                    \
   do {                                           \
      B0 ^= B2;                                   \
      SIMD_32 B4 = B2;                            \
      B2 &= B0;                                   \
      B4 ^= B3;                                   \
      B2 = ~B2;                                   \
      B3 ^= B1;                                   \
      B2 ^= B3;                                   \
      B4 |= B0;                                   \
      B0 ^= B2;                                   \
      B3 ^= B4;                                   \
      B4 ^= B1;                                   \
      B1 &= B3;                                   \
      B1 ^= B0;                                   \
      B0 ^= B3;                                   \
      B0 |= B2;                                   \
      B3 ^= B1;                                   \
      B4 ^= B0;                                   \
      B0 = B1;                                    \
      B1 = B2;                                    \
      B2 = B4;                                    \
      } while(0);

#define SBoxD8(B0, B1, B2, B3)                    \
   do {                                           \
      SIMD_32 B4 = B2;                            \
      B2 ^= B0;                                   \
      B0 &= B3;                                   \
      B4 |= B3;                                   \
      B2 = ~B2;                                   \
      B3 ^= B1;                                   \
      B1 |= B0;                                   \
      B0 ^= B2;                                   \
      B2 &= B4;                                   \
      B3 &= B4;                                   \
      B1 ^= B2;                                   \
      B2 ^= B0;                                   \
      B0 |= B2;                                   \
      B4 ^= B1;                                   \
      B0 ^= B3;                                   \
      B3 ^= B4;                                   \
      B4 |= B0;                                   \
      B3 ^= B2;                                   \
      B4 ^= B2;                                   \
      B2 = B1;                                    \
      B1 = B0;                                    \
      B0 = B3;                                    \
      B3 = B4;                                    \
      } while(0);

#define key_xor(round, B0, B1, B2, B3)                             \
   do {                                                            \
      B0 ^= SIMD_32(keys[4*round  ]);                              \
      B1 ^= SIMD_32(keys[4*round+1]);                              \
      B2 ^= SIMD_32(keys[4*round+2]);                              \
      B3 ^= SIMD_32(keys[4*round+3]);                              \
   } while(0);

/*
* Serpent's linear transformations
*/
#define transform(B0, B1, B2, B3)                                  \
   do {                                                            \
      B0.rotate_left(13);                                          \
      B2.rotate_left(3);                                           \
      B1 ^= B0 ^ B2;                                               \
      B3 ^= B2 ^ (B0 << 3);                                        \
      B1.rotate_left(1);                                           \
      B3.rotate_left(7);                                           \
      B0 ^= B1 ^ B3;                                               \
      B2 ^= B3 ^ (B1 << 7);                                        \
      B0.rotate_left(5);                                           \
      B2.rotate_left(22);                                          \
   } while(0);

#define i_transform(B0, B1, B2, B3)                                \
   do {                                                            \
      B2.rotate_right(22);                                         \
      B0.rotate_right(5);                                          \
      B2 ^= B3 ^ (B1 << 7);                                        \
      B0 ^= B1 ^ B3;                                               \
      B3.rotate_right(7);                                          \
      B1.rotate_right(1);                                          \
      B3 ^= B2 ^ (B0 << 3);                                        \
      B1 ^= B0 ^ B2;                                               \
      B2.rotate_right(3);                                          \
      B0.rotate_right(13);                                         \
   } while(0);

/*
* SIMD Serpent Encryption of 4 blocks in parallel
*/
void serpent_encrypt_4(const byte in[64],
                       byte out[64],
                       const u32bit keys[132])
   {
   SIMD_32 B0 = SIMD_32::load_le(in);
   SIMD_32 B1 = SIMD_32::load_le(in + 16);
   SIMD_32 B2 = SIMD_32::load_le(in + 32);
   SIMD_32 B3 = SIMD_32::load_le(in + 48);

   SIMD_32::transpose(B0, B1, B2, B3);

   key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);

   key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);

   key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);

   key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
   key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3);

   SIMD_32::transpose(B0, B1, B2, B3);

   B0.store_le(out);
   B1.store_le(out + 16);
   B2.store_le(out + 32);
   B3.store_le(out + 48);
   }

/*
* SIMD Serpent Decryption of 4 blocks in parallel
*/
void serpent_decrypt_4(const byte in[64],
                       byte out[64],
                       const u32bit keys[132])
   {
   SIMD_32 B0 = SIMD_32::load_le(in);
   SIMD_32 B1 = SIMD_32::load_le(in + 16);
   SIMD_32 B2 = SIMD_32::load_le(in + 32);
   SIMD_32 B3 = SIMD_32::load_le(in + 48);

   SIMD_32::transpose(B0, B1, B2, B3);

   key_xor(32,B0,B1,B2,B3);  SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3);

   i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3);

   i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3);

   i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3);
   i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3);

   SIMD_32::transpose(B0, B1, B2, B3);

   B0.store_le(out);
   B1.store_le(out + 16);
   B2.store_le(out + 32);
   B3.store_le(out + 48);
   }

}

#undef key_xor
#undef transform
#undef i_transform

#undef SBoxE1
#undef SBoxE2
#undef SBoxE3
#undef SBoxE4
#undef SBoxE5
#undef SBoxE6
#undef SBoxE7
#undef SBoxE8

#undef SBoxD1
#undef SBoxD2
#undef SBoxD3
#undef SBoxD4
#undef SBoxD5
#undef SBoxD6
#undef SBoxD7
#undef SBoxD8

/*
* Serpent Encryption
*/
void Serpent_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* KS = &(this->get_round_keys()[0]);

   while(blocks >= 4)
      {
      serpent_encrypt_4(in, out, KS);
      in += 4 * BLOCK_SIZE;
      out += 4 * BLOCK_SIZE;
      blocks -= 4;
      }

   if(blocks)
     Serpent::encrypt_n(in, out, blocks);
   }

/*
* Serpent Decryption
*/
void Serpent_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* KS = &(this->get_round_keys()[0]);

   while(blocks >= 4)
      {
      serpent_decrypt_4(in, out, KS);
      in += 4 * BLOCK_SIZE;
      out += 4 * BLOCK_SIZE;
      blocks -= 4;
      }

   if(blocks)
     Serpent::decrypt_n(in, out, blocks);
   }

}
/*
* Skipjack
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Skipjack Stepping Rule 'A'
*/
void step_A(u16bit& W1, u16bit& W4, size_t round, const byte FTAB[])
   {
   byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3;

   G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1;
   G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2;
   G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3;
   G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1;

   W1 =  make_u16bit(G2, G3);
   W4 ^= W1 ^ round;
   }

/*
* Skipjack Stepping Rule 'B'
*/
void step_B(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[])
   {
   W2 ^= W1 ^ round;
   byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3;
   G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1;
   G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2;
   G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3;
   G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1;
   W1 =  make_u16bit(G2, G3);
   }

/*
* Skipjack Invserse Stepping Rule 'A'
*/
void step_Ai(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[])
   {
   W1 ^= W2 ^ round;
   byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3;
   G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1;
   G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2;
   G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3;
   G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1;
   W2 = make_u16bit(G3, G2);
   }

/*
* Skipjack Invserse Stepping Rule 'B'
*/
void step_Bi(u16bit& W2, u16bit& W3, size_t round, const byte FTAB[])
   {
   byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3;
   G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1;
   G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2;
   G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3;
   G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1;
   W2 = make_u16bit(G3, G2);
   W3 ^= W2 ^ round;
   }

}

/*
* Skipjack Encryption
*/
void Skipjack::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const byte* ftab = &FTAB[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit W1 = load_le<u16bit>(in, 3);
      u16bit W2 = load_le<u16bit>(in, 2);
      u16bit W3 = load_le<u16bit>(in, 1);
      u16bit W4 = load_le<u16bit>(in, 0);

      step_A(W1, W4,  1, ftab); step_A(W4, W3,  2, ftab);
      step_A(W3, W2,  3, ftab); step_A(W2, W1,  4, ftab);
      step_A(W1, W4,  5, ftab); step_A(W4, W3,  6, ftab);
      step_A(W3, W2,  7, ftab); step_A(W2, W1,  8, ftab);

      step_B(W1, W2,  9, ftab); step_B(W4, W1, 10, ftab);
      step_B(W3, W4, 11, ftab); step_B(W2, W3, 12, ftab);
      step_B(W1, W2, 13, ftab); step_B(W4, W1, 14, ftab);
      step_B(W3, W4, 15, ftab); step_B(W2, W3, 16, ftab);

      step_A(W1, W4, 17, ftab); step_A(W4, W3, 18, ftab);
      step_A(W3, W2, 19, ftab); step_A(W2, W1, 20, ftab);
      step_A(W1, W4, 21, ftab); step_A(W4, W3, 22, ftab);
      step_A(W3, W2, 23, ftab); step_A(W2, W1, 24, ftab);

      step_B(W1, W2, 25, ftab); step_B(W4, W1, 26, ftab);
      step_B(W3, W4, 27, ftab); step_B(W2, W3, 28, ftab);
      step_B(W1, W2, 29, ftab); step_B(W4, W1, 30, ftab);
      step_B(W3, W4, 31, ftab); step_B(W2, W3, 32, ftab);

      store_le(out, W4, W3, W2, W1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Skipjack Decryption
*/
void Skipjack::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const byte* ftab = &FTAB[0];

   for(size_t i = 0; i != blocks; ++i)
      {
      u16bit W1 = load_le<u16bit>(in, 3);
      u16bit W2 = load_le<u16bit>(in, 2);
      u16bit W3 = load_le<u16bit>(in, 1);
      u16bit W4 = load_le<u16bit>(in, 0);

      step_Bi(W2, W3, 32, ftab); step_Bi(W3, W4, 31, ftab);
      step_Bi(W4, W1, 30, ftab); step_Bi(W1, W2, 29, ftab);
      step_Bi(W2, W3, 28, ftab); step_Bi(W3, W4, 27, ftab);
      step_Bi(W4, W1, 26, ftab); step_Bi(W1, W2, 25, ftab);

      step_Ai(W1, W2, 24, ftab); step_Ai(W2, W3, 23, ftab);
      step_Ai(W3, W4, 22, ftab); step_Ai(W4, W1, 21, ftab);
      step_Ai(W1, W2, 20, ftab); step_Ai(W2, W3, 19, ftab);
      step_Ai(W3, W4, 18, ftab); step_Ai(W4, W1, 17, ftab);

      step_Bi(W2, W3, 16, ftab); step_Bi(W3, W4, 15, ftab);
      step_Bi(W4, W1, 14, ftab); step_Bi(W1, W2, 13, ftab);
      step_Bi(W2, W3, 12, ftab); step_Bi(W3, W4, 11, ftab);
      step_Bi(W4, W1, 10, ftab); step_Bi(W1, W2,  9, ftab);

      step_Ai(W1, W2,  8, ftab); step_Ai(W2, W3,  7, ftab);
      step_Ai(W3, W4,  6, ftab); step_Ai(W4, W1,  5, ftab);
      step_Ai(W1, W2,  4, ftab); step_Ai(W2, W3,  3, ftab);
      step_Ai(W3, W4,  2, ftab); step_Ai(W4, W1,  1, ftab);

      store_le(out, W4, W3, W2, W1);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Skipjack Key Schedule
*/
void Skipjack::key_schedule(const byte key[], size_t)
   {
   static const byte F[256] = {
      0xA3, 0xD7, 0x09, 0x83, 0xF8, 0x48, 0xF6, 0xF4, 0xB3, 0x21, 0x15, 0x78,
      0x99, 0xB1, 0xAF, 0xF9, 0xE7, 0x2D, 0x4D, 0x8A, 0xCE, 0x4C, 0xCA, 0x2E,
      0x52, 0x95, 0xD9, 0x1E, 0x4E, 0x38, 0x44, 0x28, 0x0A, 0xDF, 0x02, 0xA0,
      0x17, 0xF1, 0x60, 0x68, 0x12, 0xB7, 0x7A, 0xC3, 0xE9, 0xFA, 0x3D, 0x53,
      0x96, 0x84, 0x6B, 0xBA, 0xF2, 0x63, 0x9A, 0x19, 0x7C, 0xAE, 0xE5, 0xF5,
      0xF7, 0x16, 0x6A, 0xA2, 0x39, 0xB6, 0x7B, 0x0F, 0xC1, 0x93, 0x81, 0x1B,
      0xEE, 0xB4, 0x1A, 0xEA, 0xD0, 0x91, 0x2F, 0xB8, 0x55, 0xB9, 0xDA, 0x85,
      0x3F, 0x41, 0xBF, 0xE0, 0x5A, 0x58, 0x80, 0x5F, 0x66, 0x0B, 0xD8, 0x90,
      0x35, 0xD5, 0xC0, 0xA7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56,
      0x6D, 0x98, 0x9B, 0x76, 0x97, 0xFC, 0xB2, 0xC2, 0xB0, 0xFE, 0xDB, 0x20,
      0xE1, 0xEB, 0xD6, 0xE4, 0xDD, 0x47, 0x4A, 0x1D, 0x42, 0xED, 0x9E, 0x6E,
      0x49, 0x3C, 0xCD, 0x43, 0x27, 0xD2, 0x07, 0xD4, 0xDE, 0xC7, 0x67, 0x18,
      0x89, 0xCB, 0x30, 0x1F, 0x8D, 0xC6, 0x8F, 0xAA, 0xC8, 0x74, 0xDC, 0xC9,
      0x5D, 0x5C, 0x31, 0xA4, 0x70, 0x88, 0x61, 0x2C, 0x9F, 0x0D, 0x2B, 0x87,
      0x50, 0x82, 0x54, 0x64, 0x26, 0x7D, 0x03, 0x40, 0x34, 0x4B, 0x1C, 0x73,
      0xD1, 0xC4, 0xFD, 0x3B, 0xCC, 0xFB, 0x7F, 0xAB, 0xE6, 0x3E, 0x5B, 0xA5,
      0xAD, 0x04, 0x23, 0x9C, 0x14, 0x51, 0x22, 0xF0, 0x29, 0x79, 0x71, 0x7E,
      0xFF, 0x8C, 0x0E, 0xE2, 0x0C, 0xEF, 0xBC, 0x72, 0x75, 0x6F, 0x37, 0xA1,
      0xEC, 0xD3, 0x8E, 0x62, 0x8B, 0x86, 0x10, 0xE8, 0x08, 0x77, 0x11, 0xBE,
      0x92, 0x4F, 0x24, 0xC5, 0x32, 0x36, 0x9D, 0xCF, 0xF3, 0xA6, 0xBB, 0xAC,
      0x5E, 0x6C, 0xA9, 0x13, 0x57, 0x25, 0xB5, 0xE3, 0xBD, 0xA8, 0x3A, 0x01,
      0x05, 0x59, 0x2A, 0x46 };

   for(size_t i = 0; i != 10; ++i)
      for(size_t j = 0; j != 256; ++j)
         FTAB[256*i+j] = F[j ^ key[9-i]];
   }

/*
* Clear memory of sensitive data
*/
void Skipjack::clear()
   {
   zeroise(FTAB);
   }

}
/*
* S-Box and Diffusion Tables for Square
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const byte Square::SE[256] = {
0xB1, 0xCE, 0xC3, 0x95, 0x5A, 0xAD, 0xE7, 0x02, 0x4D, 0x44, 0xFB, 0x91, 0x0C,
0x87, 0xA1, 0x50, 0xCB, 0x67, 0x54, 0xDD, 0x46, 0x8F, 0xE1, 0x4E, 0xF0, 0xFD,
0xFC, 0xEB, 0xF9, 0xC4, 0x1A, 0x6E, 0x5E, 0xF5, 0xCC, 0x8D, 0x1C, 0x56, 0x43,
0xFE, 0x07, 0x61, 0xF8, 0x75, 0x59, 0xFF, 0x03, 0x22, 0x8A, 0xD1, 0x13, 0xEE,
0x88, 0x00, 0x0E, 0x34, 0x15, 0x80, 0x94, 0xE3, 0xED, 0xB5, 0x53, 0x23, 0x4B,
0x47, 0x17, 0xA7, 0x90, 0x35, 0xAB, 0xD8, 0xB8, 0xDF, 0x4F, 0x57, 0x9A, 0x92,
0xDB, 0x1B, 0x3C, 0xC8, 0x99, 0x04, 0x8E, 0xE0, 0xD7, 0x7D, 0x85, 0xBB, 0x40,
0x2C, 0x3A, 0x45, 0xF1, 0x42, 0x65, 0x20, 0x41, 0x18, 0x72, 0x25, 0x93, 0x70,
0x36, 0x05, 0xF2, 0x0B, 0xA3, 0x79, 0xEC, 0x08, 0x27, 0x31, 0x32, 0xB6, 0x7C,
0xB0, 0x0A, 0x73, 0x5B, 0x7B, 0xB7, 0x81, 0xD2, 0x0D, 0x6A, 0x26, 0x9E, 0x58,
0x9C, 0x83, 0x74, 0xB3, 0xAC, 0x30, 0x7A, 0x69, 0x77, 0x0F, 0xAE, 0x21, 0xDE,
0xD0, 0x2E, 0x97, 0x10, 0xA4, 0x98, 0xA8, 0xD4, 0x68, 0x2D, 0x62, 0x29, 0x6D,
0x16, 0x49, 0x76, 0xC7, 0xE8, 0xC1, 0x96, 0x37, 0xE5, 0xCA, 0xF4, 0xE9, 0x63,
0x12, 0xC2, 0xA6, 0x14, 0xBC, 0xD3, 0x28, 0xAF, 0x2F, 0xE6, 0x24, 0x52, 0xC6,
0xA0, 0x09, 0xBD, 0x8C, 0xCF, 0x5D, 0x11, 0x5F, 0x01, 0xC5, 0x9F, 0x3D, 0xA2,
0x9B, 0xC9, 0x3B, 0xBE, 0x51, 0x19, 0x1F, 0x3F, 0x5C, 0xB2, 0xEF, 0x4A, 0xCD,
0xBF, 0xBA, 0x6F, 0x64, 0xD9, 0xF3, 0x3E, 0xB4, 0xAA, 0xDC, 0xD5, 0x06, 0xC0,
0x7E, 0xF6, 0x66, 0x6C, 0x84, 0x71, 0x38, 0xB9, 0x1D, 0x7F, 0x9D, 0x48, 0x8B,
0x2A, 0xDA, 0xA5, 0x33, 0x82, 0x39, 0xD6, 0x78, 0x86, 0xFA, 0xE4, 0x2B, 0xA9,
0x1E, 0x89, 0x60, 0x6B, 0xEA, 0x55, 0x4C, 0xF7, 0xE2 };

const byte Square::SD[256] = {
0x35, 0xBE, 0x07, 0x2E, 0x53, 0x69, 0xDB, 0x28, 0x6F, 0xB7, 0x76, 0x6B, 0x0C,
0x7D, 0x36, 0x8B, 0x92, 0xBC, 0xA9, 0x32, 0xAC, 0x38, 0x9C, 0x42, 0x63, 0xC8,
0x1E, 0x4F, 0x24, 0xE5, 0xF7, 0xC9, 0x61, 0x8D, 0x2F, 0x3F, 0xB3, 0x65, 0x7F,
0x70, 0xAF, 0x9A, 0xEA, 0xF5, 0x5B, 0x98, 0x90, 0xB1, 0x87, 0x71, 0x72, 0xED,
0x37, 0x45, 0x68, 0xA3, 0xE3, 0xEF, 0x5C, 0xC5, 0x50, 0xC1, 0xD6, 0xCA, 0x5A,
0x62, 0x5F, 0x26, 0x09, 0x5D, 0x14, 0x41, 0xE8, 0x9D, 0xCE, 0x40, 0xFD, 0x08,
0x17, 0x4A, 0x0F, 0xC7, 0xB4, 0x3E, 0x12, 0xFC, 0x25, 0x4B, 0x81, 0x2C, 0x04,
0x78, 0xCB, 0xBB, 0x20, 0xBD, 0xF9, 0x29, 0x99, 0xA8, 0xD3, 0x60, 0xDF, 0x11,
0x97, 0x89, 0x7E, 0xFA, 0xE0, 0x9B, 0x1F, 0xD2, 0x67, 0xE2, 0x64, 0x77, 0x84,
0x2B, 0x9E, 0x8A, 0xF1, 0x6D, 0x88, 0x79, 0x74, 0x57, 0xDD, 0xE6, 0x39, 0x7B,
0xEE, 0x83, 0xE1, 0x58, 0xF2, 0x0D, 0x34, 0xF8, 0x30, 0xE9, 0xB9, 0x23, 0x54,
0x15, 0x44, 0x0B, 0x4D, 0x66, 0x3A, 0x03, 0xA2, 0x91, 0x94, 0x52, 0x4C, 0xC3,
0x82, 0xE7, 0x80, 0xC0, 0xB6, 0x0E, 0xC2, 0x6C, 0x93, 0xEC, 0xAB, 0x43, 0x95,
0xF6, 0xD8, 0x46, 0x86, 0x05, 0x8C, 0xB0, 0x75, 0x00, 0xCC, 0x85, 0xD7, 0x3D,
0x73, 0x7A, 0x48, 0xE4, 0xD1, 0x59, 0xAD, 0xB8, 0xC6, 0xD0, 0xDC, 0xA1, 0xAA,
0x02, 0x1D, 0xBF, 0xB5, 0x9F, 0x51, 0xC4, 0xA5, 0x10, 0x22, 0xCF, 0x01, 0xBA,
0x8F, 0x31, 0x7C, 0xAE, 0x96, 0xDA, 0xF0, 0x56, 0x47, 0xD4, 0xEB, 0x4E, 0xD9,
0x13, 0x8E, 0x49, 0x55, 0x16, 0xFF, 0x3B, 0xF4, 0xA4, 0xB2, 0x06, 0xA0, 0xA7,
0xFB, 0x1B, 0x6E, 0x3C, 0x33, 0xCD, 0x18, 0x5E, 0x6A, 0xD5, 0xA6, 0x21, 0xDE,
0xFE, 0x2A, 0x1C, 0xF3, 0x0A, 0x1A, 0x19, 0x27, 0x2D };

const byte Square::Log[256] = {
0x00, 0x00, 0x01, 0x86, 0x02, 0x0D, 0x87, 0x4C, 0x03, 0xD2, 0x0E, 0xAE, 0x88,
0x22, 0x4D, 0x93, 0x04, 0x1A, 0xD3, 0xCB, 0x0F, 0x98, 0xAF, 0xA8, 0x89, 0xF0,
0x23, 0x59, 0x4E, 0x35, 0x94, 0x09, 0x05, 0x8F, 0x1B, 0x6E, 0xD4, 0x39, 0xCC,
0xBB, 0x10, 0x68, 0x99, 0x77, 0xB0, 0xDF, 0xA9, 0x72, 0x8A, 0xFA, 0xF1, 0xA0,
0x24, 0x52, 0x5A, 0x60, 0x4F, 0x2F, 0x36, 0xDC, 0x95, 0x32, 0x0A, 0x1F, 0x06,
0xA5, 0x90, 0x49, 0x1C, 0x5D, 0x6F, 0xB8, 0xD5, 0xC1, 0x3A, 0xB5, 0xCD, 0x63,
0xBC, 0x3D, 0x11, 0x44, 0x69, 0x81, 0x9A, 0x27, 0x78, 0xC4, 0xB1, 0xE6, 0xE0,
0xEA, 0xAA, 0x55, 0x73, 0xD8, 0x8B, 0xF6, 0xFB, 0x16, 0xF2, 0xF4, 0xA1, 0x40,
0x25, 0x42, 0x53, 0xE4, 0x5B, 0xA3, 0x61, 0xBF, 0x50, 0xF8, 0x30, 0x2D, 0x37,
0x8D, 0xDD, 0x66, 0x96, 0x18, 0x33, 0xEE, 0x0B, 0xFD, 0x20, 0xD0, 0x07, 0x57,
0xA6, 0xC9, 0x91, 0xAC, 0x4A, 0x84, 0x1D, 0xDA, 0x5E, 0x9E, 0x70, 0x75, 0xB9,
0x6C, 0xD6, 0xE8, 0xC2, 0x7F, 0x3B, 0xB3, 0xB6, 0x47, 0xCE, 0xEC, 0x64, 0x2B,
0xBD, 0xE2, 0x3E, 0x14, 0x12, 0x29, 0x45, 0x7D, 0x6A, 0x9C, 0x82, 0xC7, 0x9B,
0xC6, 0x28, 0x7C, 0x79, 0x7A, 0xC5, 0x7B, 0xB2, 0x46, 0xE7, 0x7E, 0xE1, 0x13,
0xEB, 0x2A, 0xAB, 0x83, 0x56, 0xC8, 0x74, 0x6B, 0xD9, 0x9D, 0x8C, 0x65, 0xF7,
0x2C, 0xFC, 0xCF, 0x17, 0xED, 0xF3, 0x3F, 0xF5, 0x15, 0xA2, 0xBE, 0x41, 0xE3,
0x26, 0xC3, 0x43, 0x80, 0x54, 0xD7, 0xE5, 0xE9, 0x5C, 0xB7, 0xA4, 0x48, 0x62,
0x3C, 0xC0, 0xB4, 0x51, 0x5F, 0xF9, 0x9F, 0x31, 0x1E, 0x2E, 0xDB, 0x38, 0xBA,
0x8E, 0x6D, 0xDE, 0x71, 0x67, 0x76, 0x97, 0xA7, 0x19, 0xCA, 0x34, 0x08, 0xEF,
0x58, 0x0C, 0x4B, 0xFE, 0x85, 0x21, 0x92, 0xD1, 0xAD };

const byte Square::ALog[255] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF5, 0x1F, 0x3E, 0x7C, 0xF8,
0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0xB5, 0x9F, 0xCB, 0x63, 0xC6, 0x79, 0xF2,
0x11, 0x22, 0x44, 0x88, 0xE5, 0x3F, 0x7E, 0xFC, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
0x55, 0xAA, 0xA1, 0xB7, 0x9B, 0xC3, 0x73, 0xE6, 0x39, 0x72, 0xE4, 0x3D, 0x7A,
0xF4, 0x1D, 0x3A, 0x74, 0xE8, 0x25, 0x4A, 0x94, 0xDD, 0x4F, 0x9E, 0xC9, 0x67,
0xCE, 0x69, 0xD2, 0x51, 0xA2, 0xB1, 0x97, 0xDB, 0x43, 0x86, 0xF9, 0x07, 0x0E,
0x1C, 0x38, 0x70, 0xE0, 0x35, 0x6A, 0xD4, 0x5D, 0xBA, 0x81, 0xF7, 0x1B, 0x36,
0x6C, 0xD8, 0x45, 0x8A, 0xE1, 0x37, 0x6E, 0xDC, 0x4D, 0x9A, 0xC1, 0x77, 0xEE,
0x29, 0x52, 0xA4, 0xBD, 0x8F, 0xEB, 0x23, 0x46, 0x8C, 0xED, 0x2F, 0x5E, 0xBC,
0x8D, 0xEF, 0x2B, 0x56, 0xAC, 0xAD, 0xAF, 0xAB, 0xA3, 0xB3, 0x93, 0xD3, 0x53,
0xA6, 0xB9, 0x87, 0xFB, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x75, 0xEA,
0x21, 0x42, 0x84, 0xFD, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x15, 0x2A, 0x54, 0xA8,
0xA5, 0xBF, 0x8B, 0xE3, 0x33, 0x66, 0xCC, 0x6D, 0xDA, 0x41, 0x82, 0xF1, 0x17,
0x2E, 0x5C, 0xB8, 0x85, 0xFF, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x95, 0xDF, 0x4B,
0x96, 0xD9, 0x47, 0x8E, 0xE9, 0x27, 0x4E, 0x9C, 0xCD, 0x6F, 0xDE, 0x49, 0x92,
0xD1, 0x57, 0xAE, 0xA9, 0xA7, 0xBB, 0x83, 0xF3, 0x13, 0x26, 0x4C, 0x98, 0xC5,
0x7F, 0xFE, 0x09, 0x12, 0x24, 0x48, 0x90, 0xD5, 0x5F, 0xBE, 0x89, 0xE7, 0x3B,
0x76, 0xEC, 0x2D, 0x5A, 0xB4, 0x9D, 0xCF, 0x6B, 0xD6, 0x59, 0xB2, 0x91, 0xD7,
0x5B, 0xB6, 0x99, 0xC7, 0x7B, 0xF6, 0x19, 0x32, 0x64, 0xC8, 0x65, 0xCA, 0x61,
0xC2, 0x71, 0xE2, 0x31, 0x62, 0xC4, 0x7D, 0xFA };

const u32bit Square::TE0[256] = {
0x97B1B126, 0x69CECEA7, 0x73C3C3B0, 0xDF95954A, 0xB45A5AEE, 0xAFADAD02,
0x3BE7E7DC, 0x04020206, 0x9A4D4DD7, 0x884444CC, 0x03FBFBF8, 0xD7919146,
0x180C0C14, 0xFB87877C, 0xB7A1A116, 0xA05050F0, 0x63CBCBA8, 0xCE6767A9,
0xA85454FC, 0x4FDDDD92, 0x8C4646CA, 0xEB8F8F64, 0x37E1E1D6, 0x9C4E4ED2,
0x15F0F0E5, 0x0FFDFDF2, 0x0DFCFCF1, 0x23EBEBC8, 0x07F9F9FE, 0x7DC4C4B9,
0x341A1A2E, 0xDC6E6EB2, 0xBC5E5EE2, 0x1FF5F5EA, 0x6DCCCCA1, 0xEF8D8D62,
0x381C1C24, 0xAC5656FA, 0x864343C5, 0x09FEFEF7, 0x0E070709, 0xC26161A3,
0x05F8F8FD, 0xEA75759F, 0xB25959EB, 0x0BFFFFF4, 0x06030305, 0x44222266,
0xE18A8A6B, 0x57D1D186, 0x26131335, 0x29EEEEC7, 0xE588886D, 0x00000000,
0x1C0E0E12, 0x6834345C, 0x2A15153F, 0xF5808075, 0xDD949449, 0x33E3E3D0,
0x2FEDEDC2, 0x9FB5B52A, 0xA65353F5, 0x46232365, 0x964B4BDD, 0x8E4747C9,
0x2E171739, 0xBBA7A71C, 0xD5909045, 0x6A35355F, 0xA3ABAB08, 0x45D8D89D,
0x85B8B83D, 0x4BDFDF94, 0x9E4F4FD1, 0xAE5757F9, 0xC19A9A5B, 0xD1929243,
0x43DBDB98, 0x361B1B2D, 0x783C3C44, 0x65C8C8AD, 0xC799995E, 0x0804040C,
0xE98E8E67, 0x35E0E0D5, 0x5BD7D78C, 0xFA7D7D87, 0xFF85857A, 0x83BBBB38,
0x804040C0, 0x582C2C74, 0x743A3A4E, 0x8A4545CF, 0x17F1F1E6, 0x844242C6,
0xCA6565AF, 0x40202060, 0x824141C3, 0x30181828, 0xE4727296, 0x4A25256F,
0xD3939340, 0xE0707090, 0x6C36365A, 0x0A05050F, 0x11F2F2E3, 0x160B0B1D,
0xB3A3A310, 0xF279798B, 0x2DECECC1, 0x10080818, 0x4E272769, 0x62313153,
0x64323256, 0x99B6B62F, 0xF87C7C84, 0x95B0B025, 0x140A0A1E, 0xE6737395,
0xB65B5BED, 0xF67B7B8D, 0x9BB7B72C, 0xF7818176, 0x51D2D283, 0x1A0D0D17,
0xD46A6ABE, 0x4C26266A, 0xC99E9E57, 0xB05858E8, 0xCD9C9C51, 0xF3838370,
0xE874749C, 0x93B3B320, 0xADACAC01, 0x60303050, 0xF47A7A8E, 0xD26969BB,
0xEE777799, 0x1E0F0F11, 0xA9AEAE07, 0x42212163, 0x49DEDE97, 0x55D0D085,
0x5C2E2E72, 0xDB97974C, 0x20101030, 0xBDA4A419, 0xC598985D, 0xA5A8A80D,
0x5DD4D489, 0xD06868B8, 0x5A2D2D77, 0xC46262A6, 0x5229297B, 0xDA6D6DB7,
0x2C16163A, 0x924949DB, 0xEC76769A, 0x7BC7C7BC, 0x25E8E8CD, 0x77C1C1B6,
0xD996964F, 0x6E373759, 0x3FE5E5DA, 0x61CACAAB, 0x1DF4F4E9, 0x27E9E9CE,
0xC66363A5, 0x24121236, 0x71C2C2B3, 0xB9A6A61F, 0x2814143C, 0x8DBCBC31,
0x53D3D380, 0x50282878, 0xABAFAF04, 0x5E2F2F71, 0x39E6E6DF, 0x4824246C,
0xA45252F6, 0x79C6C6BF, 0xB5A0A015, 0x1209091B, 0x8FBDBD32, 0xED8C8C61,
0x6BCFCFA4, 0xBA5D5DE7, 0x22111133, 0xBE5F5FE1, 0x02010103, 0x7FC5C5BA,
0xCB9F9F54, 0x7A3D3D47, 0xB1A2A213, 0xC39B9B58, 0x67C9C9AE, 0x763B3B4D,
0x89BEBE37, 0xA25151F3, 0x3219192B, 0x3E1F1F21, 0x7E3F3F41, 0xB85C5CE4,
0x91B2B223, 0x2BEFEFC4, 0x944A4ADE, 0x6FCDCDA2, 0x8BBFBF34, 0x81BABA3B,
0xDE6F6FB1, 0xC86464AC, 0x47D9D99E, 0x13F3F3E0, 0x7C3E3E42, 0x9DB4B429,
0xA1AAAA0B, 0x4DDCDC91, 0x5FD5D58A, 0x0C06060A, 0x75C0C0B5, 0xFC7E7E82,
0x19F6F6EF, 0xCC6666AA, 0xD86C6CB4, 0xFD848479, 0xE2717193, 0x70383848,
0x87B9B93E, 0x3A1D1D27, 0xFE7F7F81, 0xCF9D9D52, 0x904848D8, 0xE38B8B68,
0x542A2A7E, 0x41DADA9B, 0xBFA5A51A, 0x66333355, 0xF1828273, 0x7239394B,
0x59D6D68F, 0xF0787888, 0xF986867F, 0x01FAFAFB, 0x3DE4E4D9, 0x562B2B7D,
0xA7A9A90E, 0x3C1E1E22, 0xE789896E, 0xC06060A0, 0xD66B6BBD, 0x21EAEACB,
0xAA5555FF, 0x984C4CD4, 0x1BF7F7EC, 0x31E2E2D3 };

const u32bit Square::TE1[256] = {
0x2697B1B1, 0xA769CECE, 0xB073C3C3, 0x4ADF9595, 0xEEB45A5A, 0x02AFADAD,
0xDC3BE7E7, 0x06040202, 0xD79A4D4D, 0xCC884444, 0xF803FBFB, 0x46D79191,
0x14180C0C, 0x7CFB8787, 0x16B7A1A1, 0xF0A05050, 0xA863CBCB, 0xA9CE6767,
0xFCA85454, 0x924FDDDD, 0xCA8C4646, 0x64EB8F8F, 0xD637E1E1, 0xD29C4E4E,
0xE515F0F0, 0xF20FFDFD, 0xF10DFCFC, 0xC823EBEB, 0xFE07F9F9, 0xB97DC4C4,
0x2E341A1A, 0xB2DC6E6E, 0xE2BC5E5E, 0xEA1FF5F5, 0xA16DCCCC, 0x62EF8D8D,
0x24381C1C, 0xFAAC5656, 0xC5864343, 0xF709FEFE, 0x090E0707, 0xA3C26161,
0xFD05F8F8, 0x9FEA7575, 0xEBB25959, 0xF40BFFFF, 0x05060303, 0x66442222,
0x6BE18A8A, 0x8657D1D1, 0x35261313, 0xC729EEEE, 0x6DE58888, 0x00000000,
0x121C0E0E, 0x5C683434, 0x3F2A1515, 0x75F58080, 0x49DD9494, 0xD033E3E3,
0xC22FEDED, 0x2A9FB5B5, 0xF5A65353, 0x65462323, 0xDD964B4B, 0xC98E4747,
0x392E1717, 0x1CBBA7A7, 0x45D59090, 0x5F6A3535, 0x08A3ABAB, 0x9D45D8D8,
0x3D85B8B8, 0x944BDFDF, 0xD19E4F4F, 0xF9AE5757, 0x5BC19A9A, 0x43D19292,
0x9843DBDB, 0x2D361B1B, 0x44783C3C, 0xAD65C8C8, 0x5EC79999, 0x0C080404,
0x67E98E8E, 0xD535E0E0, 0x8C5BD7D7, 0x87FA7D7D, 0x7AFF8585, 0x3883BBBB,
0xC0804040, 0x74582C2C, 0x4E743A3A, 0xCF8A4545, 0xE617F1F1, 0xC6844242,
0xAFCA6565, 0x60402020, 0xC3824141, 0x28301818, 0x96E47272, 0x6F4A2525,
0x40D39393, 0x90E07070, 0x5A6C3636, 0x0F0A0505, 0xE311F2F2, 0x1D160B0B,
0x10B3A3A3, 0x8BF27979, 0xC12DECEC, 0x18100808, 0x694E2727, 0x53623131,
0x56643232, 0x2F99B6B6, 0x84F87C7C, 0x2595B0B0, 0x1E140A0A, 0x95E67373,
0xEDB65B5B, 0x8DF67B7B, 0x2C9BB7B7, 0x76F78181, 0x8351D2D2, 0x171A0D0D,
0xBED46A6A, 0x6A4C2626, 0x57C99E9E, 0xE8B05858, 0x51CD9C9C, 0x70F38383,
0x9CE87474, 0x2093B3B3, 0x01ADACAC, 0x50603030, 0x8EF47A7A, 0xBBD26969,
0x99EE7777, 0x111E0F0F, 0x07A9AEAE, 0x63422121, 0x9749DEDE, 0x8555D0D0,
0x725C2E2E, 0x4CDB9797, 0x30201010, 0x19BDA4A4, 0x5DC59898, 0x0DA5A8A8,
0x895DD4D4, 0xB8D06868, 0x775A2D2D, 0xA6C46262, 0x7B522929, 0xB7DA6D6D,
0x3A2C1616, 0xDB924949, 0x9AEC7676, 0xBC7BC7C7, 0xCD25E8E8, 0xB677C1C1,
0x4FD99696, 0x596E3737, 0xDA3FE5E5, 0xAB61CACA, 0xE91DF4F4, 0xCE27E9E9,
0xA5C66363, 0x36241212, 0xB371C2C2, 0x1FB9A6A6, 0x3C281414, 0x318DBCBC,
0x8053D3D3, 0x78502828, 0x04ABAFAF, 0x715E2F2F, 0xDF39E6E6, 0x6C482424,
0xF6A45252, 0xBF79C6C6, 0x15B5A0A0, 0x1B120909, 0x328FBDBD, 0x61ED8C8C,
0xA46BCFCF, 0xE7BA5D5D, 0x33221111, 0xE1BE5F5F, 0x03020101, 0xBA7FC5C5,
0x54CB9F9F, 0x477A3D3D, 0x13B1A2A2, 0x58C39B9B, 0xAE67C9C9, 0x4D763B3B,
0x3789BEBE, 0xF3A25151, 0x2B321919, 0x213E1F1F, 0x417E3F3F, 0xE4B85C5C,
0x2391B2B2, 0xC42BEFEF, 0xDE944A4A, 0xA26FCDCD, 0x348BBFBF, 0x3B81BABA,
0xB1DE6F6F, 0xACC86464, 0x9E47D9D9, 0xE013F3F3, 0x427C3E3E, 0x299DB4B4,
0x0BA1AAAA, 0x914DDCDC, 0x8A5FD5D5, 0x0A0C0606, 0xB575C0C0, 0x82FC7E7E,
0xEF19F6F6, 0xAACC6666, 0xB4D86C6C, 0x79FD8484, 0x93E27171, 0x48703838,
0x3E87B9B9, 0x273A1D1D, 0x81FE7F7F, 0x52CF9D9D, 0xD8904848, 0x68E38B8B,
0x7E542A2A, 0x9B41DADA, 0x1ABFA5A5, 0x55663333, 0x73F18282, 0x4B723939,
0x8F59D6D6, 0x88F07878, 0x7FF98686, 0xFB01FAFA, 0xD93DE4E4, 0x7D562B2B,
0x0EA7A9A9, 0x223C1E1E, 0x6EE78989, 0xA0C06060, 0xBDD66B6B, 0xCB21EAEA,
0xFFAA5555, 0xD4984C4C, 0xEC1BF7F7, 0xD331E2E2 };

const u32bit Square::TE2[256] = {
0xB12697B1, 0xCEA769CE, 0xC3B073C3, 0x954ADF95, 0x5AEEB45A, 0xAD02AFAD,
0xE7DC3BE7, 0x02060402, 0x4DD79A4D, 0x44CC8844, 0xFBF803FB, 0x9146D791,
0x0C14180C, 0x877CFB87, 0xA116B7A1, 0x50F0A050, 0xCBA863CB, 0x67A9CE67,
0x54FCA854, 0xDD924FDD, 0x46CA8C46, 0x8F64EB8F, 0xE1D637E1, 0x4ED29C4E,
0xF0E515F0, 0xFDF20FFD, 0xFCF10DFC, 0xEBC823EB, 0xF9FE07F9, 0xC4B97DC4,
0x1A2E341A, 0x6EB2DC6E, 0x5EE2BC5E, 0xF5EA1FF5, 0xCCA16DCC, 0x8D62EF8D,
0x1C24381C, 0x56FAAC56, 0x43C58643, 0xFEF709FE, 0x07090E07, 0x61A3C261,
0xF8FD05F8, 0x759FEA75, 0x59EBB259, 0xFFF40BFF, 0x03050603, 0x22664422,
0x8A6BE18A, 0xD18657D1, 0x13352613, 0xEEC729EE, 0x886DE588, 0x00000000,
0x0E121C0E, 0x345C6834, 0x153F2A15, 0x8075F580, 0x9449DD94, 0xE3D033E3,
0xEDC22FED, 0xB52A9FB5, 0x53F5A653, 0x23654623, 0x4BDD964B, 0x47C98E47,
0x17392E17, 0xA71CBBA7, 0x9045D590, 0x355F6A35, 0xAB08A3AB, 0xD89D45D8,
0xB83D85B8, 0xDF944BDF, 0x4FD19E4F, 0x57F9AE57, 0x9A5BC19A, 0x9243D192,
0xDB9843DB, 0x1B2D361B, 0x3C44783C, 0xC8AD65C8, 0x995EC799, 0x040C0804,
0x8E67E98E, 0xE0D535E0, 0xD78C5BD7, 0x7D87FA7D, 0x857AFF85, 0xBB3883BB,
0x40C08040, 0x2C74582C, 0x3A4E743A, 0x45CF8A45, 0xF1E617F1, 0x42C68442,
0x65AFCA65, 0x20604020, 0x41C38241, 0x18283018, 0x7296E472, 0x256F4A25,
0x9340D393, 0x7090E070, 0x365A6C36, 0x050F0A05, 0xF2E311F2, 0x0B1D160B,
0xA310B3A3, 0x798BF279, 0xECC12DEC, 0x08181008, 0x27694E27, 0x31536231,
0x32566432, 0xB62F99B6, 0x7C84F87C, 0xB02595B0, 0x0A1E140A, 0x7395E673,
0x5BEDB65B, 0x7B8DF67B, 0xB72C9BB7, 0x8176F781, 0xD28351D2, 0x0D171A0D,
0x6ABED46A, 0x266A4C26, 0x9E57C99E, 0x58E8B058, 0x9C51CD9C, 0x8370F383,
0x749CE874, 0xB32093B3, 0xAC01ADAC, 0x30506030, 0x7A8EF47A, 0x69BBD269,
0x7799EE77, 0x0F111E0F, 0xAE07A9AE, 0x21634221, 0xDE9749DE, 0xD08555D0,
0x2E725C2E, 0x974CDB97, 0x10302010, 0xA419BDA4, 0x985DC598, 0xA80DA5A8,
0xD4895DD4, 0x68B8D068, 0x2D775A2D, 0x62A6C462, 0x297B5229, 0x6DB7DA6D,
0x163A2C16, 0x49DB9249, 0x769AEC76, 0xC7BC7BC7, 0xE8CD25E8, 0xC1B677C1,
0x964FD996, 0x37596E37, 0xE5DA3FE5, 0xCAAB61CA, 0xF4E91DF4, 0xE9CE27E9,
0x63A5C663, 0x12362412, 0xC2B371C2, 0xA61FB9A6, 0x143C2814, 0xBC318DBC,
0xD38053D3, 0x28785028, 0xAF04ABAF, 0x2F715E2F, 0xE6DF39E6, 0x246C4824,
0x52F6A452, 0xC6BF79C6, 0xA015B5A0, 0x091B1209, 0xBD328FBD, 0x8C61ED8C,
0xCFA46BCF, 0x5DE7BA5D, 0x11332211, 0x5FE1BE5F, 0x01030201, 0xC5BA7FC5,
0x9F54CB9F, 0x3D477A3D, 0xA213B1A2, 0x9B58C39B, 0xC9AE67C9, 0x3B4D763B,
0xBE3789BE, 0x51F3A251, 0x192B3219, 0x1F213E1F, 0x3F417E3F, 0x5CE4B85C,
0xB22391B2, 0xEFC42BEF, 0x4ADE944A, 0xCDA26FCD, 0xBF348BBF, 0xBA3B81BA,
0x6FB1DE6F, 0x64ACC864, 0xD99E47D9, 0xF3E013F3, 0x3E427C3E, 0xB4299DB4,
0xAA0BA1AA, 0xDC914DDC, 0xD58A5FD5, 0x060A0C06, 0xC0B575C0, 0x7E82FC7E,
0xF6EF19F6, 0x66AACC66, 0x6CB4D86C, 0x8479FD84, 0x7193E271, 0x38487038,
0xB93E87B9, 0x1D273A1D, 0x7F81FE7F, 0x9D52CF9D, 0x48D89048, 0x8B68E38B,
0x2A7E542A, 0xDA9B41DA, 0xA51ABFA5, 0x33556633, 0x8273F182, 0x394B7239,
0xD68F59D6, 0x7888F078, 0x867FF986, 0xFAFB01FA, 0xE4D93DE4, 0x2B7D562B,
0xA90EA7A9, 0x1E223C1E, 0x896EE789, 0x60A0C060, 0x6BBDD66B, 0xEACB21EA,
0x55FFAA55, 0x4CD4984C, 0xF7EC1BF7, 0xE2D331E2 };

const u32bit Square::TE3[256] = {
0xB1B12697, 0xCECEA769, 0xC3C3B073, 0x95954ADF, 0x5A5AEEB4, 0xADAD02AF,
0xE7E7DC3B, 0x02020604, 0x4D4DD79A, 0x4444CC88, 0xFBFBF803, 0x919146D7,
0x0C0C1418, 0x87877CFB, 0xA1A116B7, 0x5050F0A0, 0xCBCBA863, 0x6767A9CE,
0x5454FCA8, 0xDDDD924F, 0x4646CA8C, 0x8F8F64EB, 0xE1E1D637, 0x4E4ED29C,
0xF0F0E515, 0xFDFDF20F, 0xFCFCF10D, 0xEBEBC823, 0xF9F9FE07, 0xC4C4B97D,
0x1A1A2E34, 0x6E6EB2DC, 0x5E5EE2BC, 0xF5F5EA1F, 0xCCCCA16D, 0x8D8D62EF,
0x1C1C2438, 0x5656FAAC, 0x4343C586, 0xFEFEF709, 0x0707090E, 0x6161A3C2,
0xF8F8FD05, 0x75759FEA, 0x5959EBB2, 0xFFFFF40B, 0x03030506, 0x22226644,
0x8A8A6BE1, 0xD1D18657, 0x13133526, 0xEEEEC729, 0x88886DE5, 0x00000000,
0x0E0E121C, 0x34345C68, 0x15153F2A, 0x808075F5, 0x949449DD, 0xE3E3D033,
0xEDEDC22F, 0xB5B52A9F, 0x5353F5A6, 0x23236546, 0x4B4BDD96, 0x4747C98E,
0x1717392E, 0xA7A71CBB, 0x909045D5, 0x35355F6A, 0xABAB08A3, 0xD8D89D45,
0xB8B83D85, 0xDFDF944B, 0x4F4FD19E, 0x5757F9AE, 0x9A9A5BC1, 0x929243D1,
0xDBDB9843, 0x1B1B2D36, 0x3C3C4478, 0xC8C8AD65, 0x99995EC7, 0x04040C08,
0x8E8E67E9, 0xE0E0D535, 0xD7D78C5B, 0x7D7D87FA, 0x85857AFF, 0xBBBB3883,
0x4040C080, 0x2C2C7458, 0x3A3A4E74, 0x4545CF8A, 0xF1F1E617, 0x4242C684,
0x6565AFCA, 0x20206040, 0x4141C382, 0x18182830, 0x727296E4, 0x25256F4A,
0x939340D3, 0x707090E0, 0x36365A6C, 0x05050F0A, 0xF2F2E311, 0x0B0B1D16,
0xA3A310B3, 0x79798BF2, 0xECECC12D, 0x08081810, 0x2727694E, 0x31315362,
0x32325664, 0xB6B62F99, 0x7C7C84F8, 0xB0B02595, 0x0A0A1E14, 0x737395E6,
0x5B5BEDB6, 0x7B7B8DF6, 0xB7B72C9B, 0x818176F7, 0xD2D28351, 0x0D0D171A,
0x6A6ABED4, 0x26266A4C, 0x9E9E57C9, 0x5858E8B0, 0x9C9C51CD, 0x838370F3,
0x74749CE8, 0xB3B32093, 0xACAC01AD, 0x30305060, 0x7A7A8EF4, 0x6969BBD2,
0x777799EE, 0x0F0F111E, 0xAEAE07A9, 0x21216342, 0xDEDE9749, 0xD0D08555,
0x2E2E725C, 0x97974CDB, 0x10103020, 0xA4A419BD, 0x98985DC5, 0xA8A80DA5,
0xD4D4895D, 0x6868B8D0, 0x2D2D775A, 0x6262A6C4, 0x29297B52, 0x6D6DB7DA,
0x16163A2C, 0x4949DB92, 0x76769AEC, 0xC7C7BC7B, 0xE8E8CD25, 0xC1C1B677,
0x96964FD9, 0x3737596E, 0xE5E5DA3F, 0xCACAAB61, 0xF4F4E91D, 0xE9E9CE27,
0x6363A5C6, 0x12123624, 0xC2C2B371, 0xA6A61FB9, 0x14143C28, 0xBCBC318D,
0xD3D38053, 0x28287850, 0xAFAF04AB, 0x2F2F715E, 0xE6E6DF39, 0x24246C48,
0x5252F6A4, 0xC6C6BF79, 0xA0A015B5, 0x09091B12, 0xBDBD328F, 0x8C8C61ED,
0xCFCFA46B, 0x5D5DE7BA, 0x11113322, 0x5F5FE1BE, 0x01010302, 0xC5C5BA7F,
0x9F9F54CB, 0x3D3D477A, 0xA2A213B1, 0x9B9B58C3, 0xC9C9AE67, 0x3B3B4D76,
0xBEBE3789, 0x5151F3A2, 0x19192B32, 0x1F1F213E, 0x3F3F417E, 0x5C5CE4B8,
0xB2B22391, 0xEFEFC42B, 0x4A4ADE94, 0xCDCDA26F, 0xBFBF348B, 0xBABA3B81,
0x6F6FB1DE, 0x6464ACC8, 0xD9D99E47, 0xF3F3E013, 0x3E3E427C, 0xB4B4299D,
0xAAAA0BA1, 0xDCDC914D, 0xD5D58A5F, 0x06060A0C, 0xC0C0B575, 0x7E7E82FC,
0xF6F6EF19, 0x6666AACC, 0x6C6CB4D8, 0x848479FD, 0x717193E2, 0x38384870,
0xB9B93E87, 0x1D1D273A, 0x7F7F81FE, 0x9D9D52CF, 0x4848D890, 0x8B8B68E3,
0x2A2A7E54, 0xDADA9B41, 0xA5A51ABF, 0x33335566, 0x828273F1, 0x39394B72,
0xD6D68F59, 0x787888F0, 0x86867FF9, 0xFAFAFB01, 0xE4E4D93D, 0x2B2B7D56,
0xA9A90EA7, 0x1E1E223C, 0x89896EE7, 0x6060A0C0, 0x6B6BBDD6, 0xEAEACB21,
0x5555FFAA, 0x4C4CD498, 0xF7F7EC1B, 0xE2E2D331 };

const u32bit Square::TD0[256] = {
0xE368BC02, 0x5585620C, 0x2A3F2331, 0x61AB13F7, 0x98D46D72, 0x21CB9A19,
0x3C22A461, 0x459D3DCD, 0x05FDB423, 0x2BC4075F, 0x9B2C01C0, 0x3DD9800F,
0x486C5C74, 0xF97F7E85, 0xF173AB1F, 0xB6EDDE0E, 0x283C6BED, 0x4997781A,
0x9F2A918D, 0xC9579F33, 0xA907A8AA, 0xA50DED7D, 0x7C422D8F, 0x764DB0C9,
0x4D91E857, 0xCEA963CC, 0xB4EE96D2, 0x3028E1B6, 0x0DF161B9, 0xBD196726,
0x419BAD80, 0xC0A06EC7, 0x5183F241, 0x92DBF034, 0x6FA21EFC, 0x8F32CE4C,
0x13E03373, 0x69A7C66D, 0xE56D6493, 0xBF1A2FFA, 0xBB1CBFB7, 0x587403B5,
0xE76E2C4F, 0x5D89B796, 0xE89C052A, 0x446619A3, 0x342E71FB, 0x0FF22965,
0xFE81827A, 0xB11322F1, 0xA30835EC, 0xCD510F7E, 0xFF7AA614, 0x5C7293F8,
0x2FC29712, 0xF370E3C3, 0x992F491C, 0xD1431568, 0xC2A3261B, 0x88CC32B3,
0x8ACF7A6F, 0xB0E8069F, 0x7A47F51E, 0xD2BB79DA, 0xE6950821, 0x4398E55C,
0xD0B83106, 0x11E37BAF, 0x7E416553, 0xCCAA2B10, 0xD8B4E49C, 0x6456A7D4,
0xFB7C3659, 0x724B2084, 0xEA9F4DF6, 0x6A5FAADF, 0x2DC1DFCE, 0x70486858,
0xCAAFF381, 0x0605D891, 0x5A774B69, 0x94DE28A5, 0x39DF1042, 0x813BC347,
0xFC82CAA6, 0x23C8D2C5, 0x03F86CB2, 0x080CD59A, 0xDAB7AC40, 0x7DB909E1,
0x3824342C, 0xCF5247A2, 0xDCB274D1, 0x63A85B2B, 0x35D55595, 0x479E7511,
0x15E5EBE2, 0x4B9430C6, 0x4A6F14A8, 0x91239C86, 0x4C6ACC39, 0x5F8AFF4A,
0x0406904D, 0xEE99DDBB, 0x1E1152CA, 0xAAFFC418, 0xEB646998, 0x07FEFCFF,
0x8B345E01, 0x567D0EBE, 0xBAE79BD9, 0x4263C132, 0x75B5DC7B, 0x97264417,
0x67AECB66, 0x95250CCB, 0xEC9A9567, 0x57862AD0, 0x60503799, 0xB8E4D305,
0x65AD83BA, 0x19EFAE35, 0xA4F6C913, 0xC15B4AA9, 0x873E1BD6, 0xA0F0595E,
0x18148A5B, 0xAF02703B, 0xAB04E076, 0xDD4950BF, 0xDF4A1863, 0xC6A5B656,
0x853D530A, 0xFA871237, 0x77B694A7, 0x4665517F, 0xED61B109, 0x1BECE6E9,
0xD5458525, 0xF5753B52, 0x7FBA413D, 0x27CE4288, 0xB2EB4E43, 0xD6BDE997,
0x527B9EF3, 0x62537F45, 0x2C3AFBA0, 0x7BBCD170, 0xB91FF76B, 0x121B171D,
0xFD79EEC8, 0x3A277CF0, 0x0C0A45D7, 0x96DD6079, 0x2233F6AB, 0xACFA1C89,
0xC8ACBB5D, 0xA10B7D30, 0xD4BEA14B, 0xBEE10B94, 0x25CD0A54, 0x547E4662,
0xA2F31182, 0x17E6A33E, 0x263566E6, 0xC3580275, 0x83388B9B, 0x7844BDC2,
0x020348DC, 0x4F92A08B, 0x2E39B37C, 0x4E6984E5, 0xF0888F71, 0x362D3927,
0x9CD2FD3F, 0x01FB246E, 0x893716DD, 0x00000000, 0xF68D57E0, 0xE293986C,
0x744EF815, 0x9320D45A, 0xAD0138E7, 0xD3405DB4, 0x1A17C287, 0xB3106A2D,
0x5078D62F, 0xF48E1F3C, 0xA70EA5A1, 0x71B34C36, 0x9AD725AE, 0x5E71DB24,
0x161D8750, 0xEF62F9D5, 0x8D318690, 0x1C121A16, 0xA6F581CF, 0x5B8C6F07,
0x37D61D49, 0x6E593A92, 0x84C67764, 0x86C53FB8, 0xD746CDF9, 0xE090D0B0,
0x29C74F83, 0xE49640FD, 0x0E090D0B, 0x6DA15620, 0x8EC9EA22, 0xDB4C882E,
0xF776738E, 0xB515B2BC, 0x10185FC1, 0x322BA96A, 0x6BA48EB1, 0xAEF95455,
0x406089EE, 0x6655EF08, 0xE9672144, 0x3E21ECBD, 0x2030BE77, 0xF28BC7AD,
0x80C0E729, 0x141ECF8C, 0xBCE24348, 0xC4A6FE8A, 0x31D3C5D8, 0xB716FA60,
0x5380BA9D, 0xD94FC0F2, 0x1DE93E78, 0x24362E3A, 0xE16BF4DE, 0xCB54D7EF,
0x09F7F1F4, 0x82C3AFF5, 0x0BF4B928, 0x9D29D951, 0xC75E9238, 0xF8845AEB,
0x90D8B8E8, 0xDEB13C0D, 0x33D08D04, 0x685CE203, 0xC55DDAE4, 0x3BDC589E,
0x0A0F9D46, 0x3FDAC8D3, 0x598F27DB, 0xA8FC8CC4, 0x79BF99AC, 0x6C5A724E,
0x8CCAA2FE, 0x9ED1B5E3, 0x1FEA76A4, 0x73B004EA };

const u32bit Square::TD1[256] = {
0x02E368BC, 0x0C558562, 0x312A3F23, 0xF761AB13, 0x7298D46D, 0x1921CB9A,
0x613C22A4, 0xCD459D3D, 0x2305FDB4, 0x5F2BC407, 0xC09B2C01, 0x0F3DD980,
0x74486C5C, 0x85F97F7E, 0x1FF173AB, 0x0EB6EDDE, 0xED283C6B, 0x1A499778,
0x8D9F2A91, 0x33C9579F, 0xAAA907A8, 0x7DA50DED, 0x8F7C422D, 0xC9764DB0,
0x574D91E8, 0xCCCEA963, 0xD2B4EE96, 0xB63028E1, 0xB90DF161, 0x26BD1967,
0x80419BAD, 0xC7C0A06E, 0x415183F2, 0x3492DBF0, 0xFC6FA21E, 0x4C8F32CE,
0x7313E033, 0x6D69A7C6, 0x93E56D64, 0xFABF1A2F, 0xB7BB1CBF, 0xB5587403,
0x4FE76E2C, 0x965D89B7, 0x2AE89C05, 0xA3446619, 0xFB342E71, 0x650FF229,
0x7AFE8182, 0xF1B11322, 0xECA30835, 0x7ECD510F, 0x14FF7AA6, 0xF85C7293,
0x122FC297, 0xC3F370E3, 0x1C992F49, 0x68D14315, 0x1BC2A326, 0xB388CC32,
0x6F8ACF7A, 0x9FB0E806, 0x1E7A47F5, 0xDAD2BB79, 0x21E69508, 0x5C4398E5,
0x06D0B831, 0xAF11E37B, 0x537E4165, 0x10CCAA2B, 0x9CD8B4E4, 0xD46456A7,
0x59FB7C36, 0x84724B20, 0xF6EA9F4D, 0xDF6A5FAA, 0xCE2DC1DF, 0x58704868,
0x81CAAFF3, 0x910605D8, 0x695A774B, 0xA594DE28, 0x4239DF10, 0x47813BC3,
0xA6FC82CA, 0xC523C8D2, 0xB203F86C, 0x9A080CD5, 0x40DAB7AC, 0xE17DB909,
0x2C382434, 0xA2CF5247, 0xD1DCB274, 0x2B63A85B, 0x9535D555, 0x11479E75,
0xE215E5EB, 0xC64B9430, 0xA84A6F14, 0x8691239C, 0x394C6ACC, 0x4A5F8AFF,
0x4D040690, 0xBBEE99DD, 0xCA1E1152, 0x18AAFFC4, 0x98EB6469, 0xFF07FEFC,
0x018B345E, 0xBE567D0E, 0xD9BAE79B, 0x324263C1, 0x7B75B5DC, 0x17972644,
0x6667AECB, 0xCB95250C, 0x67EC9A95, 0xD057862A, 0x99605037, 0x05B8E4D3,
0xBA65AD83, 0x3519EFAE, 0x13A4F6C9, 0xA9C15B4A, 0xD6873E1B, 0x5EA0F059,
0x5B18148A, 0x3BAF0270, 0x76AB04E0, 0xBFDD4950, 0x63DF4A18, 0x56C6A5B6,
0x0A853D53, 0x37FA8712, 0xA777B694, 0x7F466551, 0x09ED61B1, 0xE91BECE6,
0x25D54585, 0x52F5753B, 0x3D7FBA41, 0x8827CE42, 0x43B2EB4E, 0x97D6BDE9,
0xF3527B9E, 0x4562537F, 0xA02C3AFB, 0x707BBCD1, 0x6BB91FF7, 0x1D121B17,
0xC8FD79EE, 0xF03A277C, 0xD70C0A45, 0x7996DD60, 0xAB2233F6, 0x89ACFA1C,
0x5DC8ACBB, 0x30A10B7D, 0x4BD4BEA1, 0x94BEE10B, 0x5425CD0A, 0x62547E46,
0x82A2F311, 0x3E17E6A3, 0xE6263566, 0x75C35802, 0x9B83388B, 0xC27844BD,
0xDC020348, 0x8B4F92A0, 0x7C2E39B3, 0xE54E6984, 0x71F0888F, 0x27362D39,
0x3F9CD2FD, 0x6E01FB24, 0xDD893716, 0x00000000, 0xE0F68D57, 0x6CE29398,
0x15744EF8, 0x5A9320D4, 0xE7AD0138, 0xB4D3405D, 0x871A17C2, 0x2DB3106A,
0x2F5078D6, 0x3CF48E1F, 0xA1A70EA5, 0x3671B34C, 0xAE9AD725, 0x245E71DB,
0x50161D87, 0xD5EF62F9, 0x908D3186, 0x161C121A, 0xCFA6F581, 0x075B8C6F,
0x4937D61D, 0x926E593A, 0x6484C677, 0xB886C53F, 0xF9D746CD, 0xB0E090D0,
0x8329C74F, 0xFDE49640, 0x0B0E090D, 0x206DA156, 0x228EC9EA, 0x2EDB4C88,
0x8EF77673, 0xBCB515B2, 0xC110185F, 0x6A322BA9, 0xB16BA48E, 0x55AEF954,
0xEE406089, 0x086655EF, 0x44E96721, 0xBD3E21EC, 0x772030BE, 0xADF28BC7,
0x2980C0E7, 0x8C141ECF, 0x48BCE243, 0x8AC4A6FE, 0xD831D3C5, 0x60B716FA,
0x9D5380BA, 0xF2D94FC0, 0x781DE93E, 0x3A24362E, 0xDEE16BF4, 0xEFCB54D7,
0xF409F7F1, 0xF582C3AF, 0x280BF4B9, 0x519D29D9, 0x38C75E92, 0xEBF8845A,
0xE890D8B8, 0x0DDEB13C, 0x0433D08D, 0x03685CE2, 0xE4C55DDA, 0x9E3BDC58,
0x460A0F9D, 0xD33FDAC8, 0xDB598F27, 0xC4A8FC8C, 0xAC79BF99, 0x4E6C5A72,
0xFE8CCAA2, 0xE39ED1B5, 0xA41FEA76, 0xEA73B004 };

const u32bit Square::TD2[256] = {
0xBC02E368, 0x620C5585, 0x23312A3F, 0x13F761AB, 0x6D7298D4, 0x9A1921CB,
0xA4613C22, 0x3DCD459D, 0xB42305FD, 0x075F2BC4, 0x01C09B2C, 0x800F3DD9,
0x5C74486C, 0x7E85F97F, 0xAB1FF173, 0xDE0EB6ED, 0x6BED283C, 0x781A4997,
0x918D9F2A, 0x9F33C957, 0xA8AAA907, 0xED7DA50D, 0x2D8F7C42, 0xB0C9764D,
0xE8574D91, 0x63CCCEA9, 0x96D2B4EE, 0xE1B63028, 0x61B90DF1, 0x6726BD19,
0xAD80419B, 0x6EC7C0A0, 0xF2415183, 0xF03492DB, 0x1EFC6FA2, 0xCE4C8F32,
0x337313E0, 0xC66D69A7, 0x6493E56D, 0x2FFABF1A, 0xBFB7BB1C, 0x03B55874,
0x2C4FE76E, 0xB7965D89, 0x052AE89C, 0x19A34466, 0x71FB342E, 0x29650FF2,
0x827AFE81, 0x22F1B113, 0x35ECA308, 0x0F7ECD51, 0xA614FF7A, 0x93F85C72,
0x97122FC2, 0xE3C3F370, 0x491C992F, 0x1568D143, 0x261BC2A3, 0x32B388CC,
0x7A6F8ACF, 0x069FB0E8, 0xF51E7A47, 0x79DAD2BB, 0x0821E695, 0xE55C4398,
0x3106D0B8, 0x7BAF11E3, 0x65537E41, 0x2B10CCAA, 0xE49CD8B4, 0xA7D46456,
0x3659FB7C, 0x2084724B, 0x4DF6EA9F, 0xAADF6A5F, 0xDFCE2DC1, 0x68587048,
0xF381CAAF, 0xD8910605, 0x4B695A77, 0x28A594DE, 0x104239DF, 0xC347813B,
0xCAA6FC82, 0xD2C523C8, 0x6CB203F8, 0xD59A080C, 0xAC40DAB7, 0x09E17DB9,
0x342C3824, 0x47A2CF52, 0x74D1DCB2, 0x5B2B63A8, 0x559535D5, 0x7511479E,
0xEBE215E5, 0x30C64B94, 0x14A84A6F, 0x9C869123, 0xCC394C6A, 0xFF4A5F8A,
0x904D0406, 0xDDBBEE99, 0x52CA1E11, 0xC418AAFF, 0x6998EB64, 0xFCFF07FE,
0x5E018B34, 0x0EBE567D, 0x9BD9BAE7, 0xC1324263, 0xDC7B75B5, 0x44179726,
0xCB6667AE, 0x0CCB9525, 0x9567EC9A, 0x2AD05786, 0x37996050, 0xD305B8E4,
0x83BA65AD, 0xAE3519EF, 0xC913A4F6, 0x4AA9C15B, 0x1BD6873E, 0x595EA0F0,
0x8A5B1814, 0x703BAF02, 0xE076AB04, 0x50BFDD49, 0x1863DF4A, 0xB656C6A5,
0x530A853D, 0x1237FA87, 0x94A777B6, 0x517F4665, 0xB109ED61, 0xE6E91BEC,
0x8525D545, 0x3B52F575, 0x413D7FBA, 0x428827CE, 0x4E43B2EB, 0xE997D6BD,
0x9EF3527B, 0x7F456253, 0xFBA02C3A, 0xD1707BBC, 0xF76BB91F, 0x171D121B,
0xEEC8FD79, 0x7CF03A27, 0x45D70C0A, 0x607996DD, 0xF6AB2233, 0x1C89ACFA,
0xBB5DC8AC, 0x7D30A10B, 0xA14BD4BE, 0x0B94BEE1, 0x0A5425CD, 0x4662547E,
0x1182A2F3, 0xA33E17E6, 0x66E62635, 0x0275C358, 0x8B9B8338, 0xBDC27844,
0x48DC0203, 0xA08B4F92, 0xB37C2E39, 0x84E54E69, 0x8F71F088, 0x3927362D,
0xFD3F9CD2, 0x246E01FB, 0x16DD8937, 0x00000000, 0x57E0F68D, 0x986CE293,
0xF815744E, 0xD45A9320, 0x38E7AD01, 0x5DB4D340, 0xC2871A17, 0x6A2DB310,
0xD62F5078, 0x1F3CF48E, 0xA5A1A70E, 0x4C3671B3, 0x25AE9AD7, 0xDB245E71,
0x8750161D, 0xF9D5EF62, 0x86908D31, 0x1A161C12, 0x81CFA6F5, 0x6F075B8C,
0x1D4937D6, 0x3A926E59, 0x776484C6, 0x3FB886C5, 0xCDF9D746, 0xD0B0E090,
0x4F8329C7, 0x40FDE496, 0x0D0B0E09, 0x56206DA1, 0xEA228EC9, 0x882EDB4C,
0x738EF776, 0xB2BCB515, 0x5FC11018, 0xA96A322B, 0x8EB16BA4, 0x5455AEF9,
0x89EE4060, 0xEF086655, 0x2144E967, 0xECBD3E21, 0xBE772030, 0xC7ADF28B,
0xE72980C0, 0xCF8C141E, 0x4348BCE2, 0xFE8AC4A6, 0xC5D831D3, 0xFA60B716,
0xBA9D5380, 0xC0F2D94F, 0x3E781DE9, 0x2E3A2436, 0xF4DEE16B, 0xD7EFCB54,
0xF1F409F7, 0xAFF582C3, 0xB9280BF4, 0xD9519D29, 0x9238C75E, 0x5AEBF884,
0xB8E890D8, 0x3C0DDEB1, 0x8D0433D0, 0xE203685C, 0xDAE4C55D, 0x589E3BDC,
0x9D460A0F, 0xC8D33FDA, 0x27DB598F, 0x8CC4A8FC, 0x99AC79BF, 0x724E6C5A,
0xA2FE8CCA, 0xB5E39ED1, 0x76A41FEA, 0x04EA73B0 };

const u32bit Square::TD3[256] = {
0x68BC02E3, 0x85620C55, 0x3F23312A, 0xAB13F761, 0xD46D7298, 0xCB9A1921,
0x22A4613C, 0x9D3DCD45, 0xFDB42305, 0xC4075F2B, 0x2C01C09B, 0xD9800F3D,
0x6C5C7448, 0x7F7E85F9, 0x73AB1FF1, 0xEDDE0EB6, 0x3C6BED28, 0x97781A49,
0x2A918D9F, 0x579F33C9, 0x07A8AAA9, 0x0DED7DA5, 0x422D8F7C, 0x4DB0C976,
0x91E8574D, 0xA963CCCE, 0xEE96D2B4, 0x28E1B630, 0xF161B90D, 0x196726BD,
0x9BAD8041, 0xA06EC7C0, 0x83F24151, 0xDBF03492, 0xA21EFC6F, 0x32CE4C8F,
0xE0337313, 0xA7C66D69, 0x6D6493E5, 0x1A2FFABF, 0x1CBFB7BB, 0x7403B558,
0x6E2C4FE7, 0x89B7965D, 0x9C052AE8, 0x6619A344, 0x2E71FB34, 0xF229650F,
0x81827AFE, 0x1322F1B1, 0x0835ECA3, 0x510F7ECD, 0x7AA614FF, 0x7293F85C,
0xC297122F, 0x70E3C3F3, 0x2F491C99, 0x431568D1, 0xA3261BC2, 0xCC32B388,
0xCF7A6F8A, 0xE8069FB0, 0x47F51E7A, 0xBB79DAD2, 0x950821E6, 0x98E55C43,
0xB83106D0, 0xE37BAF11, 0x4165537E, 0xAA2B10CC, 0xB4E49CD8, 0x56A7D464,
0x7C3659FB, 0x4B208472, 0x9F4DF6EA, 0x5FAADF6A, 0xC1DFCE2D, 0x48685870,
0xAFF381CA, 0x05D89106, 0x774B695A, 0xDE28A594, 0xDF104239, 0x3BC34781,
0x82CAA6FC, 0xC8D2C523, 0xF86CB203, 0x0CD59A08, 0xB7AC40DA, 0xB909E17D,
0x24342C38, 0x5247A2CF, 0xB274D1DC, 0xA85B2B63, 0xD5559535, 0x9E751147,
0xE5EBE215, 0x9430C64B, 0x6F14A84A, 0x239C8691, 0x6ACC394C, 0x8AFF4A5F,
0x06904D04, 0x99DDBBEE, 0x1152CA1E, 0xFFC418AA, 0x646998EB, 0xFEFCFF07,
0x345E018B, 0x7D0EBE56, 0xE79BD9BA, 0x63C13242, 0xB5DC7B75, 0x26441797,
0xAECB6667, 0x250CCB95, 0x9A9567EC, 0x862AD057, 0x50379960, 0xE4D305B8,
0xAD83BA65, 0xEFAE3519, 0xF6C913A4, 0x5B4AA9C1, 0x3E1BD687, 0xF0595EA0,
0x148A5B18, 0x02703BAF, 0x04E076AB, 0x4950BFDD, 0x4A1863DF, 0xA5B656C6,
0x3D530A85, 0x871237FA, 0xB694A777, 0x65517F46, 0x61B109ED, 0xECE6E91B,
0x458525D5, 0x753B52F5, 0xBA413D7F, 0xCE428827, 0xEB4E43B2, 0xBDE997D6,
0x7B9EF352, 0x537F4562, 0x3AFBA02C, 0xBCD1707B, 0x1FF76BB9, 0x1B171D12,
0x79EEC8FD, 0x277CF03A, 0x0A45D70C, 0xDD607996, 0x33F6AB22, 0xFA1C89AC,
0xACBB5DC8, 0x0B7D30A1, 0xBEA14BD4, 0xE10B94BE, 0xCD0A5425, 0x7E466254,
0xF31182A2, 0xE6A33E17, 0x3566E626, 0x580275C3, 0x388B9B83, 0x44BDC278,
0x0348DC02, 0x92A08B4F, 0x39B37C2E, 0x6984E54E, 0x888F71F0, 0x2D392736,
0xD2FD3F9C, 0xFB246E01, 0x3716DD89, 0x00000000, 0x8D57E0F6, 0x93986CE2,
0x4EF81574, 0x20D45A93, 0x0138E7AD, 0x405DB4D3, 0x17C2871A, 0x106A2DB3,
0x78D62F50, 0x8E1F3CF4, 0x0EA5A1A7, 0xB34C3671, 0xD725AE9A, 0x71DB245E,
0x1D875016, 0x62F9D5EF, 0x3186908D, 0x121A161C, 0xF581CFA6, 0x8C6F075B,
0xD61D4937, 0x593A926E, 0xC6776484, 0xC53FB886, 0x46CDF9D7, 0x90D0B0E0,
0xC74F8329, 0x9640FDE4, 0x090D0B0E, 0xA156206D, 0xC9EA228E, 0x4C882EDB,
0x76738EF7, 0x15B2BCB5, 0x185FC110, 0x2BA96A32, 0xA48EB16B, 0xF95455AE,
0x6089EE40, 0x55EF0866, 0x672144E9, 0x21ECBD3E, 0x30BE7720, 0x8BC7ADF2,
0xC0E72980, 0x1ECF8C14, 0xE24348BC, 0xA6FE8AC4, 0xD3C5D831, 0x16FA60B7,
0x80BA9D53, 0x4FC0F2D9, 0xE93E781D, 0x362E3A24, 0x6BF4DEE1, 0x54D7EFCB,
0xF7F1F409, 0xC3AFF582, 0xF4B9280B, 0x29D9519D, 0x5E9238C7, 0x845AEBF8,
0xD8B8E890, 0xB13C0DDE, 0xD08D0433, 0x5CE20368, 0x5DDAE4C5, 0xDC589E3B,
0x0F9D460A, 0xDAC8D33F, 0x8F27DB59, 0xFC8CC4A8, 0xBF99AC79, 0x5A724E6C,
0xCAA2FE8C, 0xD1B5E39E, 0xEA76A41F, 0xB004EA73 };

}
/*
* Square
* (C) 1999-2007 Jack Lloyd
*
* Based on the public domain reference implemenation
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Square Encryption
*/
void Square::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0, B1, B2, B3;

      B0 = TE0[in[ 0] ^ ME[ 0]] ^ TE1[in[ 4] ^ ME[ 4]] ^
           TE2[in[ 8] ^ ME[ 8]] ^ TE3[in[12] ^ ME[12]] ^ EK[0];
      B1 = TE0[in[ 1] ^ ME[ 1]] ^ TE1[in[ 5] ^ ME[ 5]] ^
           TE2[in[ 9] ^ ME[ 9]] ^ TE3[in[13] ^ ME[13]] ^ EK[1];
      B2 = TE0[in[ 2] ^ ME[ 2]] ^ TE1[in[ 6] ^ ME[ 6]] ^
           TE2[in[10] ^ ME[10]] ^ TE3[in[14] ^ ME[14]] ^ EK[2];
      B3 = TE0[in[ 3] ^ ME[ 3]] ^ TE1[in[ 7] ^ ME[ 7]] ^
           TE2[in[11] ^ ME[11]] ^ TE3[in[15] ^ ME[15]] ^ EK[3];

      for(size_t j = 1; j != 7; j += 2)
         {
         u32bit T0, T1, T2, T3;
         T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(0, B1)] ^
              TE2[get_byte(0, B2)] ^ TE3[get_byte(0, B3)] ^ EK[4*j+0];
         T1 = TE0[get_byte(1, B0)] ^ TE1[get_byte(1, B1)] ^
              TE2[get_byte(1, B2)] ^ TE3[get_byte(1, B3)] ^ EK[4*j+1];
         T2 = TE0[get_byte(2, B0)] ^ TE1[get_byte(2, B1)] ^
              TE2[get_byte(2, B2)] ^ TE3[get_byte(2, B3)] ^ EK[4*j+2];
         T3 = TE0[get_byte(3, B0)] ^ TE1[get_byte(3, B1)] ^
              TE2[get_byte(3, B2)] ^ TE3[get_byte(3, B3)] ^ EK[4*j+3];

         B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(0, T1)] ^
              TE2[get_byte(0, T2)] ^ TE3[get_byte(0, T3)] ^ EK[4*j+4];
         B1 = TE0[get_byte(1, T0)] ^ TE1[get_byte(1, T1)] ^
              TE2[get_byte(1, T2)] ^ TE3[get_byte(1, T3)] ^ EK[4*j+5];
         B2 = TE0[get_byte(2, T0)] ^ TE1[get_byte(2, T1)] ^
              TE2[get_byte(2, T2)] ^ TE3[get_byte(2, T3)] ^ EK[4*j+6];
         B3 = TE0[get_byte(3, T0)] ^ TE1[get_byte(3, T1)] ^
              TE2[get_byte(3, T2)] ^ TE3[get_byte(3, T3)] ^ EK[4*j+7];
         }

      out[ 0] = SE[get_byte(0, B0)] ^ ME[16];
      out[ 1] = SE[get_byte(0, B1)] ^ ME[17];
      out[ 2] = SE[get_byte(0, B2)] ^ ME[18];
      out[ 3] = SE[get_byte(0, B3)] ^ ME[19];
      out[ 4] = SE[get_byte(1, B0)] ^ ME[20];
      out[ 5] = SE[get_byte(1, B1)] ^ ME[21];
      out[ 6] = SE[get_byte(1, B2)] ^ ME[22];
      out[ 7] = SE[get_byte(1, B3)] ^ ME[23];
      out[ 8] = SE[get_byte(2, B0)] ^ ME[24];
      out[ 9] = SE[get_byte(2, B1)] ^ ME[25];
      out[10] = SE[get_byte(2, B2)] ^ ME[26];
      out[11] = SE[get_byte(2, B3)] ^ ME[27];
      out[12] = SE[get_byte(3, B0)] ^ ME[28];
      out[13] = SE[get_byte(3, B1)] ^ ME[29];
      out[14] = SE[get_byte(3, B2)] ^ ME[30];
      out[15] = SE[get_byte(3, B3)] ^ ME[31];

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Square Decryption
*/
void Square::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit B0, B1, B2, B3;

      B0 = TD0[in[ 0] ^ MD[ 0]] ^ TD1[in[ 4] ^ MD[ 4]] ^
           TD2[in[ 8] ^ MD[ 8]] ^ TD3[in[12] ^ MD[12]] ^ DK[0];
      B1 = TD0[in[ 1] ^ MD[ 1]] ^ TD1[in[ 5] ^ MD[ 5]] ^
           TD2[in[ 9] ^ MD[ 9]] ^ TD3[in[13] ^ MD[13]] ^ DK[1];
      B2 = TD0[in[ 2] ^ MD[ 2]] ^ TD1[in[ 6] ^ MD[ 6]] ^
           TD2[in[10] ^ MD[10]] ^ TD3[in[14] ^ MD[14]] ^ DK[2];
      B3 = TD0[in[ 3] ^ MD[ 3]] ^ TD1[in[ 7] ^ MD[ 7]] ^
           TD2[in[11] ^ MD[11]] ^ TD3[in[15] ^ MD[15]] ^ DK[3];

      for(size_t j = 1; j != 7; j += 2)
         {
         u32bit T0, T1, T2, T3;
         T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(0, B1)] ^
              TD2[get_byte(0, B2)] ^ TD3[get_byte(0, B3)] ^ DK[4*j+0];
         T1 = TD0[get_byte(1, B0)] ^ TD1[get_byte(1, B1)] ^
              TD2[get_byte(1, B2)] ^ TD3[get_byte(1, B3)] ^ DK[4*j+1];
         T2 = TD0[get_byte(2, B0)] ^ TD1[get_byte(2, B1)] ^
              TD2[get_byte(2, B2)] ^ TD3[get_byte(2, B3)] ^ DK[4*j+2];
         T3 = TD0[get_byte(3, B0)] ^ TD1[get_byte(3, B1)] ^
              TD2[get_byte(3, B2)] ^ TD3[get_byte(3, B3)] ^ DK[4*j+3];

         B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(0, T1)] ^
              TD2[get_byte(0, T2)] ^ TD3[get_byte(0, T3)] ^ DK[4*j+4];
         B1 = TD0[get_byte(1, T0)] ^ TD1[get_byte(1, T1)] ^
              TD2[get_byte(1, T2)] ^ TD3[get_byte(1, T3)] ^ DK[4*j+5];
         B2 = TD0[get_byte(2, T0)] ^ TD1[get_byte(2, T1)] ^
              TD2[get_byte(2, T2)] ^ TD3[get_byte(2, T3)] ^ DK[4*j+6];
         B3 = TD0[get_byte(3, T0)] ^ TD1[get_byte(3, T1)] ^
              TD2[get_byte(3, T2)] ^ TD3[get_byte(3, T3)] ^ DK[4*j+7];
         }

      out[ 0] = SD[get_byte(0, B0)] ^ MD[16];
      out[ 1] = SD[get_byte(0, B1)] ^ MD[17];
      out[ 2] = SD[get_byte(0, B2)] ^ MD[18];
      out[ 3] = SD[get_byte(0, B3)] ^ MD[19];
      out[ 4] = SD[get_byte(1, B0)] ^ MD[20];
      out[ 5] = SD[get_byte(1, B1)] ^ MD[21];
      out[ 6] = SD[get_byte(1, B2)] ^ MD[22];
      out[ 7] = SD[get_byte(1, B3)] ^ MD[23];
      out[ 8] = SD[get_byte(2, B0)] ^ MD[24];
      out[ 9] = SD[get_byte(2, B1)] ^ MD[25];
      out[10] = SD[get_byte(2, B2)] ^ MD[26];
      out[11] = SD[get_byte(2, B3)] ^ MD[27];
      out[12] = SD[get_byte(3, B0)] ^ MD[28];
      out[13] = SD[get_byte(3, B1)] ^ MD[29];
      out[14] = SD[get_byte(3, B2)] ^ MD[30];
      out[15] = SD[get_byte(3, B3)] ^ MD[31];

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Square Key Schedule
*/
void Square::key_schedule(const byte key[], size_t)
   {
   SecureVector<u32bit> XEK(36), XDK(36);

   for(size_t i = 0; i != 4; ++i)
      XEK[i] = load_be<u32bit>(key, i);

   for(size_t i = 0; i != 8; ++i)
      {
      XEK[4*i+4] = XEK[4*i  ] ^ rotate_left(XEK[4*i+3], 8) ^ (0x01000000 << i);
      XEK[4*i+5] = XEK[4*i+1] ^ XEK[4*i+4];
      XEK[4*i+6] = XEK[4*i+2] ^ XEK[4*i+5];
      XEK[4*i+7] = XEK[4*i+3] ^ XEK[4*i+6];

      for(size_t j = 0; j != 4; ++j)
         XDK[28 - 4*i + j] = XEK[4*(i+1)+j];

      transform(&XEK[4*i]);
      }

   for(size_t i = 0; i != 4; ++i)
      for(size_t j = 0; j != 4; ++j)
         {
         ME[4*i+j   ] = get_byte(j, XEK[i   ]);
         ME[4*i+j+16] = get_byte(j, XEK[i+32]);
         MD[4*i+j   ] = get_byte(j, XDK[i   ]);
         MD[4*i+j+16] = get_byte(j, XEK[i   ]);
         }

   EK.copy(&XEK[4], 28);
   DK.copy(&XDK[4], 28);
   }

/*
* Square's Inverse Linear Transformation
*/
void Square::transform(u32bit round_key[4])
   {
   static const byte G[4][4] = {
      { 2, 1, 1, 3 },
      { 3, 2, 1, 1 },
      { 1, 3, 2, 1 },
      { 1, 1, 3, 2 } };

   for(size_t i = 0; i != 4; ++i)
      {
      byte A[4] = { 0 }, B[4] = { 0 };

      store_be(round_key[i], A);

      for(size_t j = 0; j != 4; ++j)
         for(size_t k = 0; k != 4; ++k)
            {
            const byte a = A[k];
            const byte b = G[k][j];

            if(a && b)
               B[j] ^= ALog[(Log[a] + Log[b]) % 255];
            }

      round_key[i] = load_be<u32bit>(B, 0);
      }
   }

/*
* Clear memory of sensitive data
*/
void Square::clear()
   {
   zeroise(EK);
   zeroise(DK);
   zeroise(ME);
   zeroise(MD);
   }

}
/*
* TEA
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* TEA Encryption
*/
void TEA::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      u32bit S = 0;
      for(size_t j = 0; j != 32; ++j)
         {
         S += 0x9E3779B9;
         L += ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]);
         R += ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]);
         }

      store_be(out, L, R);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* TEA Decryption
*/
void TEA::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      u32bit S = 0xC6EF3720;
      for(size_t j = 0; j != 32; ++j)
         {
         R -= ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]);
         L -= ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]);
         S -= 0x9E3779B9;
         }

      store_be(out, L, R);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* TEA Key Schedule
*/
void TEA::key_schedule(const byte key[], size_t)
   {
   for(size_t i = 0; i != 4; ++i)
      K[i] = load_be<u32bit>(key, i);
   }

}
/*
* S-Box and MDS Tables for Twofish
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const byte Twofish::Q0[256] = {
   0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
   0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
   0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
   0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
   0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
   0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
   0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
   0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
   0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
   0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
   0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
   0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
   0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
   0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
   0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
   0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
   0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
   0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
   0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
   0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
   0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
   0x4A, 0x5E, 0xC1, 0xE0 };

const byte Twofish::Q1[256] = {
   0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
   0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
   0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
   0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
   0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
   0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
   0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
   0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
   0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
   0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
   0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
   0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
   0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
   0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
   0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
   0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
   0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
   0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
   0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
   0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
   0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
   0x55, 0x09, 0xBE, 0x91 };

const byte Twofish::RS[32] = {
   0x01, 0xA4, 0x02, 0xA4, 0xA4, 0x56, 0xA1, 0x55, 0x55, 0x82, 0xFC, 0x87,
   0x87, 0xF3, 0xC1, 0x5A, 0x5A, 0x1E, 0x47, 0x58, 0x58, 0xC6, 0xAE, 0xDB,
   0xDB, 0x68, 0x3D, 0x9E, 0x9E, 0xE5, 0x19, 0x03 };

const byte Twofish::EXP_TO_POLY[255] = {
   0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
   0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
   0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
   0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
   0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
   0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
   0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
   0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
   0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
   0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
   0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
   0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
   0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
   0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
   0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
   0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
   0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
   0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
   0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
   0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
   0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
   0x8F, 0x53, 0xA6 };

const byte Twofish::POLY_TO_EXP[255] = {
   0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
   0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
   0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
   0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
   0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
   0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
   0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
   0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
   0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
   0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
   0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
   0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
   0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
   0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
   0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
   0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
   0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
   0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
   0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
   0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
   0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
   0x85, 0xC8, 0xA1 };

const u32bit Twofish::MDS0[256] = {
   0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
   0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
   0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
   0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
   0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
   0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
   0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
   0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
   0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
   0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
   0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
   0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
   0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
   0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
   0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
   0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
   0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
   0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
   0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
   0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
   0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
   0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
   0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
   0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
   0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
   0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
   0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
   0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
   0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
   0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
   0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
   0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
   0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
   0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
   0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
   0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
   0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
   0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
   0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
   0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
   0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
   0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
   0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 };

const u32bit Twofish::MDS1[256] = {
   0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
   0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
   0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
   0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
   0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
   0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
   0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
   0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
   0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
   0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
   0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
   0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
   0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
   0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
   0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
   0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
   0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
   0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
   0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
   0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
   0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
   0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
   0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
   0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
   0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
   0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
   0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
   0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
   0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
   0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
   0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
   0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
   0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
   0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
   0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
   0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
   0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
   0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
   0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
   0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
   0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
   0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
   0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 };

const u32bit Twofish::MDS2[256] = {
   0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
   0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
   0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
   0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
   0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
   0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
   0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
   0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
   0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
   0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
   0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
   0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
   0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
   0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
   0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
   0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
   0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
   0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
   0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
   0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
   0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
   0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
   0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
   0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
   0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
   0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
   0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
   0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
   0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
   0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
   0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
   0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
   0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
   0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
   0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
   0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
   0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
   0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
   0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
   0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
   0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
   0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
   0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF };

const u32bit Twofish::MDS3[256] = {
   0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
   0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
   0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
   0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
   0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
   0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
   0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
   0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
   0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
   0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
   0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
   0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
   0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
   0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
   0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
   0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
   0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
   0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
   0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
   0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
   0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
   0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
   0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
   0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
   0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
   0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
   0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
   0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
   0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
   0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
   0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
   0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
   0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
   0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
   0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
   0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
   0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
   0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
   0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
   0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
   0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
   0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
   0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 };

}
/*
* Twofish
* (C) 1999-2007 Jack Lloyd
*
* The key schedule implemenation is based on a public domain
* implementation by Matthew Skala
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Twofish Encryption
*/
void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0) ^ RK[0];
      u32bit B = load_le<u32bit>(in, 1) ^ RK[1];
      u32bit C = load_le<u32bit>(in, 2) ^ RK[2];
      u32bit D = load_le<u32bit>(in, 3) ^ RK[3];

      for(size_t j = 0; j != 16; j += 2)
         {
         u32bit X, Y;

         X = SB[    get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^
             SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)];
         Y = SB[    get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^
             SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)];
         X += Y;
         Y += X + RK[2*j + 9];
         X += RK[2*j + 8];

         C = rotate_right(C ^ X, 1);
         D = rotate_left(D, 1) ^ Y;

         X = SB[    get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^
             SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)];
         Y = SB[    get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^
             SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)];
         X += Y;
         Y += X + RK[2*j + 11];
         X += RK[2*j + 10];

         A = rotate_right(A ^ X, 1);
         B = rotate_left(B, 1) ^ Y;
         }

      C ^= RK[4];
      D ^= RK[5];
      A ^= RK[6];
      B ^= RK[7];

      store_le(out, C, D, A, B);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Twofish Decryption
*/
void Twofish::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit A = load_le<u32bit>(in, 0) ^ RK[4];
      u32bit B = load_le<u32bit>(in, 1) ^ RK[5];
      u32bit C = load_le<u32bit>(in, 2) ^ RK[6];
      u32bit D = load_le<u32bit>(in, 3) ^ RK[7];

      for(size_t j = 0; j != 16; j += 2)
         {
         u32bit X, Y;

         X = SB[    get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^
             SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)];
         Y = SB[    get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^
             SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)];
         X += Y;
         Y += X + RK[39 - 2*j];
         X += RK[38 - 2*j];

         C = rotate_left(C, 1) ^ X;
         D = rotate_right(D ^ Y, 1);

         X = SB[    get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^
             SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)];
         Y = SB[    get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^
             SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)];
         X += Y;
         Y += X + RK[37 - 2*j];
         X += RK[36 - 2*j];

         A = rotate_left(A, 1) ^ X;
         B = rotate_right(B ^ Y, 1);
         }

      C ^= RK[0];
      D ^= RK[1];
      A ^= RK[2];
      B ^= RK[3];

      store_le(out, C, D, A, B);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* Twofish Key Schedule
*/
void Twofish::key_schedule(const byte key[], size_t length)
   {
   SecureVector<byte> S(16);

   for(size_t i = 0; i != length; ++i)
      rs_mul(&S[4*(i/8)], key[i], i);

   if(length == 16)
      {
      for(size_t i = 0; i != 256; ++i)
         {
         SB[    i] = MDS0[Q0[Q0[i]^S[ 0]]^S[ 4]];
         SB[256+i] = MDS1[Q0[Q1[i]^S[ 1]]^S[ 5]];
         SB[512+i] = MDS2[Q1[Q0[i]^S[ 2]]^S[ 6]];
         SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]];
         }

      for(size_t i = 0; i != 40; i += 2)
         {
         u32bit X = MDS0[Q0[Q0[i  ]^key[ 8]]^key[ 0]] ^
                    MDS1[Q0[Q1[i  ]^key[ 9]]^key[ 1]] ^
                    MDS2[Q1[Q0[i  ]^key[10]]^key[ 2]] ^
                    MDS3[Q1[Q1[i  ]^key[11]]^key[ 3]];
         u32bit Y = MDS0[Q0[Q0[i+1]^key[12]]^key[ 4]] ^
                    MDS1[Q0[Q1[i+1]^key[13]]^key[ 5]] ^
                    MDS2[Q1[Q0[i+1]^key[14]]^key[ 6]] ^
                    MDS3[Q1[Q1[i+1]^key[15]]^key[ 7]];
         Y = rotate_left(Y, 8);
         X += Y; Y += X;

         RK[i] = X;
         RK[i+1] = rotate_left(Y, 9);
         }
      }
   else if(length == 24)
      {
      for(size_t i = 0; i != 256; ++i)
         {
         SB[    i] = MDS0[Q0[Q0[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]];
         SB[256+i] = MDS1[Q0[Q1[Q1[i]^S[ 1]]^S[ 5]]^S[ 9]];
         SB[512+i] = MDS2[Q1[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]];
         SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]];
         }

      for(size_t i = 0; i != 40; i += 2)
         {
         u32bit X = MDS0[Q0[Q0[Q1[i  ]^key[16]]^key[ 8]]^key[ 0]] ^
                    MDS1[Q0[Q1[Q1[i  ]^key[17]]^key[ 9]]^key[ 1]] ^
                    MDS2[Q1[Q0[Q0[i  ]^key[18]]^key[10]]^key[ 2]] ^
                    MDS3[Q1[Q1[Q0[i  ]^key[19]]^key[11]]^key[ 3]];
         u32bit Y = MDS0[Q0[Q0[Q1[i+1]^key[20]]^key[12]]^key[ 4]] ^
                    MDS1[Q0[Q1[Q1[i+1]^key[21]]^key[13]]^key[ 5]] ^
                    MDS2[Q1[Q0[Q0[i+1]^key[22]]^key[14]]^key[ 6]] ^
                    MDS3[Q1[Q1[Q0[i+1]^key[23]]^key[15]]^key[ 7]];
         Y = rotate_left(Y, 8);
         X += Y; Y += X;

         RK[i] = X;
         RK[i+1] = rotate_left(Y, 9);
         }
      }
   else if(length == 32)
      {
      for(size_t i = 0; i != 256; ++i)
         {
         SB[    i] = MDS0[Q0[Q0[Q1[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]];
         SB[256+i] = MDS1[Q0[Q1[Q1[Q0[i]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]];
         SB[512+i] = MDS2[Q1[Q0[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]^S[14]];
         SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]];
         }

      for(size_t i = 0; i != 40; i += 2)
         {
         u32bit X = MDS0[Q0[Q0[Q1[Q1[i  ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^
                    MDS1[Q0[Q1[Q1[Q0[i  ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^
                    MDS2[Q1[Q0[Q0[Q0[i  ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^
                    MDS3[Q1[Q1[Q0[Q1[i  ]^key[27]]^key[19]]^key[11]]^key[ 3]];
         u32bit Y = MDS0[Q0[Q0[Q1[Q1[i+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^
                    MDS1[Q0[Q1[Q1[Q0[i+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^
                    MDS2[Q1[Q0[Q0[Q0[i+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^
                    MDS3[Q1[Q1[Q0[Q1[i+1]^key[31]]^key[23]]^key[15]]^key[ 7]];
         Y = rotate_left(Y, 8);
         X += Y; Y += X;

         RK[i] = X;
         RK[i+1] = rotate_left(Y, 9);
         }
      }
   }

/*
* Do one column of the RS matrix multiplcation
*/
void Twofish::rs_mul(byte S[4], byte key, size_t offset)
   {
   if(key)
      {
      byte X = POLY_TO_EXP[key - 1];

      byte RS1 = RS[(4*offset  ) % 32];
      byte RS2 = RS[(4*offset+1) % 32];
      byte RS3 = RS[(4*offset+2) % 32];
      byte RS4 = RS[(4*offset+3) % 32];

      S[0] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255];
      S[1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255];
      S[2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255];
      S[3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255];
      }
   }

/*
* Clear memory of sensitive data
*/
void Twofish::clear()
   {
   zeroise(SB);
   zeroise(RK);
   }

}
/*
* XTEA
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

void xtea_encrypt_4(const byte in[32], byte out[32], const u32bit EK[64])
   {
   u32bit L0, R0, L1, R1, L2, R2, L3, R3;
   load_be(in, L0, R0, L1, R1, L2, R2, L3, R3);

   for(size_t i = 0; i != 32; ++i)
      {
      L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i];
      L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i];
      L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i];
      L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i];

      R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1];
      R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1];
      R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1];
      R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1];
      }

   store_be(out, L0, R0, L1, R1, L2, R2, L3, R3);
   }

void xtea_decrypt_4(const byte in[32], byte out[32], const u32bit EK[64])
   {
   u32bit L0, R0, L1, R1, L2, R2, L3, R3;
   load_be(in, L0, R0, L1, R1, L2, R2, L3, R3);

   for(size_t i = 0; i != 32; ++i)
      {
      R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i];
      R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i];
      R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i];
      R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i];

      L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i];
      L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i];
      L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i];
      L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i];
      }

   store_be(out, L0, R0, L1, R1, L2, R2, L3, R3);
   }

}

/*
* XTEA Encryption
*/
void XTEA::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   while(blocks >= 4)
      {
      xtea_encrypt_4(in, out, &(this->EK[0]));
      in += 4 * BLOCK_SIZE;
      out += 4 * BLOCK_SIZE;
      blocks -= 4;
      }

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      for(size_t j = 0; j != 32; ++j)
         {
         L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*j];
         R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*j+1];
         }

      store_be(out, L, R);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* XTEA Decryption
*/
void XTEA::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   while(blocks >= 4)
      {
      xtea_decrypt_4(in, out, &(this->EK[0]));
      in += 4 * BLOCK_SIZE;
      out += 4 * BLOCK_SIZE;
      blocks -= 4;
      }

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit L = load_be<u32bit>(in, 0);
      u32bit R = load_be<u32bit>(in, 1);

      for(size_t j = 0; j != 32; ++j)
         {
         R -= (((L << 4) ^ (L >> 5)) + L) ^ EK[63 - 2*j];
         L -= (((R << 4) ^ (R >> 5)) + R) ^ EK[62 - 2*j];
         }

      store_be(out, L, R);

      in += BLOCK_SIZE;
      out += BLOCK_SIZE;
      }
   }

/*
* XTEA Key Schedule
*/
void XTEA::key_schedule(const byte key[], size_t)
   {
   SecureVector<u32bit> UK(4);
   for(size_t i = 0; i != 4; ++i)
      UK[i] = load_be<u32bit>(key, i);

   u32bit D = 0;
   for(size_t i = 0; i != 64; i += 2)
      {
      EK[i  ] = D + UK[D % 4];
      D += 0x9E3779B9;
      EK[i+1] = D + UK[(D >> 11) % 4];
      }
   }

}
/*
* XTEA in SIMD
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

void xtea_encrypt_8(const byte in[64], byte out[64], const u32bit EK[64])
   {
   SIMD_32 L0 = SIMD_32::load_be(in     );
   SIMD_32 R0 = SIMD_32::load_be(in + 16);
   SIMD_32 L1 = SIMD_32::load_be(in + 32);
   SIMD_32 R1 = SIMD_32::load_be(in + 48);

   SIMD_32::transpose(L0, R0, L1, R1);

   for(size_t i = 0; i != 32; i += 2)
      {
      SIMD_32 K0(EK[2*i  ]);
      SIMD_32 K1(EK[2*i+1]);
      SIMD_32 K2(EK[2*i+2]);
      SIMD_32 K3(EK[2*i+3]);

      L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K0;
      L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K0;

      R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K1;
      R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K1;

      L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K2;
      L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K2;

      R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K3;
      R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K3;
      }

   SIMD_32::transpose(L0, R0, L1, R1);

   L0.store_be(out);
   R0.store_be(out + 16);
   L1.store_be(out + 32);
   R1.store_be(out + 48);
   }

void xtea_decrypt_8(const byte in[64], byte out[64], const u32bit EK[64])
   {
   SIMD_32 L0 = SIMD_32::load_be(in     );
   SIMD_32 R0 = SIMD_32::load_be(in + 16);
   SIMD_32 L1 = SIMD_32::load_be(in + 32);
   SIMD_32 R1 = SIMD_32::load_be(in + 48);

   SIMD_32::transpose(L0, R0, L1, R1);

   for(size_t i = 0; i != 32; i += 2)
      {
      SIMD_32 K0(EK[63 - 2*i]);
      SIMD_32 K1(EK[62 - 2*i]);
      SIMD_32 K2(EK[61 - 2*i]);
      SIMD_32 K3(EK[60 - 2*i]);

      R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K0;
      R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K0;

      L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K1;
      L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K1;

      R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K2;
      R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K2;

      L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K3;
      L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K3;
      }

   SIMD_32::transpose(L0, R0, L1, R1);

   L0.store_be(out);
   R0.store_be(out + 16);
   L1.store_be(out + 32);
   R1.store_be(out + 48);
   }

}

/*
* XTEA Encryption
*/
void XTEA_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* KS = &(this->get_EK()[0]);

   while(blocks >= 8)
      {
      xtea_encrypt_8(in, out, KS);
      in += 8 * BLOCK_SIZE;
      out += 8 * BLOCK_SIZE;
      blocks -= 8;
      }

   if(blocks)
     XTEA::encrypt_n(in, out, blocks);
   }

/*
* XTEA Decryption
*/
void XTEA_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const
   {
   const u32bit* KS = &(this->get_EK()[0]);

   while(blocks >= 8)
      {
      xtea_decrypt_8(in, out, KS);
      in += 8 * BLOCK_SIZE;
      out += 8 * BLOCK_SIZE;
      blocks -= 8;
      }

   if(blocks)
     XTEA::decrypt_n(in, out, blocks);
   }

}
/*
* Certificate Store
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

Certificate_Store* Certificate_Store_Memory::clone() const
   {
   return new Certificate_Store_Memory(*this);
   }

void Certificate_Store_Memory::add_certificate(const X509_Certificate& cert)
   {
   for(size_t i = 0; i != certs.size(); ++i)
      {
      if(certs[i] == cert)
         return;
      }

   certs.push_back(cert);
   }

std::vector<X509_Certificate>
Certificate_Store_Memory::find_cert_by_subject_and_key_id(
   const X509_DN& subject_dn,
   const MemoryRegion<byte>& key_id) const
   {
   std::vector<X509_Certificate> result;

   for(size_t i = 0; i != certs.size(); ++i)
      {
      // Only compare key ids if set in both call and in the cert
      if(key_id.size())
         {
         MemoryVector<byte> skid = certs[i].subject_key_id();

         if(skid.size() && skid != key_id) // no match
            continue;
         }

      if(certs[i].subject_dn() == subject_dn)
         result.push_back(certs[i]);
      }

   return result;
   }

void Certificate_Store_Memory::add_crl(const X509_CRL& crl)
   {
   X509_DN crl_issuer = crl.issuer_dn();

   for(size_t i = 0; i != crls.size(); ++i)
      {
      // Found an update of a previously existing one; replace it
      if(crls[i].issuer_dn() == crl_issuer)
         {
         if(crls[i].this_update() < crl.this_update())
            {
            crls[i] = crl;
            return;
            }
         }
      }

   // Totally new CRL, add to the list
   crls.push_back(crl);
   }

std::vector<X509_CRL>
Certificate_Store_Memory::find_crl_by_subject_and_key_id(
   const X509_DN& issuer_dn,
   const MemoryRegion<byte>& key_id) const
   {
   std::vector<X509_CRL> result;

   for(size_t i = 0; i != crls.size(); ++i)
      {
      // Only compare key ids if set in both call and in the CRL
      if(key_id.size())
         {
         MemoryVector<byte> akid = crls[i].authority_key_id();

         if(akid.size() && akid != key_id) // no match
            continue;
         }

      if(crls[i].issuer_dn() == issuer_dn)
         result.push_back(crls[i]);
      }

   return result;
   }

}
/*
* PKCS #10
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* PKCS10_Request Constructor
*/
PKCS10_Request::PKCS10_Request(DataSource& in) :
   X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST")
   {
   do_decode();
   }

/*
* PKCS10_Request Constructor
*/
PKCS10_Request::PKCS10_Request(const std::string& in) :
   X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST")
   {
   do_decode();
   }

/*
* Deocde the CertificateRequestInfo
*/
void PKCS10_Request::force_decode()
   {
   BER_Decoder cert_req_info(tbs_bits);

   size_t version;
   cert_req_info.decode(version);
   if(version != 0)
      throw Decoding_Error("Unknown version code in PKCS #10 request: " +
                           to_string(version));

   X509_DN dn_subject;
   cert_req_info.decode(dn_subject);

   info.add(dn_subject.contents());

   BER_Object public_key = cert_req_info.get_next_object();
   if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
      throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key",
                        public_key.type_tag, public_key.class_tag);

   info.add("X509.Certificate.public_key",
            PEM_Code::encode(
               ASN1::put_in_sequence(public_key.value),
               "PUBLIC KEY"
               )
      );

   BER_Object attr_bits = cert_req_info.get_next_object();

   if(attr_bits.type_tag == 0 &&
      attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
      {
      BER_Decoder attributes(attr_bits.value);
      while(attributes.more_items())
         {
         Attribute attr;
         attributes.decode(attr);
         handle_attribute(attr);
         }
      attributes.verify_end();
      }
   else if(attr_bits.type_tag != NO_OBJECT)
      throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes",
                        attr_bits.type_tag, attr_bits.class_tag);

   cert_req_info.verify_end();

   if(!this->check_signature(subject_public_key()))
      throw Decoding_Error("PKCS #10 request: Bad signature detected");
   }

/*
* Handle attributes in a PKCS #10 request
*/
void PKCS10_Request::handle_attribute(const Attribute& attr)
   {
   BER_Decoder value(attr.parameters);

   if(attr.oid == OIDS::lookup("PKCS9.EmailAddress"))
      {
      ASN1_String email;
      value.decode(email);
      info.add("RFC822", email.value());
      }
   else if(attr.oid == OIDS::lookup("PKCS9.ChallengePassword"))
      {
      ASN1_String challenge_password;
      value.decode(challenge_password);
      info.add("PKCS9.ChallengePassword", challenge_password.value());
      }
   else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest"))
      {
      Extensions extensions;
      value.decode(extensions).verify_end();

      Data_Store issuer_info;
      extensions.contents_to(info, issuer_info);
      }
   }

/*
* Return the challenge password (if any)
*/
std::string PKCS10_Request::challenge_password() const
   {
   return info.get1("PKCS9.ChallengePassword");
   }

/*
* Return the name of the requestor
*/
X509_DN PKCS10_Request::subject_dn() const
   {
   return create_dn(info);
   }

/*
* Return the public key of the requestor
*/
MemoryVector<byte> PKCS10_Request::raw_public_key() const
   {
   DataSource_Memory source(info.get1("X509.Certificate.public_key"));
   return PEM_Code::decode_check_label(source, "PUBLIC KEY");
   }

/*
* Return the public key of the requestor
*/
Public_Key* PKCS10_Request::subject_public_key() const
   {
   DataSource_Memory source(info.get1("X509.Certificate.public_key"));
   return X509::load_key(source);
   }

/*
* Return the alternative names of the requestor
*/
AlternativeName PKCS10_Request::subject_alt_name() const
   {
   return create_alt_name(info);
   }

/*
* Return the key constraints (if any)
*/
Key_Constraints PKCS10_Request::constraints() const
   {
   return Key_Constraints(info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS));
   }

/*
* Return the extendend key constraints (if any)
*/
std::vector<OID> PKCS10_Request::ex_constraints() const
   {
   std::vector<std::string> oids = info.get("X509v3.ExtendedKeyUsage");

   std::vector<OID> result;
   for(size_t i = 0; i != oids.size(); ++i)
      result.push_back(OID(oids[i]));
   return result;
   }

/*
* Return is a CA certificate is requested
*/
bool PKCS10_Request::is_CA() const
   {
   return (info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0);
   }

/*
* Return the desired path limit (if any)
*/
u32bit PKCS10_Request::path_limit() const
   {
   return info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0);
   }

}
/*
* X.509 Certificate Authority
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <typeinfo>
#include <iterator>
#include <memory>
#include <set>

namespace Botan {

/*
* Load the certificate and private key
*/
X509_CA::X509_CA(const X509_Certificate& c,
                 const Private_Key& key,
                 const std::string& hash_fn) : cert(c)
   {
   if(!cert.is_CA_cert())
      throw Invalid_Argument("X509_CA: This certificate is not for a CA");

   signer = choose_sig_format(key, hash_fn, ca_sig_algo);
   }

/*
* X509_CA Destructor
*/
X509_CA::~X509_CA()
   {
   delete signer;
   }

/*
* Sign a PKCS #10 certificate request
*/
X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
                                       RandomNumberGenerator& rng,
                                       const X509_Time& not_before,
                                       const X509_Time& not_after)
   {
   Key_Constraints constraints;
   if(req.is_CA())
      constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
   else
      {
      std::auto_ptr<Public_Key> key(req.subject_public_key());
      constraints = X509::find_constraints(*key, req.constraints());
      }

   Extensions extensions;

   extensions.add(
      new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
      true);

   extensions.add(new Cert_Extension::Key_Usage(constraints), true);

   extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
   extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));

   extensions.add(
      new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name()));

   extensions.add(
      new Cert_Extension::Extended_Key_Usage(req.ex_constraints()));

   return make_cert(signer, rng, ca_sig_algo,
                    req.raw_public_key(),
                    not_before, not_after,
                    cert.subject_dn(), req.subject_dn(),
                    extensions);
   }

/*
* Create a new certificate
*/
X509_Certificate X509_CA::make_cert(PK_Signer* signer,
                                    RandomNumberGenerator& rng,
                                    const AlgorithmIdentifier& sig_algo,
                                    const MemoryRegion<byte>& pub_key,
                                    const X509_Time& not_before,
                                    const X509_Time& not_after,
                                    const X509_DN& issuer_dn,
                                    const X509_DN& subject_dn,
                                    const Extensions& extensions)
   {
   const size_t X509_CERT_VERSION = 3;
   const size_t SERIAL_BITS = 128;

   BigInt serial_no(rng, SERIAL_BITS);

   DataSource_Memory source(X509_Object::make_signed(signer, rng, sig_algo,
         DER_Encoder().start_cons(SEQUENCE)
            .start_explicit(0)
               .encode(X509_CERT_VERSION-1)
            .end_explicit()

            .encode(serial_no)

            .encode(sig_algo)
            .encode(issuer_dn)

            .start_cons(SEQUENCE)
               .encode(not_before)
               .encode(not_after)
            .end_cons()

            .encode(subject_dn)
            .raw_bytes(pub_key)

            .start_explicit(3)
               .start_cons(SEQUENCE)
                  .encode(extensions)
                .end_cons()
            .end_explicit()
         .end_cons()
      .get_contents()
   ));

   return X509_Certificate(source);
   }

/*
* Create a new, empty CRL
*/
X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng,
                          u32bit next_update) const
   {
   std::vector<CRL_Entry> empty;
   return make_crl(empty, 1, next_update, rng);
   }

/*
* Update a CRL with new entries
*/
X509_CRL X509_CA::update_crl(const X509_CRL& crl,
                             const std::vector<CRL_Entry>& new_revoked,
                             RandomNumberGenerator& rng,
                             u32bit next_update) const
   {
   std::vector<CRL_Entry> revoked = crl.get_revoked();

   std::copy(new_revoked.begin(), new_revoked.end(),
             std::back_inserter(revoked));

   return make_crl(revoked, crl.crl_number() + 1, next_update, rng);
   }

/*
* Create a CRL
*/
X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
                           u32bit crl_number, u32bit next_update,
                           RandomNumberGenerator& rng) const
   {
   const size_t X509_CRL_VERSION = 2;

   if(next_update == 0)
      next_update = timespec_to_u32bit("7d");

   // Totally stupid: ties encoding logic to the return of std::time!!
   const u64bit current_time = system_time();

   Extensions extensions;
   extensions.add(
      new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
   extensions.add(new Cert_Extension::CRL_Number(crl_number));

   DataSource_Memory source(X509_Object::make_signed(signer, rng, ca_sig_algo,
         DER_Encoder().start_cons(SEQUENCE)
            .encode(X509_CRL_VERSION-1)
            .encode(ca_sig_algo)
            .encode(cert.issuer_dn())
            .encode(X509_Time(current_time))
            .encode(X509_Time(current_time + next_update))
            .encode_if(revoked.size() > 0,
                 DER_Encoder()
                    .start_cons(SEQUENCE)
                       .encode_list(revoked)
                    .end_cons()
               )
            .start_explicit(0)
               .start_cons(SEQUENCE)
                  .encode(extensions)
               .end_cons()
            .end_explicit()
         .end_cons()
      .get_contents()
   ));

   return X509_CRL(source);
   }

/*
* Return the CA's certificate
*/
X509_Certificate X509_CA::ca_certificate() const
   {
   return cert;
   }

/*
* Choose a signing format for the key
*/
PK_Signer* choose_sig_format(const Private_Key& key,
                             const std::string& hash_fn,
                             AlgorithmIdentifier& sig_algo)
   {
   std::string padding;

   const std::string algo_name = key.algo_name();

   const HashFunction* proto_hash = retrieve_hash(hash_fn);
   if(!proto_hash)
      throw Algorithm_Not_Found(hash_fn);

   if(key.max_input_bits() < proto_hash->output_length()*8)
      throw Invalid_Argument("Key is too small for chosen hash function");

   if(algo_name == "RSA")
      padding = "EMSA3";
   else if(algo_name == "DSA")
      padding = "EMSA1";
   else if(algo_name == "ECDSA")
      padding = "EMSA1_BSI";
   else
      throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);

   Signature_Format format =
      (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;

   padding = padding + '(' + proto_hash->name() + ')';

   sig_algo.oid = OIDS::lookup(algo_name + "/" + padding);
   sig_algo.parameters = key.algorithm_identifier().parameters;

   return new PK_Signer(key, padding, format);
   }

}
/*
* X.509 Certificate Extensions
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

/*
* List of X.509 Certificate Extensions
*/
Certificate_Extension* Extensions::get_extension(const OID& oid)
   {
#define X509_EXTENSION(NAME, TYPE) \
   if(OIDS::name_of(oid, NAME))    \
      return new Cert_Extension::TYPE();

   X509_EXTENSION("X509v3.KeyUsage", Key_Usage);
   X509_EXTENSION("X509v3.BasicConstraints", Basic_Constraints);
   X509_EXTENSION("X509v3.SubjectKeyIdentifier", Subject_Key_ID);
   X509_EXTENSION("X509v3.AuthorityKeyIdentifier", Authority_Key_ID);
   X509_EXTENSION("X509v3.ExtendedKeyUsage", Extended_Key_Usage);
   X509_EXTENSION("X509v3.IssuerAlternativeName", Issuer_Alternative_Name);
   X509_EXTENSION("X509v3.SubjectAlternativeName", Subject_Alternative_Name);
   X509_EXTENSION("X509v3.CRLNumber", CRL_Number);
   X509_EXTENSION("X509v3.CertificatePolicies", Certificate_Policies);
   X509_EXTENSION("X509v3.ReasonCode", CRL_ReasonCode);

   return 0;
   }

/*
* Extensions Copy Constructor
*/
Extensions::Extensions(const Extensions& extensions) : ASN1_Object()
   {
   *this = extensions;
   }

/*
* Extensions Assignment Operator
*/
Extensions& Extensions::operator=(const Extensions& other)
   {
   for(size_t i = 0; i != extensions.size(); ++i)
      delete extensions[i].first;
   extensions.clear();

   for(size_t i = 0; i != other.extensions.size(); ++i)
      extensions.push_back(
         std::make_pair(other.extensions[i].first->copy(),
                        other.extensions[i].second));

   return (*this);
   }

/*
* Return the OID of this extension
*/
OID Certificate_Extension::oid_of() const
   {
   return OIDS::lookup(oid_name());
   }

void Extensions::add(Certificate_Extension* extn, bool critical)
   {
   extensions.push_back(std::make_pair(extn, critical));
   }

/*
* Encode an Extensions list
*/
void Extensions::encode_into(DER_Encoder& to_object) const
   {
   for(size_t i = 0; i != extensions.size(); ++i)
      {
      const Certificate_Extension* ext = extensions[i].first;
      const bool is_critical = extensions[i].second;

      const bool should_encode = ext->should_encode();

      if(should_encode)
         {
         to_object.start_cons(SEQUENCE)
               .encode(ext->oid_of())
               .encode_optional(is_critical, false)
               .encode(ext->encode_inner(), OCTET_STRING)
            .end_cons();
         }
      }
   }

/*
* Decode a list of Extensions
*/
void Extensions::decode_from(BER_Decoder& from_source)
   {
   for(size_t i = 0; i != extensions.size(); ++i)
      delete extensions[i].first;
   extensions.clear();

   BER_Decoder sequence = from_source.start_cons(SEQUENCE);

   while(sequence.more_items())
      {
      OID oid;
      MemoryVector<byte> value;
      bool critical;

      sequence.start_cons(SEQUENCE)
            .decode(oid)
            .decode_optional(critical, BOOLEAN, UNIVERSAL, false)
            .decode(value, OCTET_STRING)
            .verify_end()
         .end_cons();

      Certificate_Extension* ext = get_extension(oid);

      if(!ext)
         {
         if(!critical || !should_throw)
            continue;

         throw Decoding_Error("Encountered unknown X.509 extension marked "
                              "as critical; OID = " + oid.as_string());
         }

      ext->decode_inner(value);

      extensions.push_back(std::make_pair(ext, critical));
      }
   sequence.verify_end();
   }

/*
* Write the extensions to an info store
*/
void Extensions::contents_to(Data_Store& subject_info,
                             Data_Store& issuer_info) const
   {
   for(size_t i = 0; i != extensions.size(); ++i)
      extensions[i].first->contents_to(subject_info, issuer_info);
   }

/*
* Delete an Extensions list
*/
Extensions::~Extensions()
   {
   for(size_t i = 0; i != extensions.size(); ++i)
      delete extensions[i].first;
   }

namespace Cert_Extension {

/*
* Checked accessor for the path_limit member
*/
size_t Basic_Constraints::get_path_limit() const
   {
   if(!is_ca)
      throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA");
   return path_limit;
   }

/*
* Encode the extension
*/
MemoryVector<byte> Basic_Constraints::encode_inner() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
      .encode_if(is_ca,
                 DER_Encoder()
                    .encode(is_ca)
                    .encode_optional(path_limit, NO_CERT_PATH_LIMIT)
         )
      .end_cons()
   .get_contents();
   }

/*
* Decode the extension
*/
void Basic_Constraints::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in)
      .start_cons(SEQUENCE)
         .decode_optional(is_ca, BOOLEAN, UNIVERSAL, false)
         .decode_optional(path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT)
         .verify_end()
      .end_cons();

   if(is_ca == false)
      path_limit = 0;
   }

/*
* Return a textual representation
*/
void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const
   {
   subject.add("X509v3.BasicConstraints.is_ca", (is_ca ? 1 : 0));
   subject.add("X509v3.BasicConstraints.path_constraint", path_limit);
   }

/*
* Encode the extension
*/
MemoryVector<byte> Key_Usage::encode_inner() const
   {
   if(constraints == NO_CONSTRAINTS)
      throw Encoding_Error("Cannot encode zero usage constraints");

   const size_t unused_bits = low_bit(constraints) - 1;

   MemoryVector<byte> der;
   der.push_back(BIT_STRING);
   der.push_back(2 + ((unused_bits < 8) ? 1 : 0));
   der.push_back(unused_bits % 8);
   der.push_back((constraints >> 8) & 0xFF);
   if(constraints & 0xFF)
      der.push_back(constraints & 0xFF);

   return der;
   }

/*
* Decode the extension
*/
void Key_Usage::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder ber(in);

   BER_Object obj = ber.get_next_object();

   if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
      throw BER_Bad_Tag("Bad tag for usage constraint",
                        obj.type_tag, obj.class_tag);

   if(obj.value.size() != 2 && obj.value.size() != 3)
      throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");

   if(obj.value[0] >= 8)
      throw BER_Decoding_Error("Invalid unused bits in usage constraint");

   obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]);

   u16bit usage = 0;
   for(size_t i = 1; i != obj.value.size(); ++i)
      usage = (obj.value[i] << 8) | usage;

   constraints = Key_Constraints(usage);
   }

/*
* Return a textual representation
*/
void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const
   {
   subject.add("X509v3.KeyUsage", constraints);
   }

/*
* Encode the extension
*/
MemoryVector<byte> Subject_Key_ID::encode_inner() const
   {
   return DER_Encoder().encode(key_id, OCTET_STRING).get_contents();
   }

/*
* Decode the extension
*/
void Subject_Key_ID::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in).decode(key_id, OCTET_STRING).verify_end();
   }

/*
* Return a textual representation
*/
void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const
   {
   subject.add("X509v3.SubjectKeyIdentifier", key_id);
   }

/*
* Subject_Key_ID Constructor
*/
Subject_Key_ID::Subject_Key_ID(const MemoryRegion<byte>& pub_key)
   {
   SHA_160 hash;
   key_id = hash.process(pub_key);
   }

/*
* Encode the extension
*/
MemoryVector<byte> Authority_Key_ID::encode_inner() const
   {
   return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC)
         .end_cons()
      .get_contents();
   }

/*
* Decode the extension
*/
void Authority_Key_ID::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in)
      .start_cons(SEQUENCE)
      .decode_optional_string(key_id, OCTET_STRING, 0);
   }

/*
* Return a textual representation
*/
void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const
   {
   if(key_id.size())
      issuer.add("X509v3.AuthorityKeyIdentifier", key_id);
   }

/*
* Encode the extension
*/
MemoryVector<byte> Alternative_Name::encode_inner() const
   {
   return DER_Encoder().encode(alt_name).get_contents();
   }

/*
* Decode the extension
*/
void Alternative_Name::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in).decode(alt_name);
   }

/*
* Return a textual representation
*/
void Alternative_Name::contents_to(Data_Store& subject_info,
                                   Data_Store& issuer_info) const
   {
   std::multimap<std::string, std::string> contents =
      get_alt_name().contents();

   if(oid_name_str == "X509v3.SubjectAlternativeName")
      subject_info.add(contents);
   else if(oid_name_str == "X509v3.IssuerAlternativeName")
      issuer_info.add(contents);
   else
      throw Internal_Error("In Alternative_Name, unknown type " +
                           oid_name_str);
   }

/*
* Alternative_Name Constructor
*/
Alternative_Name::Alternative_Name(const AlternativeName& alt_name,
                                   const std::string& oid_name_str,
                                   const std::string& config_name_str)
   {
   this->alt_name = alt_name;
   this->oid_name_str = oid_name_str;
   this->config_name_str = config_name_str;
   }

/*
* Subject_Alternative_Name Constructor
*/
Subject_Alternative_Name::Subject_Alternative_Name(
   const AlternativeName& name) :

   Alternative_Name(name, "X509v3.SubjectAlternativeName",
                    "subject_alternative_name")
   {
   }

/*
* Issuer_Alternative_Name Constructor
*/
Issuer_Alternative_Name::Issuer_Alternative_Name(const AlternativeName& name) :
   Alternative_Name(name, "X509v3.IssuerAlternativeName",
                    "issuer_alternative_name")
   {
   }

/*
* Encode the extension
*/
MemoryVector<byte> Extended_Key_Usage::encode_inner() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode_list(oids)
      .end_cons()
   .get_contents();
   }

/*
* Decode the extension
*/
void Extended_Key_Usage::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in)
      .start_cons(SEQUENCE)
         .decode_list(oids)
      .end_cons();
   }

/*
* Return a textual representation
*/
void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const
   {
   for(size_t i = 0; i != oids.size(); ++i)
      subject.add("X509v3.ExtendedKeyUsage", oids[i].as_string());
   }

/*
* A policy specifier
*/
class Policy_Information : public ASN1_Object
   {
   public:
      OID oid;

      Policy_Information() {}
      Policy_Information(const OID& oid) : oid(oid) {}

      void encode_into(DER_Encoder& codec) const
         {
         codec.start_cons(SEQUENCE)
            .encode(oid)
            .end_cons();
         }

      void decode_from(BER_Decoder& codec)
         {
         codec.start_cons(SEQUENCE)
            .decode(oid)
            .discard_remaining()
            .end_cons();
         }
   };

/*
* Encode the extension
*/
MemoryVector<byte> Certificate_Policies::encode_inner() const
   {
   std::vector<Policy_Information> policies;

   for(size_t i = 0; i != oids.size(); ++i)
      policies.push_back(oids[i]);

   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode_list(policies)
      .end_cons()
   .get_contents();
   }

/*
* Decode the extension
*/
void Certificate_Policies::decode_inner(const MemoryRegion<byte>& in)
   {
   std::vector<Policy_Information> policies;

   BER_Decoder(in)
      .start_cons(SEQUENCE)
         .decode_list(policies)
      .end_cons();

   oids.clear();
   for(size_t i = 0; i != policies.size(); ++i)
      oids.push_back(policies[i].oid);
   }

/*
* Return a textual representation
*/
void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const
   {
   for(size_t i = 0; i != oids.size(); ++i)
      info.add("X509v3.ExtendedKeyUsage", oids[i].as_string());
   }

/*
* Checked accessor for the crl_number member
*/
size_t CRL_Number::get_crl_number() const
   {
   if(!has_value)
      throw Invalid_State("CRL_Number::get_crl_number: Not set");
   return crl_number;
   }

/*
* Copy a CRL_Number extension
*/
CRL_Number* CRL_Number::copy() const
   {
   if(!has_value)
      throw Invalid_State("CRL_Number::copy: Not set");
   return new CRL_Number(crl_number);
   }

/*
* Encode the extension
*/
MemoryVector<byte> CRL_Number::encode_inner() const
   {
   return DER_Encoder().encode(crl_number).get_contents();
   }

/*
* Decode the extension
*/
void CRL_Number::decode_inner(const MemoryRegion<byte>& in)
   {
   BER_Decoder(in).decode(crl_number);
   }

/*
* Return a textual representation
*/
void CRL_Number::contents_to(Data_Store& info, Data_Store&) const
   {
   info.add("X509v3.CRLNumber", crl_number);
   }

/*
* Encode the extension
*/
MemoryVector<byte> CRL_ReasonCode::encode_inner() const
   {
   return DER_Encoder()
      .encode(static_cast<size_t>(reason), ENUMERATED, UNIVERSAL)
   .get_contents();
   }

/*
* Decode the extension
*/
void CRL_ReasonCode::decode_inner(const MemoryRegion<byte>& in)
   {
   size_t reason_code = 0;
   BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL);
   reason = static_cast<CRL_Code>(reason_code);
   }

/*
* Return a textual representation
*/
void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const
   {
   info.add("X509v3.CRLReasonCode", reason);
   }

}

}
/*
* X.509 SIGNED Object
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(DataSource& stream, const std::string& labels)
   {
   init(stream, labels);
   }

/*
* Createa a generic X.509 object
*/
X509_Object::X509_Object(const std::string& file, const std::string& labels)
   {
   DataSource_Stream stream(file, true);
   init(stream, labels);
   }

/*
* Read a PEM or BER X.509 object
*/
void X509_Object::init(DataSource& in, const std::string& labels)
   {
   PEM_labels_allowed = split_on(labels, '/');
   if(PEM_labels_allowed.size() < 1)
      throw Invalid_Argument("Bad labels argument to X509_Object");

   PEM_label_pref = PEM_labels_allowed[0];
   std::sort(PEM_labels_allowed.begin(), PEM_labels_allowed.end());

   try {
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
         decode_info(in);
      else
         {
         std::string got_label;
         DataSource_Memory ber(PEM_Code::decode(in, got_label));

         if(!std::binary_search(PEM_labels_allowed.begin(),
                                PEM_labels_allowed.end(), got_label))
            throw Decoding_Error("Invalid PEM label: " + got_label);
         decode_info(ber);
         }
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(PEM_label_pref + " decoding failed: " + e.what());
      }
   }

/*
* Read a BER encoded X.509 object
*/
void X509_Object::decode_info(DataSource& source)
   {
   BER_Decoder(source)
      .start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(tbs_bits)
         .end_cons()
         .decode(sig_algo)
         .decode(sig, BIT_STRING)
         .verify_end()
      .end_cons();
   }

/*
* Return a BER or PEM encoded X.509 object
*/
void X509_Object::encode(Pipe& out, X509_Encoding encoding) const
   {
   if(encoding == PEM)
      out.write(this->PEM_encode());
   else
      out.write(this->BER_encode());
   }

/*
* Return a BER encoded X.509 object
*/
MemoryVector<byte> X509_Object::BER_encode() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(tbs_bits)
         .end_cons()
         .encode(sig_algo)
         .encode(sig, BIT_STRING)
      .end_cons()
   .get_contents();
   }

/*
* Return a PEM encoded X.509 object
*/
std::string X509_Object::PEM_encode() const
   {
   return PEM_Code::encode(BER_encode(), PEM_label_pref);
   }

/*
* Return the TBS data
*/
MemoryVector<byte> X509_Object::tbs_data() const
   {
   return ASN1::put_in_sequence(tbs_bits);
   }

/*
* Return the signature of this object
*/
MemoryVector<byte> X509_Object::signature() const
   {
   return sig;
   }

/*
* Return the algorithm used to sign this object
*/
AlgorithmIdentifier X509_Object::signature_algorithm() const
   {
   return sig_algo;
   }

/*
* Return the hash used in generating the signature
*/
std::string X509_Object::hash_used_for_signature() const
   {
   std::vector<std::string> sig_info =
      split_on(OIDS::lookup(sig_algo.oid), '/');

   if(sig_info.size() != 2)
      throw Internal_Error("Invalid name format found for " +
                           sig_algo.oid.as_string());

   std::vector<std::string> pad_and_hash =
      parse_algorithm_name(sig_info[1]);

   if(pad_and_hash.size() != 2)
      throw Internal_Error("Invalid name format " + sig_info[1]);

   return pad_and_hash[1];
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(Public_Key* pub_key) const
   {
   std::auto_ptr<Public_Key> key(pub_key);
   return check_signature(*key);
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(Public_Key& pub_key) const
   {
   try {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
         return false;

      std::string padding = sig_info[1];
      Signature_Format format =
         (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      PK_Verifier verifier(pub_key, padding, format);

      return verifier.verify_message(tbs_data(), signature());
      }
   catch(...)
      {
      return false;
      }
   }

/*
* Apply the X.509 SIGNED macro
*/
MemoryVector<byte> X509_Object::make_signed(PK_Signer* signer,
                                            RandomNumberGenerator& rng,
                                            const AlgorithmIdentifier& algo,
                                            const MemoryRegion<byte>& tbs_bits)
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .raw_bytes(tbs_bits)
         .encode(algo)
         .encode(signer->sign_message(tbs_bits, rng), BIT_STRING)
      .end_cons()
   .get_contents();
   }

/*
* Try to decode the actual information
*/
void X509_Object::do_decode()
   {
   try {
      force_decode();
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(PEM_label_pref + " decoding failed (" +
                           e.what() + ")");
      }
   catch(Invalid_Argument& e)
      {
      throw Decoding_Error(PEM_label_pref + " decoding failed (" +
                           e.what() + ")");
      }
   }

}
/*
* X.509 Certificates
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <iterator>
#include <sstream>

namespace Botan {

namespace {

/*
* Lookup each OID in the vector
*/
std::vector<std::string> lookup_oids(const std::vector<std::string>& in)
   {
   std::vector<std::string> out;

   std::vector<std::string>::const_iterator i = in.begin();
   while(i != in.end())
      {
      out.push_back(OIDS::lookup(OID(*i)));
      ++i;
      }
   return out;
   }

}

/*
* X509_Certificate Constructor
*/
X509_Certificate::X509_Certificate(DataSource& in) :
   X509_Object(in, "CERTIFICATE/X509 CERTIFICATE")
   {
   self_signed = false;
   do_decode();
   }

/*
* X509_Certificate Constructor
*/
X509_Certificate::X509_Certificate(const std::string& in) :
   X509_Object(in, "CERTIFICATE/X509 CERTIFICATE")
   {
   self_signed = false;
   do_decode();
   }

/*
* Decode the TBSCertificate data
*/
void X509_Certificate::force_decode()
   {
   size_t version;
   BigInt serial_bn;
   AlgorithmIdentifier sig_algo_inner;
   X509_DN dn_issuer, dn_subject;
   X509_Time start, end;

   BER_Decoder tbs_cert(tbs_bits);

   tbs_cert.decode_optional(version, ASN1_Tag(0),
                            ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
      .decode(serial_bn)
      .decode(sig_algo_inner)
      .decode(dn_issuer)
      .start_cons(SEQUENCE)
         .decode(start)
         .decode(end)
         .verify_end()
      .end_cons()
      .decode(dn_subject);

   if(version > 2)
      throw Decoding_Error("Unknown X.509 cert version " + Botan::to_string(version));
   if(sig_algo != sig_algo_inner)
      throw Decoding_Error("Algorithm identifier mismatch");

   self_signed = (dn_subject == dn_issuer);

   subject.add(dn_subject.contents());
   issuer.add(dn_issuer.contents());

   BER_Object public_key = tbs_cert.get_next_object();
   if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
      throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key",
                        public_key.type_tag, public_key.class_tag);

   MemoryVector<byte> v2_issuer_key_id, v2_subject_key_id;

   tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1);
   tbs_cert.decode_optional_string(v2_subject_key_id, BIT_STRING, 2);

   BER_Object v3_exts_data = tbs_cert.get_next_object();
   if(v3_exts_data.type_tag == 3 &&
      v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
      {
      Extensions extensions;

      BER_Decoder(v3_exts_data.value).decode(extensions).verify_end();

      extensions.contents_to(subject, issuer);
      }
   else if(v3_exts_data.type_tag != NO_OBJECT)
      throw BER_Bad_Tag("Unknown tag in X.509 cert",
                        v3_exts_data.type_tag, v3_exts_data.class_tag);

   if(tbs_cert.more_items())
      throw Decoding_Error("TBSCertificate has more items that expected");

   subject.add("X509.Certificate.version", version);
   subject.add("X509.Certificate.serial", BigInt::encode(serial_bn));
   subject.add("X509.Certificate.start", start.readable_string());
   subject.add("X509.Certificate.end", end.readable_string());

   issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id);
   subject.add("X509.Certificate.v2.key_id", v2_subject_key_id);

   subject.add("X509.Certificate.public_key",
               PEM_Code::encode(
                  ASN1::put_in_sequence(public_key.value),
                  "PUBLIC KEY"
                  )
      );

   if(is_CA_cert() &&
      !subject.has_value("X509v3.BasicConstraints.path_constraint"))
      {
      const size_t limit = (x509_version() < 3) ?
        Cert_Extension::NO_CERT_PATH_LIMIT : 0;

      subject.add("X509v3.BasicConstraints.path_constraint", limit);
      }
   }

/*
* Return the X.509 version in use
*/
u32bit X509_Certificate::x509_version() const
   {
   return (subject.get1_u32bit("X509.Certificate.version") + 1);
   }

/*
* Return the time this cert becomes valid
*/
std::string X509_Certificate::start_time() const
   {
   return subject.get1("X509.Certificate.start");
   }

/*
* Return the time this cert becomes invalid
*/
std::string X509_Certificate::end_time() const
   {
   return subject.get1("X509.Certificate.end");
   }

/*
* Return information about the subject
*/
std::vector<std::string>
X509_Certificate::subject_info(const std::string& what) const
   {
   return subject.get(X509_DN::deref_info_field(what));
   }

/*
* Return information about the issuer
*/
std::vector<std::string>
X509_Certificate::issuer_info(const std::string& what) const
   {
   return issuer.get(X509_DN::deref_info_field(what));
   }

/*
* Return the public key in this certificate
*/
Public_Key* X509_Certificate::subject_public_key() const
   {
   DataSource_Memory source(subject.get1("X509.Certificate.public_key"));
   return X509::load_key(source);
   }

/*
* Check if the certificate is for a CA
*/
bool X509_Certificate::is_CA_cert() const
   {
   if(!subject.get1_u32bit("X509v3.BasicConstraints.is_ca"))
      return false;
   if((constraints() & KEY_CERT_SIGN) || (constraints() == NO_CONSTRAINTS))
      return true;
   return false;
   }

/*
* Return the path length constraint
*/
u32bit X509_Certificate::path_limit() const
   {
   return subject.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0);
   }

/*
* Return the key usage constraints
*/
Key_Constraints X509_Certificate::constraints() const
   {
   return Key_Constraints(subject.get1_u32bit("X509v3.KeyUsage",
                                              NO_CONSTRAINTS));
   }

/*
* Return the list of extended key usage OIDs
*/
std::vector<std::string> X509_Certificate::ex_constraints() const
   {
   return lookup_oids(subject.get("X509v3.ExtendedKeyUsage"));
   }

/*
* Return the list of certificate policies
*/
std::vector<std::string> X509_Certificate::policies() const
   {
   return lookup_oids(subject.get("X509v3.CertificatePolicies"));
   }

/*
* Return the authority key id
*/
MemoryVector<byte> X509_Certificate::authority_key_id() const
   {
   return issuer.get1_memvec("X509v3.AuthorityKeyIdentifier");
   }

/*
* Return the subject key id
*/
MemoryVector<byte> X509_Certificate::subject_key_id() const
   {
   return subject.get1_memvec("X509v3.SubjectKeyIdentifier");
   }

/*
* Return the certificate serial number
*/
MemoryVector<byte> X509_Certificate::serial_number() const
   {
   return subject.get1_memvec("X509.Certificate.serial");
   }

/*
* Return the distinguished name of the issuer
*/
X509_DN X509_Certificate::issuer_dn() const
   {
   return create_dn(issuer);
   }

/*
* Return the distinguished name of the subject
*/
X509_DN X509_Certificate::subject_dn() const
   {
   return create_dn(subject);
   }

/*
* Compare two certificates for equality
*/
bool X509_Certificate::operator==(const X509_Certificate& other) const
   {
   return (sig == other.sig &&
           sig_algo == other.sig_algo &&
           self_signed == other.self_signed &&
           issuer == other.issuer &&
           subject == other.subject);
   }

/*
* X.509 Certificate Comparison
*/
bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2)
   {
   return !(cert1 == cert2);
   }

std::string X509_Certificate::to_string() const
   {
   const char* dn_fields[] = { "Name",
                               "Email",
                               "Organization",
                               "Organizational Unit",
                               "Locality",
                               "State",
                               "Country",
                               "IP",
                               "DNS",
                               "URI",
                               "PKIX.XMPPAddr",
                               0 };

   std::ostringstream out;

   for(size_t i = 0; dn_fields[i]; ++i)
      {
      const std::vector<std::string> vals = this->subject_info(dn_fields[i]);

      if(vals.empty())
         continue;

      out << "Subject " << dn_fields[i] << ":";
      for(size_t j = 0; j != vals.size(); ++j)
         out << " " << vals[j];
      out << "\n";
      }

   for(size_t i = 0; dn_fields[i]; ++i)
      {
      const std::vector<std::string> vals = this->issuer_info(dn_fields[i]);

      if(vals.empty())
         continue;

      out << "Issuer " << dn_fields[i] << ":";
      for(size_t j = 0; j != vals.size(); ++j)
         out << " " << vals[j];
      out << "\n";
      }

   out << "Version: " << this->x509_version() << "\n";

   out << "Not valid before: " << this->start_time() << "\n";
   out << "Not valid after: " << this->end_time() << "\n";

   out << "Constraints:\n";
   Key_Constraints constraints = this->constraints();
   if(constraints == NO_CONSTRAINTS)
      out << " None\n";
   else
      {
      if(constraints & DIGITAL_SIGNATURE)
         out << "   Digital Signature\n";
      if(constraints & NON_REPUDIATION)
         out << "   Non-Repuidation\n";
      if(constraints & KEY_ENCIPHERMENT)
         out << "   Key Encipherment\n";
      if(constraints & DATA_ENCIPHERMENT)
         out << "   Data Encipherment\n";
      if(constraints & KEY_AGREEMENT)
         out << "   Key Agreement\n";
      if(constraints & KEY_CERT_SIGN)
         out << "   Cert Sign\n";
      if(constraints & CRL_SIGN)
         out << "   CRL Sign\n";
      }

   std::vector<std::string> policies = this->policies();
   if(policies.size())
      {
      out << "Policies: " << "\n";
      for(size_t i = 0; i != policies.size(); i++)
         out << "   " << policies[i] << "\n";
      }

   std::vector<std::string> ex_constraints = this->ex_constraints();
   if(ex_constraints.size())
      {
      out << "Extended Constraints:\n";
      for(size_t i = 0; i != ex_constraints.size(); i++)
         out << "   " << ex_constraints[i] << "\n";
      }

   out << "Signature algorithm: " <<
      OIDS::lookup(this->signature_algorithm().oid) << "\n";

   out << "Serial number: " << hex_encode(this->serial_number()) << "\n";

   if(this->authority_key_id().size())
     out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n";

   if(this->subject_key_id().size())
     out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n";

   X509_PublicKey* pubkey = this->subject_public_key();
   out << "Public Key:\n" << X509::PEM_encode(*pubkey);
   delete pubkey;

   return out.str();
   }

/*
* Create and populate a X509_DN
*/
X509_DN create_dn(const Data_Store& info)
   {
   class DN_Matcher : public Data_Store::Matcher
      {
      public:
         bool operator()(const std::string& key, const std::string&) const
            {
            if(key.find("X520.") != std::string::npos)
               return true;
            return false;
            }
      };

   std::multimap<std::string, std::string> names =
      info.search_with(DN_Matcher());

   X509_DN dn;

   std::multimap<std::string, std::string>::iterator i;
   for(i = names.begin(); i != names.end(); ++i)
      dn.add_attribute(i->first, i->second);

   return dn;
   }

/*
* Create and populate an AlternativeName
*/
AlternativeName create_alt_name(const Data_Store& info)
   {
   class AltName_Matcher : public Data_Store::Matcher
      {
      public:
         bool operator()(const std::string& key, const std::string&) const
            {
            for(size_t i = 0; i != matches.size(); ++i)
               if(key.compare(matches[i]) == 0)
                  return true;
            return false;
            }

         AltName_Matcher(const std::string& match_any_of)
            {
            matches = split_on(match_any_of, '/');
            }
      private:
         std::vector<std::string> matches;
      };

   std::multimap<std::string, std::string> names =
      info.search_with(AltName_Matcher("RFC822/DNS/URI/IP"));

   AlternativeName alt_name;

   std::multimap<std::string, std::string>::iterator i;
   for(i = names.begin(); i != names.end(); ++i)
      alt_name.add_attribute(i->first, i->second);

   return alt_name;
   }

}
/*
* CRL Entry
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create a CRL_Entry
*/
CRL_Entry::CRL_Entry(bool t_on_unknown_crit) :
   throw_on_unknown_critical(t_on_unknown_crit)
   {
   reason = UNSPECIFIED;
   }

/*
* Create a CRL_Entry
*/
CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) :
   throw_on_unknown_critical(false)
   {
   serial = cert.serial_number();
   time = X509_Time(system_time());
   reason = why;
   }

/*
* Compare two CRL_Entrys for equality
*/
bool operator==(const CRL_Entry& a1, const CRL_Entry& a2)
   {
   if(a1.serial_number() != a2.serial_number())
      return false;
   if(a1.expire_time() != a2.expire_time())
      return false;
   if(a1.reason_code() != a2.reason_code())
      return false;
   return true;
   }

/*
* Compare two CRL_Entrys for inequality
*/
bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2)
   {
   return !(a1 == a2);
   }

/*
* DER encode a CRL_Entry
*/
void CRL_Entry::encode_into(DER_Encoder& der) const
   {
   Extensions extensions;

   extensions.add(new Cert_Extension::CRL_ReasonCode(reason));

   der.start_cons(SEQUENCE)
      .encode(BigInt::decode(serial))
         .encode(time)
         .start_cons(SEQUENCE)
            .encode(extensions)
          .end_cons()
      .end_cons();
   }

/*
* Decode a BER encoded CRL_Entry
*/
void CRL_Entry::decode_from(BER_Decoder& source)
   {
   BigInt serial_number_bn;
   reason = UNSPECIFIED;

   BER_Decoder entry = source.start_cons(SEQUENCE);

   entry.decode(serial_number_bn).decode(time);

   if(entry.more_items())
      {
      Extensions extensions(throw_on_unknown_critical);
      entry.decode(extensions);
      Data_Store info;
      extensions.contents_to(info, info);
      reason = CRL_Code(info.get1_u32bit("X509v3.CRLReasonCode"));
      }

   entry.end_cons();

   serial = BigInt::encode(serial_number_bn);
   }

}
/*
* X.509 CRL
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Load a X.509 CRL
*/
X509_CRL::X509_CRL(DataSource& in, bool touc) :
   X509_Object(in, "X509 CRL/CRL"), throw_on_unknown_critical(touc)
   {
   do_decode();
   }

/*
* Load a X.509 CRL
*/
X509_CRL::X509_CRL(const std::string& in, bool touc) :
   X509_Object(in, "CRL/X509 CRL"), throw_on_unknown_critical(touc)
   {
   do_decode();
   }

/*
* Decode the TBSCertList data
*/
void X509_CRL::force_decode()
   {
   BER_Decoder tbs_crl(tbs_bits);

   size_t version;
   tbs_crl.decode_optional(version, INTEGER, UNIVERSAL);

   if(version != 0 && version != 1)
      throw X509_CRL_Error("Unknown X.509 CRL version " +
                           to_string(version+1));

   AlgorithmIdentifier sig_algo_inner;
   tbs_crl.decode(sig_algo_inner);

   if(sig_algo != sig_algo_inner)
      throw X509_CRL_Error("Algorithm identifier mismatch");

   X509_DN dn_issuer;
   tbs_crl.decode(dn_issuer);
   info.add(dn_issuer.contents());

   X509_Time start, end;
   tbs_crl.decode(start).decode(end);
   info.add("X509.CRL.start", start.readable_string());
   info.add("X509.CRL.end", end.readable_string());

   BER_Object next = tbs_crl.get_next_object();

   if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED)
      {
      BER_Decoder cert_list(next.value);

      while(cert_list.more_items())
         {
         CRL_Entry entry(throw_on_unknown_critical);
         cert_list.decode(entry);
         revoked.push_back(entry);
         }
      next = tbs_crl.get_next_object();
      }

   if(next.type_tag == 0 &&
      next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
      {
      BER_Decoder crl_options(next.value);

      Extensions extensions(throw_on_unknown_critical);

      crl_options.decode(extensions).verify_end();

      extensions.contents_to(info, info);

      next = tbs_crl.get_next_object();
      }

   if(next.type_tag != NO_OBJECT)
      throw X509_CRL_Error("Unknown tag in CRL");

   tbs_crl.verify_end();
   }

/*
* Return the list of revoked certificates
*/
std::vector<CRL_Entry> X509_CRL::get_revoked() const
   {
   return revoked;
   }

/*
* Return the distinguished name of the issuer
*/
X509_DN X509_CRL::issuer_dn() const
   {
   return create_dn(info);
   }

/*
* Return the key identifier of the issuer
*/
MemoryVector<byte> X509_CRL::authority_key_id() const
   {
   return info.get1_memvec("X509v3.AuthorityKeyIdentifier");
   }

/*
* Return the CRL number of this CRL
*/
u32bit X509_CRL::crl_number() const
   {
   return info.get1_u32bit("X509v3.CRLNumber");
   }

/*
* Return the issue data of the CRL
*/
X509_Time X509_CRL::this_update() const
   {
   return info.get1("X509.CRL.start");
   }

/*
* Return the date when a new CRL will be issued
*/
X509_Time X509_CRL::next_update() const
   {
   return info.get1("X509.CRL.end");
   }

}
/*
* X.509 Certificate Options
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Set when the certificate should become valid
*/
void X509_Cert_Options::not_before(const std::string& time_string)
   {
   start = X509_Time(time_string);
   }

/*
* Set when the certificate should expire
*/
void X509_Cert_Options::not_after(const std::string& time_string)
   {
   end = X509_Time(time_string);
   }

/*
* Set key constraint information
*/
void X509_Cert_Options::add_constraints(Key_Constraints usage)
   {
   constraints = usage;
   }

/*
* Set key constraint information
*/
void X509_Cert_Options::add_ex_constraint(const OID& oid)
   {
   ex_constraints.push_back(oid);
   }

/*
* Set key constraint information
*/
void X509_Cert_Options::add_ex_constraint(const std::string& oid_str)
   {
   ex_constraints.push_back(OIDS::lookup(oid_str));
   }

/*
* Mark this certificate for CA usage
*/
void X509_Cert_Options::CA_key(size_t limit)
   {
   is_CA = true;
   path_limit = limit;
   }

/*
* Do basic sanity checks
*/
void X509_Cert_Options::sanity_check() const
   {
   if(common_name == "" || country == "")
      throw Encoding_Error("X.509 certificate: name and country MUST be set");
   if(country.size() != 2)
      throw Encoding_Error("Invalid ISO country code: " + country);
   if(start >= end)
      throw Encoding_Error("X509_Cert_Options: invalid time constraints");
   }

/*
* Initialize the certificate options
*/
X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts,
                                     u32bit expiration_time_in_seconds)
   {
   is_CA = false;
   path_limit = 0;
   constraints = NO_CONSTRAINTS;

   const u64bit now = system_time();

   start = X509_Time(now);
   end = X509_Time(now + expiration_time_in_seconds);

   if(initial_opts == "")
      return;

   std::vector<std::string> parsed = split_on(initial_opts, '/');

   if(parsed.size() > 4)
      throw Invalid_Argument("X.509 cert options: Too many names: "
                             + initial_opts);

   if(parsed.size() >= 1) common_name  = parsed[0];
   if(parsed.size() >= 2) country      = parsed[1];
   if(parsed.size() >= 3) organization = parsed[2];
   if(parsed.size() == 4) org_unit     = parsed[3];
   }

}
/*
* PKCS #10/Self Signed Cert Creation
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

/*
* Load information from the X509_Cert_Options
*/
void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn,
               AlternativeName& subject_alt)
   {
   subject_dn.add_attribute("X520.CommonName", opts.common_name);
   subject_dn.add_attribute("X520.Country", opts.country);
   subject_dn.add_attribute("X520.State", opts.state);
   subject_dn.add_attribute("X520.Locality", opts.locality);
   subject_dn.add_attribute("X520.Organization", opts.organization);
   subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit);
   subject_dn.add_attribute("X520.SerialNumber", opts.serial_number);
   subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip);
   subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"),
                             opts.xmpp, UTF8_STRING);
   }

}

namespace X509 {

/*
* Create a new self-signed X.509 certificate
*/
X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
                                         const Private_Key& key,
                                         const std::string& hash_fn,
                                         RandomNumberGenerator& rng)
   {
   AlgorithmIdentifier sig_algo;
   X509_DN subject_dn;
   AlternativeName subject_alt;

   opts.sanity_check();

   MemoryVector<byte> pub_key = X509::BER_encode(key);
   std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
   load_info(opts, subject_dn, subject_alt);

   Key_Constraints constraints;
   if(opts.is_CA)
      constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
   else
      constraints = find_constraints(key, opts.constraints);

   Extensions extensions;

   extensions.add(
      new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit),
      true);

   extensions.add(new Cert_Extension::Key_Usage(constraints), true);

   extensions.add(new Cert_Extension::Subject_Key_ID(pub_key));

   extensions.add(
      new Cert_Extension::Subject_Alternative_Name(subject_alt));

   extensions.add(
      new Cert_Extension::Extended_Key_Usage(opts.ex_constraints));

   return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key,
                             opts.start, opts.end,
                             subject_dn, subject_dn,
                             extensions);
   }

/*
* Create a PKCS #10 certificate request
*/
PKCS10_Request create_cert_req(const X509_Cert_Options& opts,
                               const Private_Key& key,
                               const std::string& hash_fn,
                               RandomNumberGenerator& rng)
   {
   AlgorithmIdentifier sig_algo;
   X509_DN subject_dn;
   AlternativeName subject_alt;

   opts.sanity_check();

   MemoryVector<byte> pub_key = X509::BER_encode(key);
   std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
   load_info(opts, subject_dn, subject_alt);

   const size_t PKCS10_VERSION = 0;

   Extensions extensions;

   extensions.add(
      new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit));
   extensions.add(
      new Cert_Extension::Key_Usage(
         opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) :
                      find_constraints(key, opts.constraints)
         )
      );
   extensions.add(
      new Cert_Extension::Extended_Key_Usage(opts.ex_constraints));
   extensions.add(
      new Cert_Extension::Subject_Alternative_Name(subject_alt));

   DER_Encoder tbs_req;

   tbs_req.start_cons(SEQUENCE)
      .encode(PKCS10_VERSION)
      .encode(subject_dn)
      .raw_bytes(pub_key)
      .start_explicit(0);

   if(opts.challenge != "")
      {
      ASN1_String challenge(opts.challenge, DIRECTORY_STRING);

      tbs_req.encode(
         Attribute("PKCS9.ChallengePassword",
                   DER_Encoder().encode(challenge).get_contents()
            )
         );
      }

   tbs_req.encode(
      Attribute("PKCS9.ExtensionRequest",
                DER_Encoder()
                   .start_cons(SEQUENCE)
                      .encode(extensions)
                   .end_cons()
               .get_contents()
         )
      )
      .end_explicit()
      .end_cons();

   DataSource_Memory source(
      X509_Object::make_signed(signer.get(),
                               rng,
                               sig_algo,
                               tbs_req.get_contents())
      );

   return PKCS10_Request(source);
   }

}

}
/*
* X.509 Certificate Store
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

namespace {

/*
* Do a validity check
*/
s32bit validity_check(const X509_Time& start, const X509_Time& end,
                      u64bit current_time, u32bit slack)
   {
   const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1;

   if(start.cmp(current_time + slack) > 0)
      return NOT_YET_VALID;
   if(end.cmp(current_time - slack) < 0)
      return EXPIRED;
   return VALID_TIME;
   }

/*
* Compare the value of unique ID fields
*/
bool compare_ids(const MemoryVector<byte>& id1,
                 const MemoryVector<byte>& id2)
   {
   if(!id1.size() || !id2.size())
      return true;
   return (id1 == id2);
   }

/*
* Check a particular usage restriction
*/
bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage,
                 X509_Store::Cert_Usage check_for, Key_Constraints constraints)
   {
   if((usage & check_for) == 0)
      return true;
   if(cert.constraints() == NO_CONSTRAINTS)
      return true;
   if(cert.constraints() & constraints)
      return true;
   return false;
   }

/*
* Check a particular usage restriction
*/
bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage,
                 X509_Store::Cert_Usage check_for,
                 const std::string& usage_oid)
   {
   if((usage & check_for) == 0)
      return true;

   const std::vector<std::string> constraints = cert.ex_constraints();

   if(constraints.empty())
      return true;

   return std::binary_search(constraints.begin(), constraints.end(),
                             usage_oid);
   }

/*
* Check the usage restrictions
*/
X509_Code usage_check(const X509_Certificate& cert,
                      X509_Store::Cert_Usage usage)
   {
   if(usage == X509_Store::ANY)
      return VERIFIED;

   if(!check_usage(cert, usage, X509_Store::CRL_SIGNING, CRL_SIGN))
      return CA_CERT_NOT_FOR_CRL_ISSUER;

   if(!check_usage(cert, usage, X509_Store::TLS_SERVER, "PKIX.ServerAuth"))
      return INVALID_USAGE;
   if(!check_usage(cert, usage, X509_Store::TLS_CLIENT, "PKIX.ClientAuth"))
      return INVALID_USAGE;
   if(!check_usage(cert, usage, X509_Store::CODE_SIGNING, "PKIX.CodeSigning"))
      return INVALID_USAGE;
   if(!check_usage(cert, usage, X509_Store::EMAIL_PROTECTION,
                   "PKIX.EmailProtection"))
      return INVALID_USAGE;
   if(!check_usage(cert, usage, X509_Store::TIME_STAMPING,
                   "PKIX.TimeStamping"))
      return INVALID_USAGE;

   return VERIFIED;
   }

}

/*
* Define equality for revocation data
*/
bool X509_Store::CRL_Data::operator==(const CRL_Data& other) const
   {
   if(issuer != other.issuer)
      return false;
   if(serial != other.serial)
      return false;
   return compare_ids(auth_key_id, other.auth_key_id);
   }

/*
* Define inequality for revocation data
*/
bool X509_Store::CRL_Data::operator!=(const CRL_Data& other) const
   {
   return !((*this) == other);
   }

/*
* Define an ordering for revocation data
*/
bool X509_Store::CRL_Data::operator<(const X509_Store::CRL_Data& other) const
   {
   if(*this == other)
      return false;

   const MemoryVector<byte>& serial1 = serial;
   const MemoryVector<byte>& key_id1 = auth_key_id;
   const MemoryVector<byte>& serial2 = other.serial;
   const MemoryVector<byte>& key_id2 = other.auth_key_id;

   if(compare_ids(key_id1, key_id2) == false)
      {
      if(std::lexicographical_compare(key_id1.begin(), key_id1.end(),
                                      key_id2.begin(), key_id2.end()))
         return true;

      if(std::lexicographical_compare(key_id2.begin(), key_id2.end(),
                                      key_id1.begin(), key_id1.end()))
         return false;
      }

   if(compare_ids(serial1, serial2) == false)
      {
      if(std::lexicographical_compare(serial1.begin(), serial1.end(),
                                      serial2.begin(), serial2.end()))
         return true;

      if(std::lexicographical_compare(serial2.begin(), serial2.end(),
                                      serial1.begin(), serial1.end()))
         return false;
      }

   return (issuer < other.issuer);
   }

/*
* X509_Store Constructor
*/
X509_Store::X509_Store(u32bit slack, u32bit cache_timeout)
   {
   revoked_info_valid = true;

   validation_cache_timeout = cache_timeout;
   time_slack = slack;
   }

/*
* X509_Store Copy Constructor
*/
X509_Store::X509_Store(const X509_Store& other)
   {
   certs = other.certs;
   revoked = other.revoked;
   revoked_info_valid = other.revoked_info_valid;
   for(size_t j = 0; j != other.stores.size(); ++j)
      stores[j] = other.stores[j]->clone();
   time_slack = other.time_slack;
   }

/*
* X509_Store Destructor
*/
X509_Store::~X509_Store()
   {
   for(size_t j = 0; j != stores.size(); ++j)
      delete stores[j];
   }

/*
* Verify a certificate's authenticity
*/
X509_Code X509_Store::validate_cert(const X509_Certificate& cert,
                                    Cert_Usage cert_usage)
   {
   recompute_revoked_info();

   std::vector<size_t> indexes;
   X509_Code chaining_result = construct_cert_chain(cert, indexes);
   if(chaining_result != VERIFIED)
      return chaining_result;

   const u64bit current_time = system_time();

   s32bit time_check = validity_check(cert.start_time(), cert.end_time(),
                                      current_time, time_slack);
   if(time_check < 0)      return CERT_NOT_YET_VALID;
   else if(time_check > 0) return CERT_HAS_EXPIRED;

   X509_Code sig_check_result = check_sig(cert, certs[indexes[0]]);
   if(sig_check_result != VERIFIED)
      return sig_check_result;

   if(is_revoked(cert))
      return CERT_IS_REVOKED;

   for(size_t j = 0; j != indexes.size() - 1; ++j)
      {
      const X509_Certificate& current_cert = certs[indexes[j]].cert;

      time_check = validity_check(current_cert.start_time(),
                                  current_cert.end_time(),
                                  current_time,
                                  time_slack);

      if(time_check < 0)      return CERT_NOT_YET_VALID;
      else if(time_check > 0) return CERT_HAS_EXPIRED;

      sig_check_result = check_sig(certs[indexes[j]], certs[indexes[j+1]]);
      if(sig_check_result != VERIFIED)
         return sig_check_result;
      }

   return usage_check(cert, cert_usage);
   }

/*
* Find this certificate
*/
size_t X509_Store::find_cert(const X509_DN& subject_dn,
                             const MemoryRegion<byte>& subject_key_id) const
   {
   for(size_t j = 0; j != certs.size(); ++j)
      {
      const X509_Certificate& this_cert = certs[j].cert;
      if(compare_ids(this_cert.subject_key_id(), subject_key_id) &&
         this_cert.subject_dn() == subject_dn)
         return j;
      }
   return NO_CERT_FOUND;
   }

/*
* Find the parent of this certificate
*/
size_t X509_Store::find_parent_of(const X509_Certificate& cert)
   {
   const X509_DN issuer_dn = cert.issuer_dn();
   const MemoryVector<byte> auth_key_id = cert.authority_key_id();

   size_t index = find_cert(issuer_dn, auth_key_id);

   if(index != NO_CERT_FOUND)
      return index;

   for(size_t j = 0; j != stores.size(); ++j)
      {
      std::vector<X509_Certificate> got =
         stores[j]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id);

      for(size_t k = 0; k != got.size(); ++k)
         add_cert(got[k]);
      }

   return find_cert(issuer_dn, auth_key_id);
   }

/*
* Construct a chain of certificate relationships
*/
X509_Code X509_Store::construct_cert_chain(const X509_Certificate& end_cert,
                                           std::vector<size_t>& indexes,
                                           bool need_full_chain)
   {
   size_t parent = find_parent_of(end_cert);

   while(true)
      {
      if(parent == NO_CERT_FOUND)
         return CERT_ISSUER_NOT_FOUND;
      indexes.push_back(parent);

      if(certs[parent].is_verified(validation_cache_timeout))
         if(certs[parent].verify_result() != VERIFIED)
            return certs[parent].verify_result();

      const X509_Certificate& parent_cert = certs[parent].cert;
      if(!parent_cert.is_CA_cert())
         return CA_CERT_NOT_FOR_CERT_ISSUER;

      if(certs[parent].is_trusted())
         break;
      if(parent_cert.is_self_signed())
         return CANNOT_ESTABLISH_TRUST;

      if(parent_cert.path_limit() < indexes.size() - 1)
         return CERT_CHAIN_TOO_LONG;

      parent = find_parent_of(parent_cert);
      }

   if(need_full_chain)
      return VERIFIED;

   while(true)
      {
      if(indexes.size() < 2)
         break;

      const size_t cert = indexes.back();

      if(certs[cert].is_verified(validation_cache_timeout))
         {
         if(certs[cert].verify_result() != VERIFIED)
            throw Internal_Error("X509_Store::construct_cert_chain");
         indexes.pop_back();
         }
      else
         break;
      }

   const size_t last_cert = indexes.back();
   const size_t parent_of_last_cert = find_parent_of(certs[last_cert].cert);
   if(parent_of_last_cert == NO_CERT_FOUND)
      return CERT_ISSUER_NOT_FOUND;
   indexes.push_back(parent_of_last_cert);

   return VERIFIED;
   }

/*
* Check the CAs signature on a certificate
*/
X509_Code X509_Store::check_sig(const Cert_Info& cert_info,
                                const Cert_Info& ca_cert_info) const
   {
   if(cert_info.is_verified(validation_cache_timeout))
      return cert_info.verify_result();

   const X509_Certificate& cert    = cert_info.cert;
   const X509_Certificate& ca_cert = ca_cert_info.cert;

   X509_Code verify_code = check_sig(cert, ca_cert.subject_public_key());

   cert_info.set_result(verify_code);

   return verify_code;
   }

/*
* Check a CA's signature
*/
X509_Code X509_Store::check_sig(const X509_Object& object, Public_Key* key)
   {
   std::auto_ptr<Public_Key> pub_key(key);

   try {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(object.signature_algorithm().oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
         return SIGNATURE_ERROR;

      std::string padding = sig_info[1];
      Signature_Format format;
      if(key->message_parts() >= 2) format = DER_SEQUENCE;
      else                          format = IEEE_1363;

      PK_Verifier verifier(*pub_key.get(), padding, format);

      bool valid = verifier.verify_message(object.tbs_data(),
                                           object.signature());

      if(valid)
         return VERIFIED;
      else
         return SIGNATURE_ERROR;
      }
   catch(Lookup_Error)   { return CA_CERT_CANNOT_SIGN; }
   catch(Decoding_Error) { return CERT_FORMAT_ERROR; }
   catch(Exception)      {}

   return UNKNOWN_X509_ERROR;
   }

/*
* Recompute the revocation status of the certs
*/
void X509_Store::recompute_revoked_info() const
   {
   if(revoked_info_valid)
      return;

   for(size_t j = 0; j != certs.size(); ++j)
      {
      if((certs[j].is_verified(validation_cache_timeout)) &&
         (certs[j].verify_result() != VERIFIED))
         continue;

      if(is_revoked(certs[j].cert))
         certs[j].set_result(CERT_IS_REVOKED);
      }

   revoked_info_valid = true;
   }

/*
* Check if a certificate is revoked
*/
bool X509_Store::is_revoked(const X509_Certificate& cert) const
   {
   CRL_Data revoked_info;
   revoked_info.issuer = cert.issuer_dn();
   revoked_info.serial = cert.serial_number();
   revoked_info.auth_key_id = cert.authority_key_id();

   if(std::binary_search(revoked.begin(), revoked.end(), revoked_info))
      return true;
   return false;
   }

/*
* Construct a path back to a root for this cert
*/
std::vector<X509_Certificate>
X509_Store::get_cert_chain(const X509_Certificate& cert)
   {
   std::vector<X509_Certificate> result;
   std::vector<size_t> indexes;
   X509_Code chaining_result = construct_cert_chain(cert, indexes, true);

   if(chaining_result != VERIFIED)
      throw Invalid_State("X509_Store::get_cert_chain: Can't construct chain");

   for(size_t j = 0; j != indexes.size(); ++j)
      result.push_back(certs[indexes[j]].cert);
   return result;
   }

/*
* Add a certificate store to the list of stores
*/
void X509_Store::add_new_certstore(Certificate_Store* certstore)
   {
   stores.push_back(certstore);
   }

/*
* Add a certificate to the store
*/
void X509_Store::add_cert(const X509_Certificate& cert, bool trusted)
   {
   if(trusted && !cert.is_self_signed())
      throw Invalid_Argument("X509_Store: Trusted certs must be self-signed");

   if(find_cert(cert.subject_dn(), cert.subject_key_id()) == NO_CERT_FOUND)
      {
      revoked_info_valid = false;
      Cert_Info info(cert, trusted);
      certs.push_back(info);
      }
   else if(trusted)
      {
      for(size_t j = 0; j != certs.size(); ++j)
         {
         const X509_Certificate& this_cert = certs[j].cert;
         if(this_cert == cert)
            certs[j].trusted = trusted;
         }
      }
   }

/*
* Add one or more certificates to the store
*/
void X509_Store::do_add_certs(DataSource& source, bool trusted)
   {
   while(!source.end_of_data())
      {
      try {
         X509_Certificate cert(source);
         add_cert(cert, trusted);
         }
      catch(Decoding_Error) {}
      catch(Invalid_Argument) {}
      }
   }

/*
* Add one or more certificates to the store
*/
void X509_Store::add_certs(DataSource& source)
   {
   do_add_certs(source, false);
   }

/*
* Add one or more certificates to the store
*/
void X509_Store::add_trusted_certs(DataSource& source)
   {
   do_add_certs(source, true);
   }

/*
* Add one or more certificates to the store
*/
X509_Code X509_Store::add_crl(const X509_CRL& crl)
   {
   s32bit time_check = validity_check(crl.this_update(), crl.next_update(),
                                      system_time(), time_slack);

   if(time_check < 0)      return CRL_NOT_YET_VALID;
   else if(time_check > 0) return CRL_HAS_EXPIRED;

   size_t cert_index = NO_CERT_FOUND;

   for(size_t j = 0; j != certs.size(); ++j)
      {
      const X509_Certificate& this_cert = certs[j].cert;
      if(compare_ids(this_cert.subject_key_id(), crl.authority_key_id()))
         {
         if(this_cert.subject_dn() == crl.issuer_dn())
            cert_index = j;
         }
      }

   if(cert_index == NO_CERT_FOUND)
      return CRL_ISSUER_NOT_FOUND;

   const X509_Certificate& ca_cert = certs[cert_index].cert;

   X509_Code verify_result = validate_cert(ca_cert, CRL_SIGNING);
   if(verify_result != VERIFIED)
      return verify_result;

   verify_result = check_sig(crl, ca_cert.subject_public_key());
   if(verify_result != VERIFIED)
      return verify_result;

   std::vector<CRL_Entry> revoked_certs = crl.get_revoked();

   for(size_t j = 0; j != revoked_certs.size(); ++j)
      {
      CRL_Data revoked_info;
      revoked_info.issuer = crl.issuer_dn();
      revoked_info.serial = revoked_certs[j].serial_number();
      revoked_info.auth_key_id = crl.authority_key_id();

      std::vector<CRL_Data>::iterator p =
         std::find(revoked.begin(), revoked.end(), revoked_info);

      if(revoked_certs[j].reason_code() == REMOVE_FROM_CRL)
         {
         if(p == revoked.end()) continue;
         revoked.erase(p);
         }
      else
         {
         if(p != revoked.end()) continue;
         revoked.push_back(revoked_info);
         }
      }

   std::sort(revoked.begin(), revoked.end());
   revoked_info_valid = false;

   return VERIFIED;
   }

/*
* PEM encode the set of certificates
*/
std::string X509_Store::PEM_encode() const
   {
   std::string cert_store;
   for(size_t j = 0; j != certs.size(); ++j)
      cert_store += certs[j].cert.PEM_encode();
   return cert_store;
   }

/*
* Create a Cert_Info structure
*/
X509_Store::Cert_Info::Cert_Info(const X509_Certificate& c,
                                 bool t) : cert(c), trusted(t)
   {
   checked = false;
   result = UNKNOWN_X509_ERROR;
   last_checked = 0;
   }

/*
* Return the verification results
*/
X509_Code X509_Store::Cert_Info::verify_result() const
   {
   if(!checked)
      throw Invalid_State("Cert_Info::verify_result() called; not checked");
   return result;
   }

/*
* Set the verification results
*/
void X509_Store::Cert_Info::set_result(X509_Code code) const
   {
   result = code;
   last_checked = system_time();
   checked = true;
   }

/*
* Check if this certificate can be trusted
*/
bool X509_Store::Cert_Info::is_trusted() const
   {
   return trusted;
   }

/*
* Check if this certificate has been verified
*/
bool X509_Store::Cert_Info::is_verified(u32bit timeout) const
   {
   if(!checked)
      return false;
   if(result != VERIFIED && result != CERT_NOT_YET_VALID)
      return true;

   const u64bit current_time = system_time();

   if(current_time > last_checked + timeout)
      checked = false;

   return checked;
   }

}
/*
* Adler32
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

void adler32_update(const byte input[], size_t length,
                    u16bit& S1, u16bit& S2)
   {
   u32bit S1x = S1;
   u32bit S2x = S2;

   while(length >= 16)
      {
      S1x += input[ 0]; S2x += S1x;
      S1x += input[ 1]; S2x += S1x;
      S1x += input[ 2]; S2x += S1x;
      S1x += input[ 3]; S2x += S1x;
      S1x += input[ 4]; S2x += S1x;
      S1x += input[ 5]; S2x += S1x;
      S1x += input[ 6]; S2x += S1x;
      S1x += input[ 7]; S2x += S1x;
      S1x += input[ 8]; S2x += S1x;
      S1x += input[ 9]; S2x += S1x;
      S1x += input[10]; S2x += S1x;
      S1x += input[11]; S2x += S1x;
      S1x += input[12]; S2x += S1x;
      S1x += input[13]; S2x += S1x;
      S1x += input[14]; S2x += S1x;
      S1x += input[15]; S2x += S1x;
      input += 16;
      length -= 16;
      }

   for(size_t j = 0; j != length; ++j)
      {
      S1x += input[j];
      S2x += S1x;
      }

   S1 = S1x % 65521;
   S2 = S2x % 65521;
   }

}

/*
* Update an Adler32 Checksum
*/
void Adler32::add_data(const byte input[], size_t length)
   {
   const size_t PROCESS_AMOUNT = 5552;

   while(length >= PROCESS_AMOUNT)
      {
      adler32_update(input, PROCESS_AMOUNT, S1, S2);
      input += PROCESS_AMOUNT;
      length -= PROCESS_AMOUNT;
      }

   adler32_update(input, length, S1, S2);
   }

/*
* Finalize an Adler32 Checksum
*/
void Adler32::final_result(byte output[])
   {
   store_be(output, S2, S1);
   clear();
   }

}
/*
* CRC24
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Update a CRC24 Checksum
*/
void CRC24::add_data(const byte input[], size_t length)
   {
   const u32bit TABLE[256] = {
      0x00000000, 0x00864CFB, 0x008AD50D, 0x000C99F6, 0x0093E6E1, 0x0015AA1A,
      0x001933EC, 0x009F7F17, 0x00A18139, 0x0027CDC2, 0x002B5434, 0x00AD18CF,
      0x003267D8, 0x00B42B23, 0x00B8B2D5, 0x003EFE2E, 0x00C54E89, 0x00430272,
      0x004F9B84, 0x00C9D77F, 0x0056A868, 0x00D0E493, 0x00DC7D65, 0x005A319E,
      0x0064CFB0, 0x00E2834B, 0x00EE1ABD, 0x00685646, 0x00F72951, 0x007165AA,
      0x007DFC5C, 0x00FBB0A7, 0x000CD1E9, 0x008A9D12, 0x008604E4, 0x0000481F,
      0x009F3708, 0x00197BF3, 0x0015E205, 0x0093AEFE, 0x00AD50D0, 0x002B1C2B,
      0x002785DD, 0x00A1C926, 0x003EB631, 0x00B8FACA, 0x00B4633C, 0x00322FC7,
      0x00C99F60, 0x004FD39B, 0x00434A6D, 0x00C50696, 0x005A7981, 0x00DC357A,
      0x00D0AC8C, 0x0056E077, 0x00681E59, 0x00EE52A2, 0x00E2CB54, 0x006487AF,
      0x00FBF8B8, 0x007DB443, 0x00712DB5, 0x00F7614E, 0x0019A3D2, 0x009FEF29,
      0x009376DF, 0x00153A24, 0x008A4533, 0x000C09C8, 0x0000903E, 0x0086DCC5,
      0x00B822EB, 0x003E6E10, 0x0032F7E6, 0x00B4BB1D, 0x002BC40A, 0x00AD88F1,
      0x00A11107, 0x00275DFC, 0x00DCED5B, 0x005AA1A0, 0x00563856, 0x00D074AD,
      0x004F0BBA, 0x00C94741, 0x00C5DEB7, 0x0043924C, 0x007D6C62, 0x00FB2099,
      0x00F7B96F, 0x0071F594, 0x00EE8A83, 0x0068C678, 0x00645F8E, 0x00E21375,
      0x0015723B, 0x00933EC0, 0x009FA736, 0x0019EBCD, 0x008694DA, 0x0000D821,
      0x000C41D7, 0x008A0D2C, 0x00B4F302, 0x0032BFF9, 0x003E260F, 0x00B86AF4,
      0x002715E3, 0x00A15918, 0x00ADC0EE, 0x002B8C15, 0x00D03CB2, 0x00567049,
      0x005AE9BF, 0x00DCA544, 0x0043DA53, 0x00C596A8, 0x00C90F5E, 0x004F43A5,
      0x0071BD8B, 0x00F7F170, 0x00FB6886, 0x007D247D, 0x00E25B6A, 0x00641791,
      0x00688E67, 0x00EEC29C, 0x003347A4, 0x00B50B5F, 0x00B992A9, 0x003FDE52,
      0x00A0A145, 0x0026EDBE, 0x002A7448, 0x00AC38B3, 0x0092C69D, 0x00148A66,
      0x00181390, 0x009E5F6B, 0x0001207C, 0x00876C87, 0x008BF571, 0x000DB98A,
      0x00F6092D, 0x007045D6, 0x007CDC20, 0x00FA90DB, 0x0065EFCC, 0x00E3A337,
      0x00EF3AC1, 0x0069763A, 0x00578814, 0x00D1C4EF, 0x00DD5D19, 0x005B11E2,
      0x00C46EF5, 0x0042220E, 0x004EBBF8, 0x00C8F703, 0x003F964D, 0x00B9DAB6,
      0x00B54340, 0x00330FBB, 0x00AC70AC, 0x002A3C57, 0x0026A5A1, 0x00A0E95A,
      0x009E1774, 0x00185B8F, 0x0014C279, 0x00928E82, 0x000DF195, 0x008BBD6E,
      0x00872498, 0x00016863, 0x00FAD8C4, 0x007C943F, 0x00700DC9, 0x00F64132,
      0x00693E25, 0x00EF72DE, 0x00E3EB28, 0x0065A7D3, 0x005B59FD, 0x00DD1506,
      0x00D18CF0, 0x0057C00B, 0x00C8BF1C, 0x004EF3E7, 0x00426A11, 0x00C426EA,
      0x002AE476, 0x00ACA88D, 0x00A0317B, 0x00267D80, 0x00B90297, 0x003F4E6C,
      0x0033D79A, 0x00B59B61, 0x008B654F, 0x000D29B4, 0x0001B042, 0x0087FCB9,
      0x001883AE, 0x009ECF55, 0x009256A3, 0x00141A58, 0x00EFAAFF, 0x0069E604,
      0x00657FF2, 0x00E33309, 0x007C4C1E, 0x00FA00E5, 0x00F69913, 0x0070D5E8,
      0x004E2BC6, 0x00C8673D, 0x00C4FECB, 0x0042B230, 0x00DDCD27, 0x005B81DC,
      0x0057182A, 0x00D154D1, 0x0026359F, 0x00A07964, 0x00ACE092, 0x002AAC69,
      0x00B5D37E, 0x00339F85, 0x003F0673, 0x00B94A88, 0x0087B4A6, 0x0001F85D,
      0x000D61AB, 0x008B2D50, 0x00145247, 0x00921EBC, 0x009E874A, 0x0018CBB1,
      0x00E37B16, 0x006537ED, 0x0069AE1B, 0x00EFE2E0, 0x00709DF7, 0x00F6D10C,
      0x00FA48FA, 0x007C0401, 0x0042FA2F, 0x00C4B6D4, 0x00C82F22, 0x004E63D9,
      0x00D11CCE, 0x00575035, 0x005BC9C3, 0x00DD8538 };

   u32bit tmp = crc;
   while(length >= 16)
      {
      tmp = TABLE[((tmp >> 16) ^ input[ 0]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 1]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 2]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 3]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 4]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 5]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 6]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 7]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 8]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[ 9]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[10]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[11]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[12]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[13]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[14]) & 0xFF] ^ (tmp << 8);
      tmp = TABLE[((tmp >> 16) ^ input[15]) & 0xFF] ^ (tmp << 8);
      input += 16;
      length -= 16;
      }

   for(size_t i = 0; i != length; ++i)
      tmp = TABLE[((tmp >> 16) ^ input[i]) & 0xFF] ^ (tmp << 8);

   crc = tmp;
   }

/*
* Finalize a CRC24 Checksum
*/
void CRC24::final_result(byte output[])
   {
   for(size_t i = 0; i != 3; ++i)
      output[i] = get_byte(i+1, crc);
   clear();
   }

}
/*
* CRC32
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Update a CRC32 Checksum
*/
void CRC32::add_data(const byte input[], size_t length)
   {
   const u32bit TABLE[256] = {
      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
      0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
      0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
      0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
      0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
      0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
      0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
      0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
      0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
      0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
      0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
      0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
      0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
      0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
      0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
      0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
      0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
      0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
      0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
      0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
      0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
      0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
      0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
      0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
      0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
      0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
      0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
      0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
      0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
      0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
      0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
      0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
      0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };

   u32bit tmp = crc;
   while(length >= 16)
      {
      tmp = TABLE[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8);
      tmp = TABLE[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8);
      input += 16;
      length -= 16;
      }

   for(size_t i = 0; i != length; ++i)
      tmp = TABLE[(tmp ^ input[i]) & 0xFF] ^ (tmp >> 8);

   crc = tmp;
   }

/*
* Finalize a CRC32 Checksum
*/
void CRC32::final_result(byte output[])
   {
   crc ^= 0xFFFFFFFF;
   store_be(crc, output);
   clear();
   }

}
/*
* Base64 Encoding and Decoding
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

namespace {

static const byte BIN_TO_BASE64[64] = {
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};

void do_base64_encode(char out[4], const byte in[3])
   {
   out[0] = BIN_TO_BASE64[((in[0] & 0xFC) >> 2)];
   out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)];
   out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)];
   out[3] = BIN_TO_BASE64[((in[2] & 0x3F)     )];
   }

}

size_t base64_encode(char out[],
                     const byte in[],
                     size_t input_length,
                     size_t& input_consumed,
                     bool final_inputs)
   {
   input_consumed = 0;

   size_t input_remaining = input_length;
   size_t output_produced = 0;

   while(input_remaining >= 3)
      {
      do_base64_encode(out + output_produced, in + input_consumed);

      input_consumed += 3;
      output_produced += 4;
      input_remaining -= 3;
      }

   if(final_inputs && input_remaining)
      {
      byte remainder[3] = { 0 };
      for(size_t i = 0; i != input_remaining; ++i)
         remainder[i] = in[input_consumed + i];

      do_base64_encode(out + output_produced, remainder);

      size_t empty_bits = 8 * (3 - input_remaining);
      size_t index = output_produced + 4 - 1;
      while(empty_bits >= 8)
         {
         out[index--] = '=';
         empty_bits -= 6;
         }

      input_consumed += input_remaining;
      output_produced += 4;
      }

   return output_produced;
   }

std::string base64_encode(const byte input[],
                          size_t input_length)
   {
   std::string output((round_up<size_t>(input_length, 3) / 3) * 4, 0);

   size_t consumed = 0;
   size_t produced = base64_encode(&output[0],
                                   input, input_length,
                                   consumed, true);

   BOTAN_ASSERT_EQUAL(consumed, input_length, "Did not consume all input");
   BOTAN_ASSERT_EQUAL(produced, output.size(), "Did not produce right amount");

   return output;
   }

std::string base64_encode(const MemoryRegion<byte>& input)
   {
   return base64_encode(&input[0], input.size());
   }

size_t base64_decode(byte output[],
                     const char input[],
                     size_t input_length,
                     size_t& input_consumed,
                     bool final_inputs,
                     bool ignore_ws)
   {
   /*
   * Base64 Decoder Lookup Table
   * Warning: assumes ASCII encodings
   */
   static const byte BASE64_TO_BIN[256] = {
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
      0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35,
      0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
      0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04,
      0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
      0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
      0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C,
      0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
      0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
      0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

   byte* out_ptr = output;
   byte decode_buf[4];
   size_t decode_buf_pos = 0;
   size_t final_truncate = 0;

   clear_mem(output, input_length * 3 / 4);

   for(size_t i = 0; i != input_length; ++i)
      {
      const byte bin = BASE64_TO_BIN[static_cast<byte>(input[i])];

      if(bin <= 0x3F)
         {
         decode_buf[decode_buf_pos] = bin;
         decode_buf_pos += 1;
         }
      else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws)))
         {
         std::string bad_char(1, input[i]);
         if(bad_char == "\t")
           bad_char = "\\t";
         else if(bad_char == "\n")
           bad_char = "\\n";
         else if(bad_char == "\r")
           bad_char = "\\r";

         throw std::invalid_argument(
           std::string("base64_decode: invalid base64 character '") +
           bad_char + "'");
         }

      /*
      * If we're at the end of the input, pad with 0s and truncate
      */
      if(final_inputs && (i == input_length - 1))
         {
         if(decode_buf_pos)
            {
            for(size_t i = decode_buf_pos; i != 4; ++i)
               decode_buf[i] = 0;
            final_truncate = (4 - decode_buf_pos);
            decode_buf_pos = 4;
            }
         }

      if(decode_buf_pos == 4)
         {
         out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4);
         out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2);
         out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3];

         out_ptr += 3;
         decode_buf_pos = 0;
         input_consumed = i+1;
         }
      }

   while(input_consumed < input_length &&
         BASE64_TO_BIN[static_cast<byte>(input[input_consumed])] == 0x80)
      {
      ++input_consumed;
      }

   size_t written = (out_ptr - output) - final_truncate;

   return written;
   }

size_t base64_decode(byte output[],
                     const char input[],
                     size_t input_length,
                     bool ignore_ws)
   {
   size_t consumed = 0;
   size_t written = base64_decode(output, input, input_length,
                                  consumed, true, ignore_ws);

   if(consumed != input_length)
      throw std::invalid_argument("base64_decode: input did not have full bytes");

   return written;
   }

size_t base64_decode(byte output[],
                     const std::string& input,
                     bool ignore_ws)
   {
   return base64_decode(output, &input[0], input.length(), ignore_ws);
   }

SecureVector<byte> base64_decode(const char input[],
                                 size_t input_length,
                                 bool ignore_ws)
   {
   SecureVector<byte> bin((round_up<size_t>(input_length, 4) * 3) / 4);

   size_t written = base64_decode(&bin[0],
                                  input,
                                  input_length,
                                  ignore_ws);

   bin.resize(written);
   return bin;
   }

SecureVector<byte> base64_decode(const std::string& input,
                                 bool ignore_ws)
   {
   return base64_decode(&input[0], input.size(), ignore_ws);
   }


}
/*
* Hex Encoding and Decoding
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

void hex_encode(char output[],
                const byte input[],
                size_t input_length,
                bool uppercase)
   {
   static const byte BIN_TO_HEX_UPPER[16] = {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      'A', 'B', 'C', 'D', 'E', 'F' };

   static const byte BIN_TO_HEX_LOWER[16] = {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      'a', 'b', 'c', 'd', 'e', 'f' };

   const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER;

   for(size_t i = 0; i != input_length; ++i)
      {
      byte x = input[i];
      output[2*i  ] = tbl[(x >> 4) & 0x0F];
      output[2*i+1] = tbl[(x     ) & 0x0F];
      }
   }

std::string hex_encode(const MemoryRegion<byte>& input,
                       bool uppercase)
   {
   return hex_encode(&input[0], input.size(), uppercase);
   }

std::string hex_encode(const byte input[],
                       size_t input_length,
                       bool uppercase)
   {
   std::string output(2 * input_length, 0);

   if(input_length)
      hex_encode(&output[0], input, input_length, uppercase);

   return output;
   }

size_t hex_decode(byte output[],
                  const char input[],
                  size_t input_length,
                  size_t& input_consumed,
                  bool ignore_ws)
   {
   /*
   * Mapping of hex characters to either their binary equivalent
   * or to an error code.
   *  If valid hex (0-9 A-F a-f), the value.
   *  If whitespace, then 0x80
   *  Otherwise 0xFF
   * Warning: this table assumes ASCII character encodings
   */

   static const byte HEX_TO_BIN[256] = {
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
      0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
      0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
      0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C,
      0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

   byte* out_ptr = output;
   bool top_nibble = true;

   clear_mem(output, input_length / 2);

   for(size_t i = 0; i != input_length; ++i)
      {
      const byte bin = HEX_TO_BIN[static_cast<byte>(input[i])];

      if(bin >= 0x10)
         {
         if(bin == 0x80 && ignore_ws)
            continue;

         std::string bad_char(1, input[i]);
         if(bad_char == "\t")
           bad_char = "\\t";
         else if(bad_char == "\n")
           bad_char = "\\n";

         throw std::invalid_argument(
           std::string("hex_decode: invalid hex character '") +
           bad_char + "'");
         }

      *out_ptr |= bin << (top_nibble*4);

      top_nibble = !top_nibble;
      if(top_nibble)
         ++out_ptr;
      }

   input_consumed = input_length;
   size_t written = (out_ptr - output);

   /*
   * We only got half of a byte at the end; zap the half-written
   * output and mark it as unread
   */
   if(!top_nibble)
      {
      *out_ptr = 0;
      input_consumed -= 1;
      }

   return written;
   }

size_t hex_decode(byte output[],
                  const char input[],
                  size_t input_length,
                  bool ignore_ws)
   {
   size_t consumed = 0;
   size_t written = hex_decode(output, input, input_length,
                               consumed, ignore_ws);

   if(consumed != input_length)
      throw std::invalid_argument("hex_decode: input did not have full bytes");

   return written;
   }

size_t hex_decode(byte output[],
                  const std::string& input,
                  bool ignore_ws)
   {
   return hex_decode(output, &input[0], input.length(), ignore_ws);
   }

SecureVector<byte> hex_decode(const char input[],
                              size_t input_length,
                              bool ignore_ws)
   {
   SecureVector<byte> bin(1 + input_length / 2);

   size_t written = hex_decode(&bin[0],
                               input,
                               input_length,
                               ignore_ws);

   bin.resize(written);
   return bin;
   }

SecureVector<byte> hex_decode(const std::string& input,
                              bool ignore_ws)
   {
   return hex_decode(&input[0], input.size(), ignore_ws);
   }

}
/*
* OpenPGP Codec
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* OpenPGP Base64 encoding
*/
std::string PGP_encode(
   const byte input[], size_t length,
   const std::string& label,
   const std::map<std::string, std::string>& headers)
   {
   const std::string PGP_HEADER = "-----BEGIN PGP " + label + "-----\n";
   const std::string PGP_TRAILER = "-----END PGP " + label + "-----\n";
   const size_t PGP_WIDTH = 64;

   std::string pgp_encoded = PGP_HEADER;

   if(headers.find("Version") != headers.end())
      pgp_encoded += "Version: " + headers.find("Version")->second + '\n';

   std::map<std::string, std::string>::const_iterator i = headers.begin();
   while(i != headers.end())
      {
      if(i->first != "Version")
         pgp_encoded += i->first + ": " + i->second + '\n';
      ++i;
      }
   pgp_encoded += '\n';

   Pipe pipe(new Fork(
                new Base64_Encoder(true, PGP_WIDTH),
                new Chain(new Hash_Filter(new CRC24), new Base64_Encoder)
                )
      );

   pipe.process_msg(input, length);

   pgp_encoded += pipe.read_all_as_string(0);
   pgp_encoded += '=' + pipe.read_all_as_string(1) + '\n';
   pgp_encoded += PGP_TRAILER;

   return pgp_encoded;
   }

/*
* OpenPGP Base64 encoding
*/
std::string PGP_encode(const byte input[], size_t length,
                       const std::string& type)
   {
   std::map<std::string, std::string> empty;
   return PGP_encode(input, length, type, empty);
   }

/*
* OpenPGP Base64 decoding
*/
SecureVector<byte> PGP_decode(DataSource& source,
                              std::string& label,
                              std::map<std::string, std::string>& headers)
   {
   const size_t RANDOM_CHAR_LIMIT = 5;

   const std::string PGP_HEADER1 = "-----BEGIN PGP ";
   const std::string PGP_HEADER2 = "-----";
   size_t position = 0;

   while(position != PGP_HEADER1.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PGP: No PGP header found");
      if(b == PGP_HEADER1[position])
         ++position;
      else if(position >= RANDOM_CHAR_LIMIT)
         throw Decoding_Error("PGP: Malformed PGP header");
      else
         position = 0;
      }
   position = 0;
   while(position != PGP_HEADER2.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PGP: No PGP header found");
      if(b == PGP_HEADER2[position])
         ++position;
      else if(position)
         throw Decoding_Error("PGP: Malformed PGP header");

      if(position == 0)
         label += static_cast<char>(b);
      }

   headers.clear();
   bool end_of_headers = false;
   while(!end_of_headers)
      {
      std::string this_header;
      byte b = 0;
      while(b != '\n')
         {
         if(!source.read_byte(b))
            throw Decoding_Error("PGP: Bad armor header");
         if(b != '\n')
            this_header += static_cast<char>(b);
         }

      end_of_headers = true;
      for(size_t j = 0; j != this_header.length(); ++j)
         if(!Charset::is_space(this_header[j]))
            end_of_headers = false;

      if(!end_of_headers)
         {
         std::string::size_type pos = this_header.find(": ");
         if(pos == std::string::npos)
            throw Decoding_Error("OpenPGP: Bad headers");

         std::string key = this_header.substr(0, pos);
         std::string value = this_header.substr(pos + 2, std::string::npos);
         headers[key] = value;
         }
      }

   Pipe base64(new Base64_Decoder,
               new Fork(0,
                        new Chain(new Hash_Filter(new CRC24),
                                  new Base64_Encoder)
                  )
      );
   base64.start_msg();

   const std::string PGP_TRAILER = "-----END PGP " + label + "-----";
   position = 0;
   bool newline_seen = 0;
   std::string crc;
   while(position != PGP_TRAILER.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PGP: No PGP trailer found");
      if(b == PGP_TRAILER[position])
         ++position;
      else if(position)
         throw Decoding_Error("PGP: Malformed PGP trailer");

      if(b == '=' && newline_seen)
         {
         while(b != '\n')
            {
            if(!source.read_byte(b))
               throw Decoding_Error("PGP: Bad CRC tail");
            if(b != '\n')
               crc += static_cast<char>(b);
            }
         }
      else if(b == '\n')
         newline_seen = true;
      else if(position == 0)
         {
         base64.write(b);
         newline_seen = false;
         }
      }
   base64.end_msg();

   if(crc != "" && crc != base64.read_all_as_string(1))
      throw Decoding_Error("PGP: Corrupt CRC");

   return base64.read_all();
   }

/*
* OpenPGP Base64 decoding
*/
SecureVector<byte> PGP_decode(DataSource& source, std::string& label)
   {
   std::map<std::string, std::string> ignored;
   return PGP_decode(source, label, ignored);
   }

}

/*
* PEM Encoding/Decoding
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace PEM_Code {

/*
* PEM encode BER/DER-encoded objects
*/
std::string encode(const byte der[], size_t length, const std::string& label,
                   size_t width)
   {
   const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n";
   const std::string PEM_TRAILER = "-----END " + label + "-----\n";

   Pipe pipe(new Base64_Encoder(true, width));
   pipe.process_msg(der, length);
   return (PEM_HEADER + pipe.read_all_as_string() + PEM_TRAILER);
   }

/*
* PEM encode BER/DER-encoded objects
*/
std::string encode(const MemoryRegion<byte>& data, const std::string& label,
                   size_t width)
   {
   return encode(&data[0], data.size(), label, width);
   }

/*
* Decode PEM down to raw BER/DER
*/
SecureVector<byte> decode_check_label(DataSource& source,
                                      const std::string& label_want)
   {
   std::string label_got;
   SecureVector<byte> ber = decode(source, label_got);
   if(label_got != label_want)
      throw Decoding_Error("PEM: Label mismatch, wanted " + label_want +
                           ", got " + label_got);
   return ber;
   }

/*
* Decode PEM down to raw BER/DER
*/
SecureVector<byte> decode(DataSource& source, std::string& label)
   {
   const size_t RANDOM_CHAR_LIMIT = 8;

   const std::string PEM_HEADER1 = "-----BEGIN ";
   const std::string PEM_HEADER2 = "-----";
   size_t position = 0;

   while(position != PEM_HEADER1.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PEM: No PEM header found");
      if(b == PEM_HEADER1[position])
         ++position;
      else if(position >= RANDOM_CHAR_LIMIT)
         throw Decoding_Error("PEM: Malformed PEM header");
      else
         position = 0;
      }
   position = 0;
   while(position != PEM_HEADER2.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PEM: No PEM header found");
      if(b == PEM_HEADER2[position])
         ++position;
      else if(position)
         throw Decoding_Error("PEM: Malformed PEM header");

      if(position == 0)
         label += static_cast<char>(b);
      }

   Pipe base64(new Base64_Decoder);
   base64.start_msg();

   const std::string PEM_TRAILER = "-----END " + label + "-----";
   position = 0;
   while(position != PEM_TRAILER.length())
      {
      byte b;
      if(!source.read_byte(b))
         throw Decoding_Error("PEM: No PEM trailer found");
      if(b == PEM_TRAILER[position])
         ++position;
      else if(position)
         throw Decoding_Error("PEM: Malformed PEM trailer");

      if(position == 0)
         base64.write(b);
      }
   base64.end_msg();
   return base64.read_all();
   }

/*
* Search for a PEM signature
*/
bool matches(DataSource& source, const std::string& extra,
             size_t search_range)
   {
   const std::string PEM_HEADER = "-----BEGIN " + extra;

   SecureVector<byte> search_buf(search_range);
   size_t got = source.peek(&search_buf[0], search_buf.size(), 0);

   if(got < PEM_HEADER.length())
      return false;

   size_t index = 0;

   for(size_t j = 0; j != got; ++j)
      {
      if(search_buf[j] == PEM_HEADER[index])
         ++index;
      else
         index = 0;
      if(index == PEM_HEADER.size())
         return true;
      }
   return false;
   }

}

}
/*
* Rivest's Package Tranform
*
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

void aont_package(RandomNumberGenerator& rng,
                  BlockCipher* cipher,
                  const byte input[], size_t input_len,
                  byte output[])
   {
   const size_t BLOCK_SIZE = cipher->block_size();

   if(!cipher->valid_keylength(BLOCK_SIZE))
      throw Invalid_Argument("AONT::package: Invalid cipher");

   // The all-zero string which is used both as the CTR IV and as K0
   const std::string all_zeros(BLOCK_SIZE*2, '0');

   SymmetricKey package_key(rng, BLOCK_SIZE);

   Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key));

   pipe.process_msg(input, input_len);
   pipe.read(output, pipe.remaining());

   // Set K0 (the all zero key)
   cipher->set_key(SymmetricKey(all_zeros));

   SecureVector<byte> buf(BLOCK_SIZE);

   const size_t blocks =
      (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE;

   byte* final_block = output + input_len;
   clear_mem(final_block, BLOCK_SIZE);

   // XOR the hash blocks into the final block
   for(size_t i = 0; i != blocks; ++i)
      {
      const size_t left = std::min<size_t>(BLOCK_SIZE,
                                           input_len - BLOCK_SIZE * i);

      zeroise(buf);
      copy_mem(&buf[0], output + (BLOCK_SIZE * i), left);

      for(size_t j = 0; j != sizeof(i); ++j)
         buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i);

      cipher->encrypt(buf);

      xor_buf(final_block, buf, BLOCK_SIZE);
      }

   // XOR the random package key into the final block
   xor_buf(final_block, package_key.begin(), BLOCK_SIZE);
   }

void aont_unpackage(BlockCipher* cipher,
                    const byte input[], size_t input_len,
                    byte output[])
   {
   const size_t BLOCK_SIZE = cipher->block_size();

   if(!cipher->valid_keylength(BLOCK_SIZE))
      throw Invalid_Argument("AONT::unpackage: Invalid cipher");

   if(input_len < BLOCK_SIZE)
      throw Invalid_Argument("AONT::unpackage: Input too short");

   // The all-zero string which is used both as the CTR IV and as K0
   const std::string all_zeros(BLOCK_SIZE*2, '0');

   cipher->set_key(SymmetricKey(all_zeros));

   SecureVector<byte> package_key(BLOCK_SIZE);
   SecureVector<byte> buf(BLOCK_SIZE);

   // Copy the package key (masked with the block hashes)
   copy_mem(&package_key[0],
            input + (input_len - BLOCK_SIZE),
            BLOCK_SIZE);

   const size_t blocks = ((input_len - 1) / BLOCK_SIZE);

   // XOR the blocks into the package key bits
   for(size_t i = 0; i != blocks; ++i)
      {
      const size_t left = std::min<size_t>(BLOCK_SIZE,
                                           input_len - BLOCK_SIZE * (i+1));

      zeroise(buf);
      copy_mem(&buf[0], input + (BLOCK_SIZE * i), left);

      for(size_t j = 0; j != sizeof(i); ++j)
         buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i);

      cipher->encrypt(buf);

      xor_buf(&package_key[0], buf, BLOCK_SIZE);
      }

   Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key));

   pipe.process_msg(input, input_len - BLOCK_SIZE);

   pipe.read(output, pipe.remaining());
   }

}
/*
* Cryptobox Message Routines
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace CryptoBox {

namespace {

/*
First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
for later use as flags, etc if needed
*/
const u32bit CRYPTOBOX_VERSION_CODE = 0xEFC22400;

const size_t VERSION_CODE_LEN = 4;
const size_t CIPHER_KEY_LEN = 32;
const size_t CIPHER_IV_LEN = 16;
const size_t MAC_KEY_LEN = 32;
const size_t MAC_OUTPUT_LEN = 20;
const size_t PBKDF_SALT_LEN = 10;
const size_t PBKDF_ITERATIONS = 8 * 1024;

const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + CIPHER_IV_LEN + MAC_KEY_LEN;

}

std::string encrypt(const byte input[], size_t input_len,
                    const std::string& passphrase,
                    RandomNumberGenerator& rng)
   {
   SecureVector<byte> pbkdf_salt(PBKDF_SALT_LEN);
   rng.randomize(&pbkdf_salt[0], pbkdf_salt.size());

   PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512));

   OctetString master_key = pbkdf.derive_key(
      PBKDF_OUTPUT_LEN,
      passphrase,
      &pbkdf_salt[0],
      pbkdf_salt.size(),
      PBKDF_ITERATIONS);

   const byte* mk = master_key.begin();

   SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN);
   SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN);
   InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN);

   Pipe pipe(get_cipher("Serpent/CTR-BE", cipher_key, iv, ENCRYPTION),
             new Fork(
                0,
                new MAC_Filter(new HMAC(new SHA_512),
                               mac_key, MAC_OUTPUT_LEN)));

   pipe.process_msg(input, input_len);

   /*
   Output format is:
      version # (4 bytes)
      salt (10 bytes)
      mac (20 bytes)
      ciphertext
   */
   const size_t ciphertext_len = pipe.remaining(0);

   SecureVector<byte> out_buf(VERSION_CODE_LEN +
                              PBKDF_SALT_LEN +
                              MAC_OUTPUT_LEN +
                              ciphertext_len);

   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
     out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE);

   copy_mem(&out_buf[VERSION_CODE_LEN], &pbkdf_salt[0],  PBKDF_SALT_LEN);

   pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], MAC_OUTPUT_LEN, 1);
   pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN],
             ciphertext_len, 0);

   return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
   }

std::string decrypt(const byte input[], size_t input_len,
                    const std::string& passphrase)
   {
   DataSource_Memory input_src(input, input_len);
   SecureVector<byte> ciphertext =
      PEM_Code::decode_check_label(input_src,
                                   "BOTAN CRYPTOBOX MESSAGE");

   if(ciphertext.size() < (VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN))
      throw Decoding_Error("Invalid CryptoBox input");

   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
      if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE))
         throw Decoding_Error("Bad CryptoBox version");

   const byte* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];

   PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512));

   OctetString master_key = pbkdf.derive_key(
      PBKDF_OUTPUT_LEN,
      passphrase,
      pbkdf_salt,
      PBKDF_SALT_LEN,
      PBKDF_ITERATIONS);

   const byte* mk = master_key.begin();

   SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN);
   SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN);
   InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN);

   Pipe pipe(new Fork(
                get_cipher("Serpent/CTR-BE", cipher_key, iv, DECRYPTION),
                new MAC_Filter(new HMAC(new SHA_512),
                               mac_key, MAC_OUTPUT_LEN)));

   const size_t ciphertext_offset =
      VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;

   pipe.process_msg(&ciphertext[ciphertext_offset],
                    ciphertext.size() - ciphertext_offset);

   byte computed_mac[MAC_OUTPUT_LEN];
   pipe.read(computed_mac, MAC_OUTPUT_LEN, 1);

   if(!same_mem(computed_mac,
                &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN],
                MAC_OUTPUT_LEN))
      throw Decoding_Error("CryptoBox integrity failure");

   return pipe.read_all_as_string(0);
   }

std::string decrypt(const std::string& input,
                    const std::string& passphrase)
   {
   return decrypt(reinterpret_cast<const byte*>(&input[0]),
                  input.size(),
                  passphrase);
   }

}

}
/*
* Format Preserving Encryption using the scheme FE1 from the paper
* "Format-Preserving Encryption" by Bellare, Rogaway, et al
*    (http://eprint.iacr.org/2009/251)
*
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

namespace FPE {

namespace {

// Normally FPE is for SSNs, CC#s, etc, nothing too big
const size_t MAX_N_BYTES = 128/8;

/*
* Factor n into a and b which are as close together as possible.
* Assumes n is composed mostly of small factors which is the case for
* typical uses of FPE (typically, n is a power of 10)
*
* Want a >= b since the safe number of rounds is 2+log_a(b); if a >= b
* then this is always 3
*/
void factor(BigInt n, BigInt& a, BigInt& b)
   {
   a = 1;
   b = 1;

   size_t n_low_zero = low_zero_bits(n);

   a <<= (n_low_zero / 2);
   b <<= n_low_zero - (n_low_zero / 2);
   n >>= n_low_zero;

   for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i)
      {
      while(n % PRIMES[i] == 0)
         {
         a *= PRIMES[i];
         if(a > b)
            std::swap(a, b);
         n /= PRIMES[i];
         }
      }

   if(a > b)
      std::swap(a, b);
   a *= n;
   if(a < b)
      std::swap(a, b);

   if(a <= 1 || b <= 1)
      throw std::runtime_error("Could not factor n for use in FPE");
   }

/*
* According to a paper by Rogaway, Bellare, etc, the min safe number
* of rounds to use for FPE is 2+log_a(b). If a >= b then log_a(b) <= 1
* so 3 rounds is safe. The FPE factorization routine should always
* return a >= b, so just confirm that and return 3.
*/
size_t rounds(const BigInt& a, const BigInt& b)
   {
   if(a < b)
      throw std::logic_error("FPE rounds: a < b");
   return 3;
   }

/*
* A simple round function based on HMAC(SHA-256)
*/
class FPE_Encryptor
   {
   public:
      FPE_Encryptor(const SymmetricKey& key,
                    const BigInt& n,
                    const MemoryRegion<byte>& tweak);

      ~FPE_Encryptor() { delete mac; }

      BigInt operator()(size_t i, const BigInt& R);

   private:
      MessageAuthenticationCode* mac;
      SecureVector<byte> mac_n_t;
   };

FPE_Encryptor::FPE_Encryptor(const SymmetricKey& key,
                             const BigInt& n,
                             const MemoryRegion<byte>& tweak)
   {
   mac = new HMAC(new SHA_256);
   mac->set_key(key);

   SecureVector<byte> n_bin = BigInt::encode(n);

   if(n_bin.size() > MAX_N_BYTES)
      throw std::runtime_error("N is too large for FPE encryption");

   mac->update_be(static_cast<u32bit>(n_bin.size()));
   mac->update(&n_bin[0], n_bin.size());

   mac->update_be(static_cast<u32bit>(tweak.size()));
   mac->update(&tweak[0], tweak.size());

   mac_n_t = mac->final();
   }

BigInt FPE_Encryptor::operator()(size_t round_no, const BigInt& R)
   {
   SecureVector<byte> r_bin = BigInt::encode(R);

   mac->update(mac_n_t);
   mac->update_be(static_cast<u32bit>(round_no));

   mac->update_be(static_cast<u32bit>(r_bin.size()));
   mac->update(&r_bin[0], r_bin.size());

   SecureVector<byte> X = mac->final();
   return BigInt(&X[0], X.size());
   }

}

/*
* Generic Z_n FPE encryption, FE1 scheme
*/
BigInt fe1_encrypt(const BigInt& n, const BigInt& X0,
                   const SymmetricKey& key,
                   const MemoryRegion<byte>& tweak)
   {
   FPE_Encryptor F(key, n, tweak);

   BigInt a, b;
   factor(n, a, b);

   const size_t r = rounds(a, b);

   BigInt X = X0;

   for(size_t i = 0; i != r; ++i)
      {
      BigInt L = X / b;
      BigInt R = X % b;

      BigInt W = (L + F(i, R)) % a;
      X = a * R + W;
      }

   return X;
   }

/*
* Generic Z_n FPE decryption, FD1 scheme
*/
BigInt fe1_decrypt(const BigInt& n, const BigInt& X0,
                   const SymmetricKey& key,
                   const MemoryRegion<byte>& tweak)
   {
   FPE_Encryptor F(key, n, tweak);

   BigInt a, b;
   factor(n, a, b);

   const size_t r = rounds(a, b);

   BigInt X = X0;

   for(size_t i = 0; i != r; ++i)
      {
      BigInt W = X % a;
      BigInt R = X / a;

      BigInt L = (W - F(r-i-1, R)) % a;
      X = b * L + R;
      }

   return X;
   }

}

}
/*
* AES Key Wrap (RFC 3394)
* (C) 2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

BlockCipher* make_aes(size_t keylength,
                      Algorithm_Factory& af)
   {
   if(keylength == 16)
      return af.make_block_cipher("AES-128");
   else if(keylength == 24)
      return af.make_block_cipher("AES-192");
   else if(keylength == 32)
      return af.make_block_cipher("AES-256");
   else
      throw std::invalid_argument("Bad KEK length for NIST keywrap");
   }

}

SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key,
                                   const SymmetricKey& kek,
                                   Algorithm_Factory& af)
   {
   if(key.size() % 8 != 0)
      throw std::invalid_argument("Bad input key size for NIST key wrap");

   std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af));
   aes->set_key(kek);

   const size_t n = key.size() / 8;

   SecureVector<byte> R((n + 1) * 8);
   SecureVector<byte> A(16);

   for(size_t i = 0; i != 8; ++i)
      A[i] = 0xA6;

   copy_mem(&R[8], key.begin(), key.size());

   for(size_t j = 0; j <= 5; ++j)
      {
      for(size_t i = 1; i <= n; ++i)
         {
         const u32bit t = (n * j) + i;

         copy_mem(&A[8], &R[8*i], 8);

         aes->encrypt(&A[0]);
         copy_mem(&R[8*i], &A[8], 8);

         byte t_buf[4] = { 0 };
         store_be(t, t_buf);
         xor_buf(&A[4], &t_buf[0], 4);
         }
      }

   copy_mem(&R[0], &A[0], 8);

   return R;
   }

SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key,
                                     const SymmetricKey& kek,
                                     Algorithm_Factory& af)
   {
   if(key.size() < 16 || key.size() % 8 != 0)
      throw std::invalid_argument("Bad input key size for NIST key unwrap");

   std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af));
   aes->set_key(kek);

   const size_t n = (key.size() - 8) / 8;

   SecureVector<byte> R(n * 8);
   SecureVector<byte> A(16);

   for(size_t i = 0; i != 8; ++i)
      A[i] = key[i];

   copy_mem(&R[0], key.begin() + 8, key.size() - 8);

   for(size_t j = 0; j <= 5; ++j)
      {
      for(size_t i = n; i != 0; --i)
         {
         const u32bit t = (5 - j) * n + i;

         byte t_buf[4] = { 0 };
         store_be(t, t_buf);

         xor_buf(&A[4], &t_buf[0], 4);

         copy_mem(&A[8], &R[8*(i-1)], 8);

         aes->decrypt(&A[0]);

         copy_mem(&R[8*(i-1)], &A[8], 8);
         }
      }

   if(load_be<u64bit>(&A[0], 0) != 0xA6A6A6A6A6A6A6A6ULL)
      throw Integrity_Failure("NIST key unwrap failed");

   return R;
   }

}
/*
* SRP-6a (RFC 5054 compatatible)
* (C) 2011,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

BigInt hash_seq(const std::string& hash_id,
                size_t pad_to,
                const BigInt& in1,
                const BigInt& in2)
   {
   std::auto_ptr<HashFunction> hash_fn(
      global_state().algorithm_factory().make_hash_function(hash_id));

   hash_fn->update(BigInt::encode_1363(in1, pad_to));
   hash_fn->update(BigInt::encode_1363(in2, pad_to));

   return BigInt::decode(hash_fn->final());
   }

BigInt hash_seq(const std::string& hash_id,
                size_t pad_to,
                const BigInt& in1,
                const BigInt& in2,
                const BigInt& in3)
   {
   std::auto_ptr<HashFunction> hash_fn(
      global_state().algorithm_factory().make_hash_function(hash_id));

   hash_fn->update(BigInt::encode_1363(in1, pad_to));
   hash_fn->update(BigInt::encode_1363(in2, pad_to));
   hash_fn->update(BigInt::encode_1363(in3, pad_to));

   return BigInt::decode(hash_fn->final());
   }

BigInt compute_x(const std::string& hash_id,
                 const std::string& identifier,
                 const std::string& password,
                 const MemoryRegion<byte>& salt)
   {
   std::auto_ptr<HashFunction> hash_fn(
      global_state().algorithm_factory().make_hash_function(hash_id));

   hash_fn->update(identifier);
   hash_fn->update(":");
   hash_fn->update(password);

   SecureVector<byte> inner_h = hash_fn->final();

   hash_fn->update(salt);
   hash_fn->update(inner_h);

   SecureVector<byte> outer_h = hash_fn->final();

   return BigInt::decode(outer_h);
   }

}

std::string srp6_group_identifier(const BigInt& N, const BigInt& g)
   {
   /*
   This function assumes that only one 'standard' SRP parameter set has
   been defined for a particular bitsize. As of this writing that is the case.
   */
   try
      {
      const std::string group_name = "modp/srp/" + to_string(N.bits());

      DL_Group group(group_name);

      if(group.get_p() == N && group.get_g() == g)
         return group_name;

      throw std::runtime_error("Unknown SRP params");
      }
   catch(...)
      {
      throw Invalid_Argument("Bad SRP group parameters");
      }
   }

std::pair<BigInt, SymmetricKey>
srp6_client_agree(const std::string& identifier,
                  const std::string& password,
                  const std::string& group_id,
                  const std::string& hash_id,
                  const MemoryRegion<byte>& salt,
                  const BigInt& B,
                  RandomNumberGenerator& rng)
   {
   DL_Group group(group_id);
   const BigInt& g = group.get_g();
   const BigInt& p = group.get_p();

   const size_t p_bytes = group.get_p().bytes();

   if(B % p == 0)
      throw std::runtime_error("Invalid SRP parameter from server");

   BigInt k = hash_seq(hash_id, p_bytes, p, g);

   BigInt a(rng, 256);

   BigInt A = power_mod(g, a, p);

   BigInt u = hash_seq(hash_id, p_bytes, A, B);

   const BigInt x = compute_x(hash_id, identifier, password, salt);

   BigInt S = power_mod((B - (k * power_mod(g, x, p))) % p, (a + (u * x)), p);

   SymmetricKey Sk(BigInt::encode_1363(S, p_bytes));

   return std::make_pair(A, Sk);
   }

BigInt generate_srp6_verifier(const std::string& identifier,
                              const std::string& password,
                              const MemoryRegion<byte>& salt,
                              const std::string& group_id,
                              const std::string& hash_id)
   {
   const BigInt x = compute_x(hash_id, identifier, password, salt);

   DL_Group group(group_id);
   return power_mod(group.get_g(), x, group.get_p());
   }

BigInt SRP6_Server_Session::step1(const BigInt& v,
                                  const std::string& group_id,
                                  const std::string& hash_id,
                                  RandomNumberGenerator& rng)
   {
   DL_Group group(group_id);
   const BigInt& g = group.get_g();
   const BigInt& p = group.get_p();

   p_bytes = p.bytes();

   BigInt k = hash_seq(hash_id, p_bytes, p, g);

   BigInt b(rng, 256);

   B = (v*k + power_mod(g, b, p)) % p;

   this->v = v;
   this->b = b;
   this->p = p;
   this->hash_id = hash_id;

   return B;
   }

SymmetricKey SRP6_Server_Session::step2(const BigInt& A)
   {
   if(A % p == 0)
      throw std::runtime_error("Invalid SRP parameter from client");

   BigInt u = hash_seq(hash_id, p_bytes, A, B);

   BigInt S = power_mod(A * power_mod(v, u, p), b, p);

   return BigInt::encode_1363(S, p_bytes);
   }

}
/*
* RTSS (threshold secret sharing)
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

/**
Table for GF(2^8) arithmetic (exponentials)
*/
const byte RTSS_EXP[256] = {
0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72,
0x96, 0xA1, 0xF8, 0x13, 0x35, 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73,
0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA, 0xE5,
0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70,
0x90, 0xAB, 0xE6, 0x31, 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44,
0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD, 0x4C, 0xD4,
0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18,
0x28, 0x78, 0x88, 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F,
0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A, 0xB5, 0xC4, 0x57,
0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6,
0x61, 0xA3, 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F,
0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0, 0xFB, 0x16, 0x3A, 0x4E,
0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F,
0x41, 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED,
0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75, 0x9F, 0xBA, 0xD5, 0x64, 0xAC,
0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F,
0xB1, 0xC8, 0x43, 0xC5, 0x54, 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4,
0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA, 0x45,
0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42,
0xC6, 0x51, 0xF3, 0x0E, 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D,
0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17, 0x39, 0x4B,
0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7,
0x52, 0xF6, 0x01 };

/**
Table for GF(2^8) arithmetic (logarithms)
*/
const byte RTSS_LOG[] = {
0x90, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B,
0x68, 0x33, 0xEE, 0xDF, 0x03, 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D,
0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1, 0x7D,
0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72,
0x9A, 0xC9, 0x09, 0x78, 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1,
0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E, 0x96, 0x8F,
0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40,
0x46, 0x83, 0x38, 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62,
0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10, 0x7E, 0x6E, 0x48,
0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85,
0x3D, 0xBA, 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E,
0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57, 0xAF, 0x58, 0xA8, 0x50,
0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD,
0xE8, 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB,
0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0, 0x7F, 0x0C, 0xF6, 0x6F, 0x17,
0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7,
0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1,
0x6C, 0xAA, 0x55, 0x29, 0x9D, 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE,
0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1, 0x53,
0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D,
0x56, 0xF2, 0xD3, 0xAB, 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E,
0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5, 0x67, 0x4A,
0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0,
0xF7, 0x70, 0x07 };

byte gfp_mul(byte x, byte y)
   {
   if(x == 0 || y == 0)
      return 0;
   return RTSS_EXP[(RTSS_LOG[x] + RTSS_LOG[y]) % 255];
   }

byte rtss_hash_id(const std::string& hash_name)
   {
   if(hash_name == "SHA-160")
      return 1;
   else if(hash_name == "SHA-256")
      return 2;
   else
      throw Invalid_Argument("RTSS only supports SHA-1 and SHA-256");
   }

HashFunction* get_rtss_hash_by_id(byte id)
   {
   if(id == 1)
      return new SHA_160;
   else if(id == 2)
      return new SHA_256;
   else
      throw Decoding_Error("Bad RTSS hash identifier");
   }

}

RTSS_Share::RTSS_Share(const std::string& hex_input)
   {
   contents = hex_decode(hex_input);
   }

byte RTSS_Share::share_id() const
   {
   if(!initialized())
      throw Invalid_State("RTSS_Share::share_id not initialized");

   return contents[20];
   }

std::string RTSS_Share::to_string() const
   {
   return hex_encode(&contents[0], contents.size());
   }

std::vector<RTSS_Share>
RTSS_Share::split(byte M, byte N,
                  const byte S[], u16bit S_len,
                  const byte identifier[16],
                  RandomNumberGenerator& rng)
   {
   if(M == 0 || N == 0 || M > N)
      throw Encoding_Error("RTSS_Share::split: M == 0 or N == 0 or M > N");

   SHA_256 hash; // always use SHA-256 when generating shares

   std::vector<RTSS_Share> shares(N);

   // Create RTSS header in each share
   for(byte i = 0; i != N; ++i)
      {
      shares[i].contents += std::make_pair(identifier, 16);
      shares[i].contents += rtss_hash_id(hash.name());
      shares[i].contents += M;
      shares[i].contents += get_byte(0, S_len);
      shares[i].contents += get_byte(1, S_len);
      }

   // Choose sequential values for X starting from 1
   for(byte i = 0; i != N; ++i)
      shares[i].contents.push_back(i+1);

   // secret = S || H(S)
   SecureVector<byte> secret(S, S_len);
   secret += hash.process(S, S_len);

   for(size_t i = 0; i != secret.size(); ++i)
      {
      std::vector<byte> coefficients(M-1);
      rng.randomize(&coefficients[0], coefficients.size());

      for(byte j = 0; j != N; ++j)
         {
         const byte X = j + 1;

         byte sum = secret[i];
         byte X_i = X;

         for(size_t k = 0; k != coefficients.size(); ++k)
            {
            sum ^= gfp_mul(X_i, coefficients[k]);
            X_i  = gfp_mul(X_i, X);
            }

         shares[j].contents.push_back(sum);
         }
      }

   return shares;
   }

SecureVector<byte>
RTSS_Share::reconstruct(const std::vector<RTSS_Share>& shares)
   {
   const size_t RTSS_HEADER_SIZE = 20;

   for(size_t i = 0; i != shares.size(); ++i)
      {
      if(shares[i].size() != shares[0].size())
         throw Decoding_Error("Different sized RTSS shares detected");
      if(shares[i].share_id() == 0)
         throw Decoding_Error("Invalid (id = 0) RTSS share detected");
      if(shares[i].size() < RTSS_HEADER_SIZE)
         throw Decoding_Error("Missing or malformed RTSS header");

      if(!same_mem(&shares[0].contents[0],
                   &shares[i].contents[0], RTSS_HEADER_SIZE))
         throw Decoding_Error("Different RTSS headers detected");
      }

   if(shares.size() < shares[0].contents[17])
      throw Decoding_Error("Insufficient shares to do TSS reconstruction");

   u16bit secret_len = make_u16bit(shares[0].contents[18],
                                   shares[0].contents[19]);

   byte hash_id = shares[0].contents[16];

   std::auto_ptr<HashFunction> hash(get_rtss_hash_by_id(hash_id));

   if(shares[0].size() != secret_len + hash->output_length() + RTSS_HEADER_SIZE + 1)
      throw Decoding_Error("Bad RTSS length field in header");

   std::vector<byte> V(shares.size());
   SecureVector<byte> secret;

   for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i)
      {
      for(size_t j = 0; j != V.size(); ++j)
         V[j] = shares[j].contents[i];

      byte r = 0;
      for(size_t k = 0; k != shares.size(); ++k)
         {
         // L_i function:
         byte r2 = 1;
         for(size_t l = 0; l != shares.size(); ++l)
            {
            if(k == l)
               continue;

            byte share_k = shares[k].share_id();
            byte share_l = shares[l].share_id();

            if(share_k == share_l)
               throw Decoding_Error("Duplicate shares found in RTSS recovery");

            byte div = RTSS_EXP[(255 +
                                 RTSS_LOG[share_l] -
                                 RTSS_LOG[share_k ^ share_l]) % 255];

            r2 = gfp_mul(r2, div);
            }

         r ^= gfp_mul(V[k], r2);
         }
      secret.push_back(r);
      }

   if(secret.size() != secret_len + hash->output_length())
      throw Decoding_Error("Bad length in RTSS output");

   hash->update(&secret[0], secret_len);
   SecureVector<byte> hash_check = hash->final();

   if(!same_mem(&hash_check[0],
                &secret[secret_len], hash->output_length()))
      throw Decoding_Error("RTSS hash check failed");

   return SecureVector<byte>(&secret[0], secret_len);
   }

}
/*
* Core Engine
* (C) 1999-2007,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

#if defined(BOTAN_HAS_ECB)
#endif

#if defined(BOTAN_HAS_CBC)
#endif

#if defined(BOTAN_HAS_CTS)
#endif

#if defined(BOTAN_HAS_CFB)
#endif

#if defined(BOTAN_HAS_OFB)
#endif

#if defined(BOTAN_HAS_CTR_BE)
#endif

#if defined(BOTAN_HAS_EAX)
#endif

#if defined(BOTAN_HAS_XTS)
#endif

namespace Botan {

namespace {

/**
* Get a block cipher padding method by name
*/
BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec,
                                         const std::string& def_if_empty)
   {
#if defined(BOTAN_HAS_CIPHER_MODE_PADDING)
   if(algo_spec == "NoPadding" || (algo_spec == "" && def_if_empty == "NoPadding"))
      return new Null_Padding;

   if(algo_spec == "PKCS7" || (algo_spec == "" && def_if_empty == "PKCS7"))
      return new PKCS7_Padding;

   if(algo_spec == "OneAndZeros")
      return new OneAndZeros_Padding;

   if(algo_spec == "X9.23")
      return new ANSI_X923_Padding;

#endif

   throw Algorithm_Not_Found(algo_spec);
   }

}

Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher,
                              Cipher_Dir direction,
                              const std::string& mode,
                              const std::string& padding)
   {
#if defined(BOTAN_HAS_OFB)
   if(mode == "OFB")
      return new StreamCipher_Filter(new OFB(block_cipher->clone()));
#endif

#if defined(BOTAN_HAS_CTR_BE)
   if(mode == "CTR-BE")
      return new StreamCipher_Filter(new CTR_BE(block_cipher->clone()));
#endif

#if defined(BOTAN_HAS_ECB)
   if(mode == "ECB" || mode == "")
      {
      if(direction == ENCRYPTION)
         return new ECB_Encryption(block_cipher->clone(),
                                   get_bc_pad(padding, "NoPadding"));
      else
         return new ECB_Decryption(block_cipher->clone(),
                                   get_bc_pad(padding, "NoPadding"));
      }
#endif

   if(mode == "CBC")
      {
      if(padding == "CTS")
         {
#if defined(BOTAN_HAS_CTS)
         if(direction == ENCRYPTION)
            return new CTS_Encryption(block_cipher->clone());
         else
            return new CTS_Decryption(block_cipher->clone());
#else
         return 0;
#endif
         }

#if defined(BOTAN_HAS_CBC)
      if(direction == ENCRYPTION)
         return new CBC_Encryption(block_cipher->clone(),
                                   get_bc_pad(padding, "PKCS7"));
      else
         return new CBC_Decryption(block_cipher->clone(),
                                   get_bc_pad(padding, "PKCS7"));
#else
      return 0;
#endif
      }

#if defined(BOTAN_HAS_XTS)
   if(mode == "XTS")
      {
      if(direction == ENCRYPTION)
         return new XTS_Encryption(block_cipher->clone());
      else
         return new XTS_Decryption(block_cipher->clone());
      }
#endif

   if(mode.find("CFB") != std::string::npos ||
      mode.find("EAX") != std::string::npos)
      {
      size_t bits = 0;

      std::vector<std::string> algo_info = parse_algorithm_name(mode);
      std::string mode_name = algo_info[0];
      if(algo_info.size() == 1)
         bits = 8 * block_cipher->block_size();
      else if(algo_info.size() == 2)
         bits = to_u32bit(algo_info[1]);
      else
         return 0;

#if defined(BOTAN_HAS_CFB)
      if(mode_name == "CFB")
         {
         if(direction == ENCRYPTION)
            return new CFB_Encryption(block_cipher->clone(), bits);
         else
            return new CFB_Decryption(block_cipher->clone(), bits);
         }
#endif

#if defined(BOTAN_HAS_EAX)
      if(mode_name == "EAX")
         {
         if(direction == ENCRYPTION)
            return new EAX_Encryption(block_cipher->clone(), bits);
         else
            return new EAX_Decryption(block_cipher->clone(), bits);
         }
#endif
      }

   return 0;
   }

/*
* Get a cipher object
*/
Keyed_Filter* Core_Engine::get_cipher(const std::string& algo_spec,
                                      Cipher_Dir direction,
                                      Algorithm_Factory& af)
   {
   std::vector<std::string> algo_parts = split_on(algo_spec, '/');
   if(algo_parts.empty())
      throw Invalid_Algorithm_Name(algo_spec);

   const std::string cipher_name = algo_parts[0];

   // check if it is a stream cipher first (easy case)
   const StreamCipher* stream_cipher = af.prototype_stream_cipher(cipher_name);
   if(stream_cipher)
      return new StreamCipher_Filter(stream_cipher->clone());

   const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_name);
   if(!block_cipher)
      return 0;

   if(algo_parts.size() >= 4)
      return 0; // 4 part mode, not something we know about

   if(algo_parts.size() < 2)
      throw Lookup_Error("Cipher specification '" + algo_spec +
                         "' is missing mode identifier");

   std::string mode = algo_parts[1];

   std::string padding;
   if(algo_parts.size() == 3)
      padding = algo_parts[2];
   else
      padding = (mode == "CBC") ? "PKCS7" : "NoPadding";

   if(mode == "ECB" && padding == "CTS")
      return 0;
   else if((mode != "CBC" && mode != "ECB") && padding != "NoPadding")
      throw Invalid_Algorithm_Name(algo_spec);

   Keyed_Filter* filt = get_cipher_mode(block_cipher, direction, mode, padding);
   if(filt)
      return filt;

   throw Algorithm_Not_Found(cipher_name + "/" + mode + "/" + padding);
   }

}
/*
* PK Operations
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_RSA)
#endif

#if defined(BOTAN_HAS_RW)
#endif

#if defined(BOTAN_HAS_DSA)
#endif

#if defined(BOTAN_HAS_ECDSA)
#endif

#if defined(BOTAN_HAS_ELGAMAL)
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
#endif

#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
#endif

#if defined(BOTAN_HAS_ECDH)
#endif

namespace Botan {

PK_Ops::Encryption*
Core_Engine::get_encryption_op(const Public_Key& key) const
   {
#if defined(BOTAN_HAS_RSA)
   if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key))
      return new RSA_Public_Operation(*s);
#endif

#if defined(BOTAN_HAS_ELGAMAL)
   if(const ElGamal_PublicKey* s = dynamic_cast<const ElGamal_PublicKey*>(&key))
      return new ElGamal_Encryption_Operation(*s);
#endif

   return 0;
   }

PK_Ops::Decryption*
Core_Engine::get_decryption_op(const Private_Key& key) const
   {
#if defined(BOTAN_HAS_RSA)
   if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key))
      return new RSA_Private_Operation(*s);
#endif

#if defined(BOTAN_HAS_ELGAMAL)
   if(const ElGamal_PrivateKey* s = dynamic_cast<const ElGamal_PrivateKey*>(&key))
      return new ElGamal_Decryption_Operation(*s);
#endif

   return 0;
   }

PK_Ops::Key_Agreement*
Core_Engine::get_key_agreement_op(const Private_Key& key) const
   {
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
   if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key))
      return new DH_KA_Operation(*dh);
#endif

#if defined(BOTAN_HAS_ECDH)
   if(const ECDH_PrivateKey* ecdh = dynamic_cast<const ECDH_PrivateKey*>(&key))
      return new ECDH_KA_Operation(*ecdh);
#endif

   return 0;
   }

PK_Ops::Signature*
Core_Engine::get_signature_op(const Private_Key& key) const
   {
#if defined(BOTAN_HAS_RSA)
   if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key))
      return new RSA_Private_Operation(*s);
#endif

#if defined(BOTAN_HAS_RW)
   if(const RW_PrivateKey* s = dynamic_cast<const RW_PrivateKey*>(&key))
      return new RW_Signature_Operation(*s);
#endif

#if defined(BOTAN_HAS_DSA)
   if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key))
      return new DSA_Signature_Operation(*s);
#endif

#if defined(BOTAN_HAS_ECDSA)
   if(const ECDSA_PrivateKey* s = dynamic_cast<const ECDSA_PrivateKey*>(&key))
      return new ECDSA_Signature_Operation(*s);
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
   if(const GOST_3410_PrivateKey* s =
         dynamic_cast<const GOST_3410_PrivateKey*>(&key))
      return new GOST_3410_Signature_Operation(*s);
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
   if(const NR_PrivateKey* s = dynamic_cast<const NR_PrivateKey*>(&key))
      return new NR_Signature_Operation(*s);
#endif

   return 0;
   }

PK_Ops::Verification*
Core_Engine::get_verify_op(const Public_Key& key) const
   {
#if defined(BOTAN_HAS_RSA)
   if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key))
      return new RSA_Public_Operation(*s);
#endif

#if defined(BOTAN_HAS_RW)
   if(const RW_PublicKey* s = dynamic_cast<const RW_PublicKey*>(&key))
      return new RW_Verification_Operation(*s);
#endif

#if defined(BOTAN_HAS_DSA)
   if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key))
      return new DSA_Verification_Operation(*s);
#endif

#if defined(BOTAN_HAS_ECDSA)
   if(const ECDSA_PublicKey* s = dynamic_cast<const ECDSA_PublicKey*>(&key))
      return new ECDSA_Verification_Operation(*s);
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
   if(const GOST_3410_PublicKey* s =
         dynamic_cast<const GOST_3410_PublicKey*>(&key))
      return new GOST_3410_Verification_Operation(*s);
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
   if(const NR_PublicKey* s = dynamic_cast<const NR_PublicKey*>(&key))
      return new NR_Verification_Operation(*s);
#endif

   return 0;
   }

}
/*
* Modular Exponentiation
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Choose a modular exponentation algorithm
*/
Modular_Exponentiator*
Core_Engine::mod_exp(const BigInt& n, Power_Mod::Usage_Hints hints) const
   {
   if(n.is_odd())
      return new Montgomery_Exponentiator(n, hints);
   return new Fixed_Window_Exponentiator(n, hints);
   }

}
/*
* Block Cipher Lookup
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_AES)
#endif

#if defined(BOTAN_HAS_BLOWFISH)
#endif

#if defined(BOTAN_HAS_CAMELLIA)
#endif

#if defined(BOTAN_HAS_CAST)
#endif

#if defined(BOTAN_HAS_CASCADE)
#endif

#if defined(BOTAN_HAS_DES)
#endif

#if defined(BOTAN_HAS_GOST_28147_89)
#endif

#if defined(BOTAN_HAS_IDEA)
#endif

#if defined(BOTAN_HAS_KASUMI)
#endif

#if defined(BOTAN_HAS_LION)
#endif

#if defined(BOTAN_HAS_LUBY_RACKOFF)
#endif

#if defined(BOTAN_HAS_MARS)
#endif

#if defined(BOTAN_HAS_MISTY1)
#endif

#if defined(BOTAN_HAS_NOEKEON)
#endif

#if defined(BOTAN_HAS_RC2)
#endif

#if defined(BOTAN_HAS_RC5)
#endif

#if defined(BOTAN_HAS_RC6)
#endif

#if defined(BOTAN_HAS_SAFER)
#endif

#if defined(BOTAN_HAS_SEED)
#endif

#if defined(BOTAN_HAS_SERPENT)
#endif

#if defined(BOTAN_HAS_SKIPJACK)
#endif

#if defined(BOTAN_HAS_SQUARE)
#endif

#if defined(BOTAN_HAS_TEA)
#endif

#if defined(BOTAN_HAS_TWOFISH)
#endif

#if defined(BOTAN_HAS_XTEA)
#endif

namespace Botan {

/*
* Look for an algorithm with this name
*/
BlockCipher* Core_Engine::find_block_cipher(const SCAN_Name& request,
                                            Algorithm_Factory& af) const
   {

#if defined(BOTAN_HAS_AES)
   if(request.algo_name() == "AES-128")
      return new AES_128;
   if(request.algo_name() == "AES-192")
      return new AES_192;
   if(request.algo_name() == "AES-256")
      return new AES_256;
#endif

#if defined(BOTAN_HAS_BLOWFISH)
   if(request.algo_name() == "Blowfish")
      return new Blowfish;
#endif

#if defined(BOTAN_HAS_CAMELLIA)
   if(request.algo_name() == "Camellia-128")
      return new Camellia_128;
   if(request.algo_name() == "Camellia-192")
      return new Camellia_192;
   if(request.algo_name() == "Camellia-256")
      return new Camellia_256;
#endif

#if defined(BOTAN_HAS_CAST)
   if(request.algo_name() == "CAST-128")
      return new CAST_128;
   if(request.algo_name() == "CAST-256")
      return new CAST_256;
#endif

#if defined(BOTAN_HAS_DES)
   if(request.algo_name() == "DES")
      return new DES;
   if(request.algo_name() == "DESX")
      return new DESX;
   if(request.algo_name() == "TripleDES")
      return new TripleDES;
#endif

#if defined(BOTAN_HAS_GOST_28147_89)
   if(request.algo_name() == "GOST-28147-89")
      return new GOST_28147_89(request.arg(0, "R3411_94_TestParam"));
#endif

#if defined(BOTAN_HAS_IDEA)
   if(request.algo_name() == "IDEA")
      return new IDEA;
#endif

#if defined(BOTAN_HAS_KASUMI)
   if(request.algo_name() == "KASUMI")
      return new KASUMI;
#endif

#if defined(BOTAN_HAS_MARS)
   if(request.algo_name() == "MARS")
      return new MARS;
#endif

#if defined(BOTAN_HAS_MISTY1)
   if(request.algo_name() == "MISTY1")
      return new MISTY1(request.arg_as_integer(0, 8));
#endif

#if defined(BOTAN_HAS_NOEKEON)
   if(request.algo_name() == "Noekeon")
      return new Noekeon;
#endif

#if defined(BOTAN_HAS_RC2)
   if(request.algo_name() == "RC2")
      return new RC2;
#endif

#if defined(BOTAN_HAS_RC5)
   if(request.algo_name() == "RC5")
      return new RC5(request.arg_as_integer(0, 12));
#endif

#if defined(BOTAN_HAS_RC6)
   if(request.algo_name() == "RC6")
      return new RC6;
#endif

#if defined(BOTAN_HAS_SAFER)
   if(request.algo_name() == "SAFER-SK")
      return new SAFER_SK(request.arg_as_integer(0, 10));
#endif

#if defined(BOTAN_HAS_SEED)
   if(request.algo_name() == "SEED")
      return new SEED;
#endif

#if defined(BOTAN_HAS_SERPENT)
   if(request.algo_name() == "Serpent")
      return new Serpent;
#endif

#if defined(BOTAN_HAS_SKIPJACK)
   if(request.algo_name() == "Skipjack")
      return new Skipjack;
#endif

#if defined(BOTAN_HAS_SQUARE)
   if(request.algo_name() == "Square")
      return new Square;
#endif

#if defined(BOTAN_HAS_TEA)
   if(request.algo_name() == "TEA")
      return new TEA;
#endif

#if defined(BOTAN_HAS_TWOFISH)
   if(request.algo_name() == "Twofish")
      return new Twofish;
#endif

#if defined(BOTAN_HAS_XTEA)
   if(request.algo_name() == "XTEA")
      return new XTEA;
#endif

#if defined(BOTAN_HAS_LUBY_RACKOFF)
   if(request.algo_name() == "Luby-Rackoff" && request.arg_count() == 1)
      {
      const HashFunction* hash = af.prototype_hash_function(request.arg(0));

      if(hash)
         return new LubyRackoff(hash->clone());
      }
#endif

#if defined(BOTAN_HAS_CASCADE)
   if(request.algo_name() == "Cascade" && request.arg_count() == 2)
      {
      const BlockCipher* c1 = af.prototype_block_cipher(request.arg(0));
      const BlockCipher* c2 = af.prototype_block_cipher(request.arg(1));

      if(c1 && c2)
         return new Cascade_Cipher(c1->clone(), c2->clone());
      }
#endif

#if defined(BOTAN_HAS_LION)
   if(request.algo_name() == "Lion" && request.arg_count_between(2, 3))
      {
      const size_t block_size = request.arg_as_integer(2, 1024);

      const HashFunction* hash =
         af.prototype_hash_function(request.arg(0));

      const StreamCipher* stream_cipher =
         af.prototype_stream_cipher(request.arg(1));

      if(!hash || !stream_cipher)
         return 0;

      return new Lion(hash->clone(), stream_cipher->clone(), block_size);
      }
#endif

   return 0;
   }

}
/*
* Hash Algorithms Lookup
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

#if defined(BOTAN_HAS_ADLER32)
#endif

#if defined(BOTAN_HAS_CRC24)
#endif

#if defined(BOTAN_HAS_CRC32)
#endif

#if defined(BOTAN_HAS_BMW_512)
#endif

#if defined(BOTAN_HAS_GOST_34_11)
#endif

#if defined(BOTAN_HAS_HAS_160)
#endif

#if defined(BOTAN_HAS_KECCAK)
#endif

#if defined(BOTAN_HAS_MD2)
#endif

#if defined(BOTAN_HAS_MD4)
#endif

#if defined(BOTAN_HAS_MD5)
#endif

#if defined(BOTAN_HAS_RIPEMD_128)
#endif

#if defined(BOTAN_HAS_RIPEMD_160)
#endif

#if defined(BOTAN_HAS_SHA1)
#endif

#if defined(BOTAN_HAS_SHA2_32)
#endif

#if defined(BOTAN_HAS_SHA2_64)
#endif

#if defined(BOTAN_HAS_SKEIN_512)
#endif

#if defined(BOTAN_HAS_TIGER)
#endif

#if defined(BOTAN_HAS_WHIRLPOOL)
#endif

#if defined(BOTAN_HAS_PARALLEL_HASH)
#endif

#if defined(BOTAN_HAS_COMB4P)
#endif

namespace Botan {

/*
* Look for an algorithm with this name
*/
HashFunction* Core_Engine::find_hash(const SCAN_Name& request,
                                     Algorithm_Factory& af) const
   {
#if defined(BOTAN_HAS_ADLER32)
   if(request.algo_name() == "Adler32")
      return new Adler32;
#endif

#if defined(BOTAN_HAS_CRC24)
   if(request.algo_name() == "CRC24")
      return new CRC24;
#endif

#if defined(BOTAN_HAS_CRC32)
   if(request.algo_name() == "CRC32")
      return new CRC32;
#endif

#if defined(BOTAN_HAS_BMW_512)
   if(request.algo_name() == "BMW-512")
      return new BMW_512;
#endif

#if defined(BOTAN_HAS_GOST_34_11)
   if(request.algo_name() == "GOST-34.11")
      return new GOST_34_11;
#endif

#if defined(BOTAN_HAS_HAS_160)
   if(request.algo_name() == "HAS-160")
      return new HAS_160;
#endif

#if defined(BOTAN_HAS_KECCAK)
   if(request.algo_name() == "Keccak-1600")
      return new Keccak_1600(request.arg_as_integer(0, 512));
#endif

#if defined(BOTAN_HAS_MD2)
   if(request.algo_name() == "MD2")
      return new MD2;
#endif

#if defined(BOTAN_HAS_MD4)
   if(request.algo_name() == "MD4")
      return new MD4;
#endif

#if defined(BOTAN_HAS_MD5)
   if(request.algo_name() == "MD5")
      return new MD5;
#endif

#if defined(BOTAN_HAS_RIPEMD_128)
   if(request.algo_name() == "RIPEMD-128")
      return new RIPEMD_128;
#endif

#if defined(BOTAN_HAS_RIPEMD_160)
   if(request.algo_name() == "RIPEMD-160")
      return new RIPEMD_160;
#endif

#if defined(BOTAN_HAS_SHA1)
   if(request.algo_name() == "SHA-160")
      return new SHA_160;
#endif

#if defined(BOTAN_HAS_SHA2_32)
   if(request.algo_name() == "SHA-224")
      return new SHA_224;
   if(request.algo_name() == "SHA-256")
      return new SHA_256;
#endif

#if defined(BOTAN_HAS_SHA2_64)
   if(request.algo_name() == "SHA-384")
      return new SHA_384;
   if(request.algo_name() == "SHA-512")
      return new SHA_512;
#endif

#if defined(BOTAN_HAS_TIGER)
   if(request.algo_name() == "Tiger")
      return new Tiger(request.arg_as_integer(0, 24), // hash output
                       request.arg_as_integer(1, 3)); // # passes
#endif

#if defined(BOTAN_HAS_SKEIN_512)
   if(request.algo_name() == "Skein-512")
      return new Skein_512(request.arg_as_integer(0, 512),
                           request.arg(1, ""));
#endif

#if defined(BOTAN_HAS_WHIRLPOOL)
   if(request.algo_name() == "Whirlpool")
      return new Whirlpool;
#endif

#if defined(BOTAN_HAS_COMB4P)
   if(request.algo_name() == "Comb4P" && request.arg_count() == 2)
      {
      const HashFunction* h1 = af.prototype_hash_function(request.arg(0));
      const HashFunction* h2 = af.prototype_hash_function(request.arg(1));

      if(h1 && h2)
         return new Comb4P(h1->clone(), h2->clone());
      }
#endif

#if defined(BOTAN_HAS_PARALLEL_HASH)

   if(request.algo_name() == "Parallel")
      {
      std::vector<const HashFunction*> hash_prototypes;

      /* First pass, just get the prototypes (no memory allocation). Then
         if all were found, replace each prototype with a newly created clone
      */
      for(size_t i = 0; i != request.arg_count(); ++i)
         {
         const HashFunction* hash = af.prototype_hash_function(request.arg(i));
         if(!hash)
            return 0;

         hash_prototypes.push_back(hash);
         }

      std::vector<HashFunction*> hashes;
      for(size_t i = 0; i != hash_prototypes.size(); ++i)
         hashes.push_back(hash_prototypes[i]->clone());

      return new Parallel(hashes);
      }

#endif

   return 0;
   }

}
/*
* MAC Lookup
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_CBC_MAC)
#endif

#if defined(BOTAN_HAS_CMAC)
#endif

#if defined(BOTAN_HAS_HMAC)
#endif

#if defined(BOTAN_HAS_SSL3_MAC)
#endif

#if defined(BOTAN_HAS_ANSI_X919_MAC)
#endif

namespace Botan {

/*
* Look for an algorithm with this name
*/
MessageAuthenticationCode*
Core_Engine::find_mac(const SCAN_Name& request,
                      Algorithm_Factory& af) const
   {

#if defined(BOTAN_HAS_CBC_MAC)
   if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1)
      return new CBC_MAC(af.make_block_cipher(request.arg(0)));
#endif

#if defined(BOTAN_HAS_CMAC)
   if(request.algo_name() == "CMAC" && request.arg_count() == 1)
      return new CMAC(af.make_block_cipher(request.arg(0)));
#endif

#if defined(BOTAN_HAS_HMAC)
   if(request.algo_name() == "HMAC" && request.arg_count() == 1)
      return new HMAC(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_SSL3_MAC)
   if(request.algo_name() == "SSL3-MAC" && request.arg_count() == 1)
      return new SSL3_MAC(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_ANSI_X919_MAC)
   if(request.algo_name() == "X9.19-MAC" && request.arg_count() == 0)
      return new ANSI_X919_MAC(af.make_block_cipher("DES"));
#endif

   return 0;
   }

}
/*
* PBKDF Lookup
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_PBKDF1)
#endif

#if defined(BOTAN_HAS_PBKDF2)
#endif

#if defined(BOTAN_HAS_PGPS2K)
#endif

namespace Botan {

PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec,
                               Algorithm_Factory& af) const
   {
#if defined(BOTAN_HAS_PBKDF1)
   if(algo_spec.algo_name() == "PBKDF1" && algo_spec.arg_count() == 1)
      return new PKCS5_PBKDF1(af.make_hash_function(algo_spec.arg(0)));
#endif

#if defined(BOTAN_HAS_PBKDF2)
   if(algo_spec.algo_name() == "PBKDF2" && algo_spec.arg_count() == 1)
      {
      if(const MessageAuthenticationCode* mac_proto = af.prototype_mac(algo_spec.arg(0)))
         return new PKCS5_PBKDF2(mac_proto->clone());

      return new PKCS5_PBKDF2(af.make_mac("HMAC(" + algo_spec.arg(0) + ")"));
      }
#endif

#if defined(BOTAN_HAS_PGPS2K)
   if(algo_spec.algo_name() == "OpenPGP-S2K" && algo_spec.arg_count() == 1)
      return new OpenPGP_S2K(af.make_hash_function(algo_spec.arg(0)));
#endif

   return 0;
   }

}
/*
* Stream Cipher Lookup
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_ARC4)
#endif

#if defined(BOTAN_HAS_SALSA20)
#endif

#if defined(BOTAN_HAS_TURING)
#endif

#if defined(BOTAN_HAS_WID_WAKE)
#endif

namespace Botan {

/*
* Look for an algorithm with this name
*/
StreamCipher*
Core_Engine::find_stream_cipher(const SCAN_Name& request,
                                Algorithm_Factory&) const
   {
#if defined(BOTAN_HAS_ARC4)
   if(request.algo_name() == "ARC4")
      return new ARC4(request.arg_as_integer(0, 0));
   if(request.algo_name() == "RC4_drop")
      return new ARC4(768);
#endif

#if defined(BOTAN_HAS_SALSA20)
   if(request.algo_name() == "Salsa20")
      return new Salsa20;
#endif

#if defined(BOTAN_HAS_TURING)
   if(request.algo_name() == "Turing")
      return new Turing;
#endif

#if defined(BOTAN_HAS_WID_WAKE)
   if(request.algo_name() == "WiderWake4+1-BE")
      return new WiderWake_41_BE;
#endif

   return 0;
   }

}
/**
* Dynamically Loaded Engine
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

extern "C" {
   typedef Engine* (*creator_func)(void);
   typedef u32bit (*module_version_func)(void);
}

}

Dynamically_Loaded_Engine::Dynamically_Loaded_Engine(
   const std::string& library_path) :
   engine(0)
   {
   lib = new Dynamically_Loaded_Library(library_path);

   try
      {
      module_version_func get_version =
         lib->resolve<module_version_func>("module_version");

      const u32bit mod_version = get_version();

      if(mod_version != 20101003)
         throw std::runtime_error("Incompatible version in " +
                                  library_path + " of " +
                                  to_string(mod_version));

      creator_func creator =
         lib->resolve<creator_func>("create_engine");

      engine = creator();

      if(!engine)
         throw std::runtime_error("Creator function in " +
                                  library_path + " failed");
      }
   catch(...)
      {
      delete lib;
      lib = 0;
      throw;
      }
   }

Dynamically_Loaded_Engine::~Dynamically_Loaded_Engine()
   {
   delete engine;
   delete lib;
   }

}
/*
* Engine
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

BlockCipher*
Engine::find_block_cipher(const SCAN_Name&,
                          Algorithm_Factory&) const
   {
   return 0;
   }

StreamCipher*
Engine::find_stream_cipher(const SCAN_Name&,
                           Algorithm_Factory&) const
   {
   return 0;
   }

HashFunction*
Engine::find_hash(const SCAN_Name&,
                  Algorithm_Factory&) const
   {
   return 0;
   }

MessageAuthenticationCode*
Engine::find_mac(const SCAN_Name&,
                 Algorithm_Factory&) const
   {
   return 0;
   }

PBKDF*
Engine::find_pbkdf(const SCAN_Name&,
                   Algorithm_Factory&) const
   {
   return 0;
   }

Modular_Exponentiator*
Engine::mod_exp(const BigInt&,
                Power_Mod::Usage_Hints) const
   {
   return 0;
   }

Keyed_Filter* Engine::get_cipher(const std::string&,
                                 Cipher_Dir,
                                 Algorithm_Factory&)
   {
   return 0;
   }

PK_Ops::Key_Agreement*
Engine::get_key_agreement_op(const Private_Key&) const
   {
   return 0;
   }

PK_Ops::Signature*
Engine::get_signature_op(const Private_Key&) const
   {
   return 0;
   }

PK_Ops::Verification*
Engine::get_verify_op(const Public_Key&) const
   {
   return 0;
   }

PK_Ops::Encryption*
Engine::get_encryption_op(const Public_Key&) const
   {
   return 0;
   }

PK_Ops::Decryption*
Engine::get_decryption_op(const Private_Key&) const
   {
   return 0;
   }

}
/*
* SIMD Engine
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_AES_SSSE3)
#endif

#if defined(BOTAN_HAS_SERPENT_SIMD)
#endif

#if defined(BOTAN_HAS_NOEKEON_SIMD)
#endif

#if defined(BOTAN_HAS_XTEA_SIMD)
#endif

#if defined(BOTAN_HAS_IDEA_SSE2)
#endif

#if defined(BOTAN_HAS_SHA1_SSE2)
#endif

namespace Botan {

BlockCipher*
SIMD_Engine::find_block_cipher(const SCAN_Name& request,
                               Algorithm_Factory&) const
   {
#if defined(BOTAN_HAS_AES_SSSE3)
   if(request.algo_name() == "AES-128" && CPUID::has_ssse3())
      return new AES_128_SSSE3;
   if(request.algo_name() == "AES-192" && CPUID::has_ssse3())
      return new AES_192_SSSE3;
   if(request.algo_name() == "AES-256" && CPUID::has_ssse3())
      return new AES_256_SSSE3;
#endif

#if defined(BOTAN_HAS_IDEA_SSE2)
   if(request.algo_name() == "IDEA" && CPUID::has_sse2())
      return new IDEA_SSE2;
#endif

#if defined(BOTAN_HAS_NOEKEON_SIMD)
   if(request.algo_name() == "Noekeon" && SIMD_32::enabled())
      return new Noekeon_SIMD;
#endif

#if defined(BOTAN_HAS_SERPENT_SIMD)
   if(request.algo_name() == "Serpent" && SIMD_32::enabled())
      return new Serpent_SIMD;
#endif

#if defined(BOTAN_HAS_XTEA_SIMD)
   if(request.algo_name() == "XTEA" && SIMD_32::enabled())
      return new XTEA_SIMD;
#endif

   return 0;
   }

HashFunction*
SIMD_Engine::find_hash(const SCAN_Name& request,
                       Algorithm_Factory&) const
   {
#if defined(BOTAN_HAS_SHA1_SSE2)
   if(request.algo_name() == "SHA-160" && CPUID::has_sse2())
      return new SHA_160_SSE2;
#else
    Q_UNUSED(request);
#endif

   return 0;
   }

}

#ifdef Q_OS_WIN
/*
* Win32 CryptoAPI EntropySource
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <windows.h>
#include <wincrypt.h>

namespace Botan {

namespace {

class CSP_Handle
   {
   public:
      CSP_Handle(u64bit capi_provider)
         {
         valid = false;
         DWORD prov_type = (DWORD)capi_provider;

         if(CryptAcquireContext(&handle, 0, 0,
                                prov_type, CRYPT_VERIFYCONTEXT))
            valid = true;
         }

      ~CSP_Handle()
         {
         if(is_valid())
            CryptReleaseContext(handle, 0);
         }

      size_t gen_random(byte out[], size_t n) const
         {
         if(is_valid() && CryptGenRandom(handle, static_cast<DWORD>(n), out))
            return n;
         return 0;
         }

      bool is_valid() const { return valid; }

      HCRYPTPROV get_handle() const { return handle; }
   private:
      HCRYPTPROV handle;
      bool valid;
   };

}

/*
* Gather Entropy from Win32 CAPI
*/
void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
   {
   MemoryRegion<byte>& io_buffer = accum.get_io_buffer(32);

   for(size_t i = 0; i != prov_types.size(); ++i)
      {
      CSP_Handle csp(prov_types[i]);

      size_t got = csp.gen_random(&io_buffer[0], io_buffer.size());

      if(got)
         {
         accum.add(&io_buffer[0], io_buffer.size(), 6);
         break;
         }
      }
   }

/*
* Win32_Capi_Entropysource Constructor
*/
Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs)
   {
   std::vector<std::string> capi_provs = split_on(provs, ':');

   for(size_t i = 0; i != capi_provs.size(); ++i)
      {
      if(capi_provs[i] == "RSA_FULL")  prov_types.push_back(PROV_RSA_FULL);
      if(capi_provs[i] == "INTEL_SEC") prov_types.push_back(PROV_INTEL_SEC);
      if(capi_provs[i] == "FORTEZZA")  prov_types.push_back(PROV_FORTEZZA);
      if(capi_provs[i] == "RNG")       prov_types.push_back(PROV_RNG);
      }

   if(prov_types.size() == 0)
      prov_types.push_back(PROV_RSA_FULL);
   }

}
#endif

#ifdef Q_OS_UNIX
/*
* /dev/random EntropySource
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#include <sys/types.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

namespace Botan {

/**
Close the device, if open
*/
void Device_EntropySource::Device_Reader::close()
   {
   if(fd > 0) { ::close(fd); fd = -1; }
   }

/**
Read bytes from a device file
*/
size_t Device_EntropySource::Device_Reader::get(byte out[], size_t length,
                                                size_t ms_wait_time)
   {
   if(fd < 0)
      return 0;

   if(fd >= FD_SETSIZE)
      return 0;

   fd_set read_set;
   FD_ZERO(&read_set);
   FD_SET(fd, &read_set);

   struct ::timeval timeout;

   timeout.tv_sec = (ms_wait_time / 1000);
   timeout.tv_usec = (ms_wait_time % 1000) * 1000;

   if(::select(fd + 1, &read_set, 0, 0, &timeout) < 0)
      return 0;

   if(!(FD_ISSET(fd, &read_set)))
      return 0;

   const ssize_t got = ::read(fd, out, length);
   if(got <= 0)
      return 0;

   return static_cast<size_t>(got);
   }

/**
Attempt to open a device
*/
Device_EntropySource::Device_Reader::fd_type
Device_EntropySource::Device_Reader::open(const std::string& pathname)
   {
#ifndef O_NONBLOCK
  #define O_NONBLOCK 0
#endif

#ifndef O_NOCTTY
  #define O_NOCTTY 0
#endif

   const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY;
   return ::open(pathname.c_str(), flags);
   }

/**
Device_EntropySource constructor
Open a file descriptor to each (available) device in fsnames
*/
Device_EntropySource::Device_EntropySource(
   const std::vector<std::string>& fsnames)
   {
   for(size_t i = 0; i != fsnames.size(); ++i)
      {
      Device_Reader::fd_type fd = Device_Reader::open(fsnames[i]);
      if(fd > 0)
         devices.push_back(Device_Reader(fd));
      }
   }

/**
Device_EntropySource destructor: close all open devices
*/
Device_EntropySource::~Device_EntropySource()
   {
   for(size_t i = 0; i != devices.size(); ++i)
      devices[i].close();
   }

/**
* Gather entropy from a RNG device
*/
void Device_EntropySource::poll(Entropy_Accumulator& accum)
   {
   const size_t ENTROPY_BITS_PER_BYTE = 7;

   const size_t go_get = std::min<size_t>(
      accum.desired_remaining_bits() / ENTROPY_BITS_PER_BYTE, 32);

   const size_t read_wait_ms = std::max<size_t>(go_get, 100);
   MemoryRegion<byte>& io_buffer = accum.get_io_buffer(go_get);

   for(size_t i = 0; i != devices.size(); ++i)
      {
      size_t got = devices[i].get(&io_buffer[0], io_buffer.size(),
                                  read_wait_ms);

      if(got)
         {
         accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE);
         break;
         }
      }
   }

}

/*
* EGD EntropySource
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <cstring>
#include <stdexcept>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/un.h>

#ifndef PF_LOCAL
  #define PF_LOCAL PF_UNIX
#endif

namespace Botan {

EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) :
   socket_path(path), m_fd(-1)
   {
   }

/**
* Attempt a connection to an EGD/PRNGD socket
*/
int EGD_EntropySource::EGD_Socket::open_socket(const std::string& path)
   {
   int fd = ::socket(PF_LOCAL, SOCK_STREAM, 0);

   if(fd >= 0)
      {
      sockaddr_un addr;
      std::memset(&addr, 0, sizeof(addr));
      addr.sun_family = PF_LOCAL;

      if(sizeof(addr.sun_path) < path.length() + 1)
         throw std::invalid_argument("EGD socket path is too long");

      std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));

      int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1;

      if(::connect(fd, reinterpret_cast<struct ::sockaddr*>(&addr), len) < 0)
         {
         ::close(fd);
         fd = -1;
         }
      }

   return fd;
   }

/**
* Attempt to read entropy from EGD
*/
size_t EGD_EntropySource::EGD_Socket::read(byte outbuf[], size_t length)
   {
   if(length == 0)
      return 0;

   if(m_fd < 0)
      {
      m_fd = open_socket(socket_path);
      if(m_fd < 0)
         return 0;
      }

   try
      {
      // 1 == EGD command for non-blocking read
      byte egd_read_command[2] = {
         1, static_cast<byte>(std::min<size_t>(length, 255)) };

      if(::write(m_fd, egd_read_command, 2) != 2)
         throw std::runtime_error("Writing entropy read command to EGD failed");

      byte out_len = 0;
      if(::read(m_fd, &out_len, 1) != 1)
         throw std::runtime_error("Reading response length from EGD failed");

      if(out_len > egd_read_command[1])
         throw std::runtime_error("Bogus length field received from EGD");

      ssize_t count = ::read(m_fd, outbuf, out_len);

      if(count != out_len)
         throw std::runtime_error("Reading entropy result from EGD failed");

      return static_cast<size_t>(count);
      }
   catch(std::exception)
      {
      this->close();
      // Will attempt to reopen next poll
      }

   return 0;
   }

void EGD_EntropySource::EGD_Socket::close()
   {
   if(m_fd > 0)
      {
      ::close(m_fd);
      m_fd = -1;
      }
   }

/**
* EGD_EntropySource constructor
*/
EGD_EntropySource::EGD_EntropySource(const std::vector<std::string>& paths)
   {
   for(size_t i = 0; i != paths.size(); ++i)
      sockets.push_back(EGD_Socket(paths[i]));
   }

EGD_EntropySource::~EGD_EntropySource()
   {
   for(size_t i = 0; i != sockets.size(); ++i)
      sockets[i].close();
   sockets.clear();
   }

/**
* Gather Entropy from EGD
*/
void EGD_EntropySource::poll(Entropy_Accumulator& accum)
   {
   size_t go_get = std::min<size_t>(accum.desired_remaining_bits() / 8, 32);

   MemoryRegion<byte>& io_buffer = accum.get_io_buffer(go_get);

   for(size_t i = 0; i != sockets.size(); ++i)
      {
      size_t got = sockets[i].read(&io_buffer[0], io_buffer.size());

      if(got)
         {
         accum.add(&io_buffer[0], got, 6);
         break;
         }
      }
   }

}
#endif

/*
* High Resolution Timestamp Entropy Source
* (C) 1999-2009,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_TARGET_OS_IS_WINDOWS)
  #include <windows.h>
#endif

namespace Botan {

/*
* Get the timestamp
*/
void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum)
   {
   // If Windows, grab the Performance Counter (usually TSC or PIT)
#if defined(BOTAN_TARGET_OS_IS_WINDOWS)
   {
   LARGE_INTEGER tv;
   ::QueryPerformanceCounter(&tv);
   accum.add(tv.QuadPart, 0);
   }
#endif

#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)

#define CLOCK_POLL(src)                     \
   do {                                     \
     struct timespec ts;                    \
     clock_gettime(src, &ts);               \
     accum.add(&ts, sizeof(ts), 0);         \
   } while(0)

#if defined(CLOCK_REALTIME)
   CLOCK_POLL(CLOCK_REALTIME);
#endif

#if defined(CLOCK_MONOTONIC)
   CLOCK_POLL(CLOCK_MONOTONIC);
#endif

#if defined(CLOCK_MONOTONIC_RAW)
   CLOCK_POLL(CLOCK_MONOTONIC_RAW);
#endif

#if defined(CLOCK_PROCESS_CPUTIME_ID)
   CLOCK_POLL(CLOCK_PROCESS_CPUTIME_ID);
#endif

#if defined(CLOCK_THREAD_CPUTIME_ID)
   CLOCK_POLL(CLOCK_THREAD_CPUTIME_ID);
#endif

#undef CLOCK_POLL

#endif

#if BOTAN_USE_GCC_INLINE_ASM

   u64bit rtc = 0;

#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
   if(CPUID::has_rdtsc()) // not availble on all x86 CPUs
      {
      u32bit rtc_low = 0, rtc_high = 0;
      asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low));
      rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low;
      }

#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
   u32bit rtc_low = 0, rtc_high = 0;
   asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low));
   rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low;

#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA)
   asm volatile("rpcc %0" : "=r" (rtc));

#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD)
   asm volatile("rd %%tick, %0" : "=r" (rtc));

#elif defined(BOTAN_TARGET_ARCH_IS_IA64)
   asm volatile("mov %0=ar.itc" : "=r" (rtc));

#elif defined(BOTAN_TARGET_ARCH_IS_S390X)
   asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc");

#elif defined(BOTAN_TARGET_ARCH_IS_HPPA)
   asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only?

#endif

   // Don't count the timestamp as contributing entropy
   accum.add(rtc, 0);

#endif
   }

}

#ifdef Q_OS_UNIX
/*
* FTW EntropySource
* (C) 1999-2008,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <cstring>
#include <deque>

#ifndef _POSIX_C_SOURCE
  #define _POSIX_C_SOURCE 199309
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>

namespace Botan {

/**
* Returns file descriptors. Until it doesn't
*/
class File_Descriptor_Source
   {
   public:
      /**
      * @return next file descriptor, or -1 if done
      */
      virtual int next_fd() = 0;

      virtual ~File_Descriptor_Source() {}
   };

namespace {

class Directory_Walker : public File_Descriptor_Source
   {
   public:
      Directory_Walker(const std::string& root) :
         m_cur_dir(std::make_pair<DIR*, std::string>(0, ""))
         {
         if(DIR* root_dir = ::opendir(root.c_str()))
            m_cur_dir = std::make_pair(root_dir, root);
         }

      ~Directory_Walker()
         {
         if(m_cur_dir.first)
            ::closedir(m_cur_dir.first);
         }

      int next_fd();
   private:
      void add_directory(const std::string& dirname)
         {
         m_dirlist.push_back(dirname);
         }

      std::pair<struct dirent*, std::string> get_next_dirent();

      std::pair<DIR*, std::string> m_cur_dir;
      std::deque<std::string> m_dirlist;
   };

std::pair<struct dirent*, std::string> Directory_Walker::get_next_dirent()
   {
   while(m_cur_dir.first)
      {
      struct dirent* dir = ::readdir(m_cur_dir.first);

      if(dir)
         return std::make_pair<struct dirent*, std::string>(dir, m_cur_dir.second);

      ::closedir(m_cur_dir.first);
      m_cur_dir = std::make_pair<DIR*, std::string>(0, "");

      while(!m_dirlist.empty() && m_cur_dir.first == 0)
         {
         const std::string next_dir_name = m_dirlist[0];
         m_dirlist.pop_front();

         if(DIR* next_dir = ::opendir(next_dir_name.c_str()))
            m_cur_dir = std::make_pair(next_dir, next_dir_name);
         }
      }

   return std::make_pair<struct dirent*, std::string>(0, ""); // nothing left
   }

int Directory_Walker::next_fd()
   {
   while(true)
      {
      std::pair<struct dirent*, std::string> entry = get_next_dirent();

      if(!entry.first)
         break; // no more dirs

      const std::string filename = entry.first->d_name;

      if(filename == "." || filename == "..")
         continue;

      const std::string full_path = entry.second + '/' + filename;

      struct stat stat_buf;
      if(::lstat(full_path.c_str(), &stat_buf) == -1)
         continue;

      if(S_ISDIR(stat_buf.st_mode))
         {
         add_directory(full_path);
         }
      else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH))
         {
         int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY);

         if(fd > 0)
            return fd;
         }
      }

   return -1;
   }

}

/**
* FTW_EntropySource Constructor
*/
FTW_EntropySource::FTW_EntropySource(const std::string& p) : path(p)
   {
   dir = 0;
   }

/**
* FTW_EntropySource Destructor
*/
FTW_EntropySource::~FTW_EntropySource()
   {
   delete dir;
   }

void FTW_EntropySource::poll(Entropy_Accumulator& accum)
   {
   const size_t MAX_FILES_READ_PER_POLL = 2048;

   if(!dir)
      dir = new Directory_Walker(path);

   MemoryRegion<byte>& io_buffer = accum.get_io_buffer(4096);

   for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i)
      {
      int fd = dir->next_fd();

      // If we've exhaused this walk of the directory, halt the poll
      if(fd == -1)
         {
         delete dir;
         dir = 0;
         break;
         }

      ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size());
      ::close(fd);

      if(got > 0)
         accum.add(&io_buffer[0], got, .001);

      if(accum.polling_goal_achieved())
         break;
      }
   }

}

/*
* Unix EntropySource
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <unistd.h>

namespace Botan {

namespace {

/**
* Sort ordering by priority
*/
bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b)
   {
   if(a.priority == b.priority)
      return (a.name_and_args < b.name_and_args);

   return (a.priority < b.priority);
   }

}

/**
* Unix_EntropySource Constructor
*/
Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& path) :
   PATH(path)
   {
   std::vector<Unix_Program> default_sources = get_default_sources();
   add_sources(&default_sources[0], default_sources.size());
   }

/**
* Add sources to the list
*/
void Unix_EntropySource::add_sources(const Unix_Program srcs[], size_t count)
   {
   sources.insert(sources.end(), srcs, srcs + count);
   std::sort(sources.begin(), sources.end(), Unix_Program_Cmp);
   }

/**
* Poll for entropy on a generic Unix system, first by grabbing various
* statistics (stat on common files, getrusage, etc), and then, if more
* is required, by exec'ing various programs like uname and rpcinfo and
* reading the output.
*/
void Unix_EntropySource::poll(Entropy_Accumulator& accum)
   {
   const char* stat_targets[] = {
      "/",
      "/tmp",
      "/var/tmp",
      "/usr",
      "/home",
      "/etc/passwd",
      ".",
      "..",
      0 };

   for(size_t i = 0; stat_targets[i]; i++)
      {
      struct stat statbuf;
      clear_mem(&statbuf, 1);
      ::stat(stat_targets[i], &statbuf);
      accum.add(&statbuf, sizeof(statbuf), .005);
      }

   accum.add(::getpid(),  0);
   accum.add(::getppid(), 0);
   accum.add(::getuid(),  0);
   accum.add(::getgid(), 0);
   accum.add(::getpgrp(), 0);

   struct ::rusage usage;
   ::getrusage(RUSAGE_SELF, &usage);
   accum.add(usage, .005);

   ::getrusage(RUSAGE_CHILDREN, &usage);
   accum.add(usage, .005);

   const size_t MINIMAL_WORKING = 16;

   MemoryRegion<byte>& io_buffer = accum.get_io_buffer(DEFAULT_BUFFERSIZE);

   for(size_t i = 0; i != sources.size(); i++)
      {
      DataSource_Command pipe(sources[i].name_and_args, PATH);

      size_t got_from_src = 0;

      while(!pipe.end_of_data())
         {
         size_t got_this_loop = pipe.read(&io_buffer[0], io_buffer.size());
         got_from_src += got_this_loop;

         accum.add(&io_buffer[0], got_this_loop, .005);
         }

      sources[i].working = (got_from_src >= MINIMAL_WORKING) ? true : false;

      if(accum.polling_goal_achieved())
         break;
      }
   }

}
/*
* Unix Command Execution
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

namespace Botan {

namespace {

/**
* Attempt to execute the command
*/
void do_exec(const std::vector<std::string>& arg_list,
             const std::vector<std::string>& paths)
   {
   const size_t args = arg_list.size() - 1;

   const char* arg1 = (args >= 1) ? arg_list[1].c_str() : 0;
   const char* arg2 = (args >= 2) ? arg_list[2].c_str() : 0;
   const char* arg3 = (args >= 3) ? arg_list[3].c_str() : 0;
   const char* arg4 = (args >= 4) ? arg_list[4].c_str() : 0;

   for(size_t j = 0; j != paths.size(); j++)
      {
      const std::string full_path = paths[j] + "/" + arg_list[0];
      const char* fsname = full_path.c_str();

      ::execl(fsname, fsname, arg1, arg2, arg3, arg4, NULL);
      }
   }

}

/**
* Local information about the pipe
*/
struct pipe_wrapper
   {
   int fd;
   pid_t pid;

   pipe_wrapper(int f, pid_t p) : fd(f), pid(p) {}
   ~pipe_wrapper() { ::close(fd); }
   };

/**
* Read from the pipe
*/
size_t DataSource_Command::read(byte buf[], size_t length)
   {
   if(end_of_data())
      return 0;

   fd_set set;
   FD_ZERO(&set);
   FD_SET(pipe->fd, &set);

   struct ::timeval tv;
   tv.tv_sec = 0;
   tv.tv_usec = MAX_BLOCK_USECS;

   ssize_t got = 0;
   if(::select(pipe->fd + 1, &set, 0, 0, &tv) == 1)
      {
      if(FD_ISSET(pipe->fd, &set))
         got = ::read(pipe->fd, buf, length);
      }

   if(got <= 0)
      {
      shutdown_pipe();
      return 0;
      }

   return static_cast<size_t>(got);
   }

/**
* Peek at the pipe contents
*/
size_t DataSource_Command::peek(byte[], size_t, size_t) const
   {
   if(end_of_data())
      throw Invalid_State("DataSource_Command: Cannot peek when out of data");
   throw Stream_IO_Error("Cannot peek/seek on a command pipe");
   }

/**
* Check if we reached EOF
*/
bool DataSource_Command::end_of_data() const
   {
   return (pipe) ? false : true;
   }

/**
* Return the Unix file descriptor of the pipe
*/
int DataSource_Command::fd() const
   {
   if(!pipe)
      return -1;
   return pipe->fd;
   }

/**
* Return a human-readable ID for this stream
*/
std::string DataSource_Command::id() const
   {
   return "Unix command: " + arg_list[0];
   }

/**
* Create the pipe
*/
void DataSource_Command::create_pipe(const std::vector<std::string>& paths)
   {
   bool found_something = false;

   for(size_t j = 0; j != paths.size(); j++)
      {
      const std::string full_path = paths[j] + "/" + arg_list[0];
      if(::access(full_path.c_str(), X_OK) == 0)
         {
         found_something = true;
         break;
         }
      }

   if(!found_something)
      return;

   int pipe_fd[2];
   if(::pipe(pipe_fd) != 0)
      return;

   pid_t pid = ::fork();

   if(pid == -1)
      {
      ::close(pipe_fd[0]);
      ::close(pipe_fd[1]);
      }
   else if(pid > 0)
      {
      pipe = new pipe_wrapper(pipe_fd[0], pid);
      ::close(pipe_fd[1]);
      }
   else
      {
      if(dup2(pipe_fd[1], STDOUT_FILENO) == -1)
         ::exit(127);
      if(close(pipe_fd[0]) != 0 || close(pipe_fd[1]) != 0)
         ::exit(127);
      if(close(STDERR_FILENO) != 0)
         ::exit(127);

      do_exec(arg_list, paths);
      ::exit(127);
      }
   }

/**
* Shutdown the pipe
*/
void DataSource_Command::shutdown_pipe()
   {
   if(pipe)
      {
      pid_t reaped = waitpid(pipe->pid, 0, WNOHANG);

      if(reaped == 0)
         {
         kill(pipe->pid, SIGTERM);

         struct ::timeval tv;
         tv.tv_sec = 0;
         tv.tv_usec = KILL_WAIT;
         select(0, 0, 0, 0, &tv);

         reaped = ::waitpid(pipe->pid, 0, WNOHANG);

         if(reaped == 0)
            {
            ::kill(pipe->pid, SIGKILL);
            do
               reaped = ::waitpid(pipe->pid, 0, 0);
            while(reaped == -1);
            }
         }

      delete pipe;
      pipe = 0;
      }
   }

/**
* DataSource_Command Constructor
*/
DataSource_Command::DataSource_Command(const std::string& prog_and_args,
                                       const std::vector<std::string>& paths) :
   MAX_BLOCK_USECS(100000), KILL_WAIT(10000)
   {
   arg_list = split_on(prog_and_args, ' ');

   if(arg_list.size() == 0)
      throw Invalid_Argument("DataSource_Command: No command given");
   if(arg_list.size() > 5)
      throw Invalid_Argument("DataSource_Command: Too many args");

   pipe = 0;
   create_pipe(paths);
   }

/**
* DataSource_Command Destructor
*/
DataSource_Command::~DataSource_Command()
   {
   if(!end_of_data())
      shutdown_pipe();
   }

}
/*
* Program List for Unix_EntropySource
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/**
* Default Commands for Entropy Gathering
*/
std::vector<Unix_Program> Unix_EntropySource::get_default_sources()
   {
   std::vector<Unix_Program> srcs;

   srcs.push_back(Unix_Program("netstat -in",           1));
   srcs.push_back(Unix_Program("pfstat",                1));
   srcs.push_back(Unix_Program("vmstat -s",             1));
   srcs.push_back(Unix_Program("vmstat",                1));

   srcs.push_back(Unix_Program("arp -a -n",             2));
   srcs.push_back(Unix_Program("ifconfig -a",           2));
   srcs.push_back(Unix_Program("iostat",                2));
   srcs.push_back(Unix_Program("ipcs -a",               2));
   srcs.push_back(Unix_Program("mpstat",                2));
   srcs.push_back(Unix_Program("netstat -an",           2));
   srcs.push_back(Unix_Program("netstat -s",            2));
   srcs.push_back(Unix_Program("nfsstat",               2));
   srcs.push_back(Unix_Program("portstat",              2));
   srcs.push_back(Unix_Program("procinfo -a",           2));
   srcs.push_back(Unix_Program("pstat -T",              2));
   srcs.push_back(Unix_Program("pstat -s",              2));
   srcs.push_back(Unix_Program("uname -a",              2));
   srcs.push_back(Unix_Program("uptime",                2));

   srcs.push_back(Unix_Program("listarea",              3));
   srcs.push_back(Unix_Program("listdev",               3));
   srcs.push_back(Unix_Program("ps -A",                 3));
   srcs.push_back(Unix_Program("sysinfo",               3));

   srcs.push_back(Unix_Program("finger",                4));
   srcs.push_back(Unix_Program("mailstats",             4));
   srcs.push_back(Unix_Program("rpcinfo -p localhost",  4));
   srcs.push_back(Unix_Program("who",                   4));

   srcs.push_back(Unix_Program("df -l",                 4));
   srcs.push_back(Unix_Program("dmesg",                 4));
   srcs.push_back(Unix_Program("last -5",               4));
   srcs.push_back(Unix_Program("ls -alni /proc",        4));
   srcs.push_back(Unix_Program("ls -alni /tmp",         4));
   srcs.push_back(Unix_Program("pstat -f",              4));

   srcs.push_back(Unix_Program("ps -elf",               5));
   srcs.push_back(Unix_Program("ps aux",                5));

   srcs.push_back(Unix_Program("lsof -n",               6));
   srcs.push_back(Unix_Program("sar -A",                6));

   return srcs;
   }

}
#endif

#ifdef Q_OS_WIN
/*
* Win32 EntropySource
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <windows.h>
#include <tlhelp32.h>

namespace Botan {

/**
* Win32 poll using stats functions including Tooltip32
*/
void Win32_EntropySource::poll(Entropy_Accumulator& accum)
   {
   /*
   First query a bunch of basic statistical stuff, though
   don't count it for much in terms of contributed entropy.
   */
   accum.add(GetTickCount(), 0);
   accum.add(GetMessagePos(), 0);
   accum.add(GetMessageTime(), 0);
   accum.add(GetInputState(), 0);
   accum.add(GetCurrentProcessId(), 0);
   accum.add(GetCurrentThreadId(), 0);

   SYSTEM_INFO sys_info;
   GetSystemInfo(&sys_info);
   accum.add(sys_info, 1);

   MEMORYSTATUS mem_info;
   GlobalMemoryStatus(&mem_info);
   accum.add(mem_info, 1);

   POINT point;
   GetCursorPos(&point);
   accum.add(point, 1);

   GetCaretPos(&point);
   accum.add(point, 1);

   LARGE_INTEGER perf_counter;
   QueryPerformanceCounter(&perf_counter);
   accum.add(perf_counter, 0);

   /*
   Now use the Tooltip library to iterate throug various objects on
   the system, including processes, threads, and heap objects.
   */

   HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);

#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \
   if(!accum.polling_goal_achieved())                     \
      {                                                   \
      DATA_TYPE info;                                     \
      info.dwSize = sizeof(DATA_TYPE);                    \
      if(FUNC_FIRST(snapshot, &info))                     \
         {                                                \
         do                                               \
            {                                             \
            accum.add(info, 1);                           \
            } while(FUNC_NEXT(snapshot, &info));          \
         }                                                \
      }

   TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next);
   TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next);
   TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next);

#undef TOOLHELP32_ITER

   if(!accum.polling_goal_achieved())
      {
      size_t heap_lists_found = 0;
      HEAPLIST32 heap_list;
      heap_list.dwSize = sizeof(HEAPLIST32);

      const size_t HEAP_LISTS_MAX = 32;
      const size_t HEAP_OBJS_PER_LIST = 128;

      if(Heap32ListFirst(snapshot, &heap_list))
         {
         do
            {
            accum.add(heap_list, 1);

            if(++heap_lists_found > HEAP_LISTS_MAX)
               break;

            size_t heap_objs_found = 0;
            HEAPENTRY32 heap_entry;
            heap_entry.dwSize = sizeof(HEAPENTRY32);
            if(Heap32First(&heap_entry, heap_list.th32ProcessID,
                           heap_list.th32HeapID))
               {
               do
                  {
                  if(heap_objs_found++ > HEAP_OBJS_PER_LIST)
                     break;
                  accum.add(heap_entry, 1);
                  } while(Heap32Next(&heap_entry));
               }

            if(accum.polling_goal_achieved())
               break;

            } while(Heap32ListNext(snapshot, &heap_list));
         }
      }

   CloseHandle(snapshot);
   }

}
#endif

/*
* Filters
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* StreamCipher_Filter Constructor
*/
StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher) :
   buffer(DEFAULT_BUFFERSIZE)
   {
   cipher = stream_cipher;
   }

/*
* StreamCipher_Filter Constructor
*/
StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher,
                                         const SymmetricKey& key) :
   buffer(DEFAULT_BUFFERSIZE)
   {
   cipher = stream_cipher;
   cipher->set_key(key);
   }

/*
* StreamCipher_Filter Constructor
*/
StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) :
   buffer(DEFAULT_BUFFERSIZE)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();
   cipher = af.make_stream_cipher(sc_name);
   }

/*
* StreamCipher_Filter Constructor
*/
StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name,
                                         const SymmetricKey& key) :
   buffer(DEFAULT_BUFFERSIZE)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();
   cipher = af.make_stream_cipher(sc_name);
   cipher->set_key(key);
   }

/*
* Set the IV of a stream cipher
*/
void StreamCipher_Filter::set_iv(const InitializationVector& iv)
   {
   cipher->set_iv(iv.begin(), iv.length());
   }

/*
* Write data into a StreamCipher_Filter
*/
void StreamCipher_Filter::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t copied = std::min<size_t>(length, buffer.size());
      cipher->cipher(input, &buffer[0], copied);
      send(buffer, copied);
      input += copied;
      length -= copied;
      }
   }

/*
* Hash_Filter Constructor
*/
Hash_Filter::Hash_Filter(const std::string& algo_spec,
                         size_t len) :
   OUTPUT_LENGTH(len)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();
   hash = af.make_hash_function(algo_spec);
   }

/*
* Complete a calculation by a Hash_Filter
*/
void Hash_Filter::end_msg()
   {
   SecureVector<byte> output = hash->final();
   if(OUTPUT_LENGTH)
      send(output, std::min<size_t>(OUTPUT_LENGTH, output.size()));
   else
      send(output);
   }

/*
* MAC_Filter Constructor
*/
MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) :
   OUTPUT_LENGTH(len)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();
   mac = af.make_mac(mac_name);
   }

/*
* MAC_Filter Constructor
*/
MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key,
                       size_t len) : OUTPUT_LENGTH(len)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();
   mac = af.make_mac(mac_name);
   mac->set_key(key);
   }

/*
* Complete a calculation by a MAC_Filter
*/
void MAC_Filter::end_msg()
   {
   SecureVector<byte> output = mac->final();
   if(OUTPUT_LENGTH)
      send(output, std::min<size_t>(OUTPUT_LENGTH, output.size()));
   else
      send(output);
   }

}
/*
* Basic Filters
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

void Keyed_Filter::set_iv(const InitializationVector& iv)
   {
   if(iv.length() != 0)
      throw Invalid_IV_Length(name(), iv.length());
   }

/*
* Chain Constructor
*/
Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
   {
   if(f1) { attach(f1); incr_owns(); }
   if(f2) { attach(f2); incr_owns(); }
   if(f3) { attach(f3); incr_owns(); }
   if(f4) { attach(f4); incr_owns(); }
   }

/*
* Chain Constructor
*/
Chain::Chain(Filter* filters[], size_t count)
   {
   for(size_t j = 0; j != count; ++j)
      if(filters[j])
         {
         attach(filters[j]);
         incr_owns();
         }
   }

std::string Chain::name() const
   {
   return "Chain";
   }

/*
* Fork Constructor
*/
Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
   {
   Filter* filters[4] = { f1, f2, f3, f4 };
   set_next(filters, 4);
   }

/*
* Fork Constructor
*/
Fork::Fork(Filter* filters[], size_t count)
   {
   set_next(filters, count);
   }

std::string Fork::name() const
   {
   return "Fork";
   }

}
/*
* Buffered Filter
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

/*
* Buffered_Filter Constructor
*/
Buffered_Filter::Buffered_Filter(size_t b, size_t f) :
   main_block_mod(b), final_minimum(f)
   {
   if(main_block_mod == 0)
      throw std::invalid_argument("main_block_mod == 0");

   if(final_minimum > main_block_mod)
      throw std::invalid_argument("final_minimum > main_block_mod");

   buffer.resize(2 * main_block_mod);
   buffer_pos = 0;
   }

/*
* Buffer input into blocks, trying to minimize copying
*/
void Buffered_Filter::write(const byte input[], size_t input_size)
   {
   if(!input_size)
      return;

   if(buffer_pos + input_size >= main_block_mod + final_minimum)
      {
      size_t to_copy = std::min<size_t>(buffer.size() - buffer_pos, input_size);

      copy_mem(&buffer[buffer_pos], input, to_copy);
      buffer_pos += to_copy;

      input += to_copy;
      input_size -= to_copy;

      size_t total_to_consume =
         round_down(std::min(buffer_pos,
                             buffer_pos + input_size - final_minimum),
                    main_block_mod);

      buffered_block(&buffer[0], total_to_consume);

      buffer_pos -= total_to_consume;

      copy_mem(&buffer[0], &buffer[total_to_consume], buffer_pos);
      }

   if(input_size >= final_minimum)
      {
      size_t full_blocks = (input_size - final_minimum) / main_block_mod;
      size_t to_copy = full_blocks * main_block_mod;

      if(to_copy)
         {
         buffered_block(input, to_copy);

         input += to_copy;
         input_size -= to_copy;
         }
      }

   copy_mem(&buffer[buffer_pos], input, input_size);
   buffer_pos += input_size;
   }

/*
* Finish/flush operation
*/
void Buffered_Filter::end_msg()
   {
   if(buffer_pos < final_minimum)
      throw std::runtime_error("Buffered filter end_msg without enough input");

   size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod;

   if(spare_blocks)
      {
      size_t spare_bytes = main_block_mod * spare_blocks;
      buffered_block(&buffer[0], spare_bytes);
      buffered_final(&buffer[spare_bytes], buffer_pos - spare_bytes);
      }
   else
      {
      buffered_final(&buffer[0], buffer_pos);
      }

   buffer_pos = 0;
   }

}
/*
* Base64 Encoder/Decoder
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Base64_Encoder Constructor
*/
Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) :
   line_length(breaks ? length : 0),
   trailing_newline(t_n && breaks),
   in(48),
   out(64),
   position(0),
   out_position(0)
   {
   }

/*
* Encode and send a block
*/
void Base64_Encoder::encode_and_send(const byte input[], size_t length,
                                     bool final_inputs)
   {
   while(length)
      {
      const size_t proc = std::min(length, in.size());

      size_t consumed = 0;
      size_t produced = base64_encode(reinterpret_cast<char*>(&out[0]), input,
                                      proc, consumed, final_inputs);

      do_output(&out[0], produced);

      // FIXME: s/proc/consumed/?
      input += proc;
      length -= proc;
      }
   }

/*
* Handle the output
*/
void Base64_Encoder::do_output(const byte input[], size_t length)
   {
   if(line_length == 0)
      send(input, length);
   else
      {
      size_t remaining = length, offset = 0;
      while(remaining)
         {
         size_t sent = std::min(line_length - out_position, remaining);
         send(input + offset, sent);
         out_position += sent;
         remaining -= sent;
         offset += sent;
         if(out_position == line_length)
            {
            send('\n');
            out_position = 0;
            }
         }
      }
   }

/*
* Convert some data into Base64
*/
void Base64_Encoder::write(const byte input[], size_t length)
   {
   in.copy(position, input, length);
   if(position + length >= in.size())
      {
      encode_and_send(&in[0], in.size());
      input += (in.size() - position);
      length -= (in.size() - position);
      while(length >= in.size())
         {
         encode_and_send(input, in.size());
         input += in.size();
         length -= in.size();
         }
      in.copy(input, length);
      position = 0;
      }
   position += length;
   }

/*
* Flush buffers
*/
void Base64_Encoder::end_msg()
   {
   encode_and_send(&in[0], position, true);

   if(trailing_newline || (out_position && line_length))
      send('\n');

   out_position = position = 0;
   }

/*
* Base64_Decoder Constructor
*/
Base64_Decoder::Base64_Decoder(Decoder_Checking c) :
   checking(c), in(64), out(48), position(0)
   {
   }

/*
* Convert some data from Base64
*/
void Base64_Decoder::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t to_copy = std::min<size_t>(length, in.size() - position);
      copy_mem(&in[position], input, to_copy);
      position += to_copy;

      size_t consumed = 0;
      size_t written = base64_decode(&out[0],
                                     reinterpret_cast<const char*>(&in[0]),
                                     position,
                                     consumed,
                                     false,
                                     checking != FULL_CHECK);

      send(out, written);

      if(consumed != position)
         {
         copy_mem(&in[0], &in[consumed], position - consumed);
         position = position - consumed;
         }
      else
         position = 0;

      length -= to_copy;
      input += to_copy;
      }
   }

/*
* Flush buffers
*/
void Base64_Decoder::end_msg()
   {
   size_t consumed = 0;
   size_t written = base64_decode(&out[0],
                                  reinterpret_cast<const char*>(&in[0]),
                                  position,
                                  consumed,
                                  true,
                                  checking != FULL_CHECK);

   send(out, written);

   const bool not_full_bytes = consumed != position;

   position = 0;

   if(not_full_bytes)
      throw std::invalid_argument("Base64_Decoder: Input not full bytes");
   }

}
/*
* Hex Encoder/Decoder
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/**
* Size used for internal buffer in hex encoder/decoder
*/
const size_t HEX_CODEC_BUFFER_SIZE = 256;

/*
* Hex_Encoder Constructor
*/
Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) :
   casing(c), line_length(breaks ? length : 0)
   {
   in.resize(HEX_CODEC_BUFFER_SIZE);
   out.resize(2*in.size());
   counter = position = 0;
   }

/*
* Hex_Encoder Constructor
*/
Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0)
   {
   in.resize(HEX_CODEC_BUFFER_SIZE);
   out.resize(2*in.size());
   counter = position = 0;
   }

/*
* Encode and send a block
*/
void Hex_Encoder::encode_and_send(const byte block[], size_t length)
   {
   hex_encode(reinterpret_cast<char*>(&out[0]),
              block, length,
              casing == Uppercase);

   if(line_length == 0)
      send(out, 2*length);
   else
      {
      size_t remaining = 2*length, offset = 0;
      while(remaining)
         {
         size_t sent = std::min(line_length - counter, remaining);
         send(&out[offset], sent);
         counter += sent;
         remaining -= sent;
         offset += sent;
         if(counter == line_length)
            {
            send('\n');
            counter = 0;
            }
         }
      }
   }

/*
* Convert some data into hex format
*/
void Hex_Encoder::write(const byte input[], size_t length)
   {
   in.copy(position, input, length);
   if(position + length >= in.size())
      {
      encode_and_send(&in[0], in.size());
      input += (in.size() - position);
      length -= (in.size() - position);
      while(length >= in.size())
         {
         encode_and_send(input, in.size());
         input += in.size();
         length -= in.size();
         }
      in.copy(input, length);
      position = 0;
      }
   position += length;
   }

/*
* Flush buffers
*/
void Hex_Encoder::end_msg()
   {
   encode_and_send(&in[0], position);
   if(counter && line_length)
      send('\n');
   counter = position = 0;
   }

/*
* Hex_Decoder Constructor
*/
Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c)
   {
   in.resize(HEX_CODEC_BUFFER_SIZE);
   out.resize(in.size() / 2);
   position = 0;
   }

/*
* Convert some data from hex format
*/
void Hex_Decoder::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t to_copy = std::min<size_t>(length, in.size() - position);
      copy_mem(&in[position], input, to_copy);
      position += to_copy;

      size_t consumed = 0;
      size_t written = hex_decode(&out[0],
                                  reinterpret_cast<const char*>(&in[0]),
                                  position,
                                  consumed,
                                  checking != FULL_CHECK);

      send(out, written);

      if(consumed != position)
         {
         copy_mem(&in[0], &in[consumed], position - consumed);
         position = position - consumed;
         }
      else
         position = 0;

      length -= to_copy;
      input += to_copy;
      }
   }

/*
* Flush buffers
*/
void Hex_Decoder::end_msg()
   {
   size_t consumed = 0;
   size_t written = hex_decode(&out[0],
                               reinterpret_cast<const char*>(&in[0]),
                               position,
                               consumed,
                               checking != FULL_CHECK);

   send(out, written);

   const bool not_full_bytes = consumed != position;

   position = 0;

   if(not_full_bytes)
      throw std::invalid_argument("Hex_Decoder: Input not full bytes");
   }

}
/*
* DataSink
* (C) 1999-2007 Jack Lloyd
*     2005 Matthew Gregan
*
* Distributed under the terms of the Botan license
*/

#include <fstream>

namespace Botan {

/*
* Write to a stream
*/
void DataSink_Stream::write(const byte out[], size_t length)
   {
   sink.write(reinterpret_cast<const char*>(out), length);
   if(!sink.good())
      throw Stream_IO_Error("DataSink_Stream: Failure writing to " +
                            identifier);
   }

/*
* DataSink_Stream Constructor
*/
DataSink_Stream::DataSink_Stream(std::ostream& out,
                                 const std::string& name) :
   identifier(name),
   sink_p(0),
   sink(out)
   {
   }

/*
* DataSink_Stream Constructor
*/
DataSink_Stream::DataSink_Stream(const std::string& path,
                                 bool use_binary) :
   identifier(path),
   sink_p(new std::ofstream(
             path.c_str(),
             use_binary ? std::ios::binary : std::ios::out)),
   sink(*sink_p)
   {
   if(!sink.good())
      {
      delete sink_p;
      throw Stream_IO_Error("DataSink_Stream: Failure opening " + path);
      }
   }

/*
* DataSink_Stream Destructor
*/
DataSink_Stream::~DataSink_Stream()
   {
   delete sink_p;
   }

}
/*
* DataSource
* (C) 1999-2007 Jack Lloyd
*     2005 Matthew Gregan
*
* Distributed under the terms of the Botan license
*/

#include <fstream>
#include <algorithm>

namespace Botan {

/*
* Read a single byte from the DataSource
*/
size_t DataSource::read_byte(byte& out)
   {
   return read(&out, 1);
   }

/*
* Peek a single byte from the DataSource
*/
size_t DataSource::peek_byte(byte& out) const
   {
   return peek(&out, 1, 0);
   }

/*
* Discard the next N bytes of the data
*/
size_t DataSource::discard_next(size_t n)
   {
   size_t discarded = 0;
   byte dummy;
   for(size_t j = 0; j != n; ++j)
      discarded += read_byte(dummy);
   return discarded;
   }

/*
* Read from a memory buffer
*/
size_t DataSource_Memory::read(byte out[], size_t length)
   {
   size_t got = std::min<size_t>(source.size() - offset, length);
   copy_mem(out, &source[offset], got);
   offset += got;
   return got;
   }

/*
* Peek into a memory buffer
*/
size_t DataSource_Memory::peek(byte out[], size_t length,
                               size_t peek_offset) const
   {
   const size_t bytes_left = source.size() - offset;
   if(peek_offset >= bytes_left) return 0;

   size_t got = std::min(bytes_left - peek_offset, length);
   copy_mem(out, &source[offset + peek_offset], got);
   return got;
   }

/*
* Check if the memory buffer is empty
*/
bool DataSource_Memory::end_of_data() const
   {
   return (offset == source.size());
   }

/*
* DataSource_Memory Constructor
*/
DataSource_Memory::DataSource_Memory(const byte in[], size_t length) :
   source(in, length)
   {
   offset = 0;
   }

/*
* DataSource_Memory Constructor
*/
DataSource_Memory::DataSource_Memory(const MemoryRegion<byte>& in) :
   source(in)
   {
   offset = 0;
   }

/*
* DataSource_Memory Constructor
*/
DataSource_Memory::DataSource_Memory(const std::string& in) :
   source(reinterpret_cast<const byte*>(in.data()), in.length())
   {
   offset = 0;
   }

/*
* Read from a stream
*/
size_t DataSource_Stream::read(byte out[], size_t length)
   {
   source.read(reinterpret_cast<char*>(out), length);
   if(source.bad())
      throw Stream_IO_Error("DataSource_Stream::read: Source failure");

   size_t got = source.gcount();
   total_read += got;
   return got;
   }

/*
* Peek into a stream
*/
size_t DataSource_Stream::peek(byte out[], size_t length, size_t offset) const
   {
   if(end_of_data())
      throw Invalid_State("DataSource_Stream: Cannot peek when out of data");

   size_t got = 0;

   if(offset)
      {
      SecureVector<byte> buf(offset);
      source.read(reinterpret_cast<char*>(&buf[0]), buf.size());
      if(source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = source.gcount();
      }

   if(got == offset)
      {
      source.read(reinterpret_cast<char*>(out), length);
      if(source.bad())
         throw Stream_IO_Error("DataSource_Stream::peek: Source failure");
      got = source.gcount();
      }

   if(source.eof())
      source.clear();
   source.seekg(total_read, std::ios::beg);

   return got;
   }

/*
* Check if the stream is empty or in error
*/
bool DataSource_Stream::end_of_data() const
   {
   return (!source.good());
   }

/*
* Return a human-readable ID for this stream
*/
std::string DataSource_Stream::id() const
   {
   return identifier;
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(const std::string& path,
                                     bool use_binary) :
   identifier(path),
   source_p(new std::ifstream(
               path.c_str(),
               use_binary ? std::ios::binary : std::ios::in)),
   source(*source_p),
   total_read(0)
   {
   if(!source.good())
      {
      delete source_p;
      throw Stream_IO_Error("DataSource: Failure opening file " + path);
      }
   }

/*
* DataSource_Stream Constructor
*/
DataSource_Stream::DataSource_Stream(std::istream& in,
                                     const std::string& name) :
   identifier(name),
   source_p(0),
   source(in),
   total_read(0)
   {
   }

/*
* DataSource_Stream Destructor
*/
DataSource_Stream::~DataSource_Stream()
   {
   delete source_p;
   }

}

#ifdef Q_OS_UNIX
/*
* Pipe I/O for Unix
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <unistd.h>

namespace Botan {

/*
* Write data from a pipe into a Unix fd
*/
int operator<<(int fd, Pipe& pipe)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(pipe.remaining())
      {
      size_t got = pipe.read(&buffer[0], buffer.size());
      size_t position = 0;
      while(got)
         {
         ssize_t ret = write(fd, &buffer[position], got);
         if(ret == -1)
            throw Stream_IO_Error("Pipe output operator (unixfd) has failed");
         position += ret;
         got -= ret;
         }
      }
   return fd;
   }

/*
* Read data from a Unix fd into a pipe
*/
int operator>>(int fd, Pipe& pipe)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(true)
      {
      ssize_t ret = read(fd, &buffer[0], buffer.size());
      if(ret == 0) break;
      if(ret == -1)
         throw Stream_IO_Error("Pipe input operator (unixfd) has failed");
      pipe.write(&buffer[0], ret);
      }
   return fd;
   }

}
#endif

/*
* Filter
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Filter Constructor
*/
Filter::Filter()
   {
   next.resize(1);
   port_num = 0;
   filter_owns = 0;
   owned = false;
   }

/*
* Send data to all ports
*/
void Filter::send(const byte input[], size_t length)
   {
   bool nothing_attached = true;
   for(size_t j = 0; j != total_ports(); ++j)
      if(next[j])
         {
         if(write_queue.size())
            next[j]->write(&write_queue[0], write_queue.size());
         next[j]->write(input, length);
         nothing_attached = false;
         }

   if(nothing_attached)
      write_queue += std::make_pair(input, length);
   else
      write_queue.clear();
   }

/*
* Start a new message
*/
void Filter::new_msg()
   {
   start_msg();
   for(size_t j = 0; j != total_ports(); ++j)
      if(next[j])
         next[j]->new_msg();
   }

/*
* End the current message
*/
void Filter::finish_msg()
   {
   end_msg();
   for(size_t j = 0; j != total_ports(); ++j)
      if(next[j])
         next[j]->finish_msg();
   }

/*
* Attach a filter to the current port
*/
void Filter::attach(Filter* new_filter)
   {
   if(new_filter)
      {
      Filter* last = this;
      while(last->get_next())
         last = last->get_next();
      last->next[last->current_port()] = new_filter;
      }
   }

/*
* Set the active port on a filter
*/
void Filter::set_port(size_t new_port)
   {
   if(new_port >= total_ports())
      throw Invalid_Argument("Filter: Invalid port number");
   port_num = new_port;
   }

/*
* Return the next Filter in the logical chain
*/
Filter* Filter::get_next() const
   {
   if(port_num < next.size())
      return next[port_num];
   return 0;
   }

/*
* Set the next Filters
*/
void Filter::set_next(Filter* filters[], size_t size)
   {
   while(size && filters && filters[size-1] == 0)
      --size;

   next.clear();
   next.resize(size);

   port_num = 0;
   filter_owns = 0;

   for(size_t j = 0; j != size; ++j)
      next[j] = filters[j];
   }

/*
* Return the total number of ports
*/
size_t Filter::total_ports() const
   {
   return next.size();
   }

}
/*
* CBC Mode
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* CBC Encryption Constructor
*/
CBC_Encryption::CBC_Encryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad) :
   Buffered_Filter(ciph->block_size(), 0),
   cipher(ciph), padder(pad)
   {
   if(!padder->valid_blocksize(cipher->block_size()))
      throw Invalid_Block_Size(name(), padder->name());

   state.resize(cipher->block_size());
   }

/*
* CBC Encryption Constructor
*/
CBC_Encryption::CBC_Encryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   Buffered_Filter(ciph->block_size(), 0),
   cipher(ciph), padder(pad)
   {
   if(!padder->valid_blocksize(cipher->block_size()))
      throw Invalid_Block_Size(name(), padder->name());

   state.resize(cipher->block_size());

   set_key(key);
   set_iv(iv);
   }

/*
* Set the IV
*/
void CBC_Encryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   buffer_reset();
   }

/*
* Encrypt in CBC mode
*/
void CBC_Encryption::buffered_block(const byte input[], size_t length)
   {
   size_t blocks = length / state.size();

   for(size_t i = 0; i != blocks; ++i)
      {
      xor_buf(state, input + i * cipher->block_size(), state.size());
      cipher->encrypt(state);
      send(state, state.size());
      }
   }

/*
* Finish encrypting in CBC mode
*/
void CBC_Encryption::buffered_final(const byte input[], size_t length)
   {
   if(length % cipher->block_size() == 0)
      buffered_block(input, length);
   else if(length != 0)
      throw Encoding_Error(name() + ": Did not pad to full blocksize");
   }

void CBC_Encryption::write(const byte input[], size_t input_length)
   {
   Buffered_Filter::write(input, input_length);
   }

void CBC_Encryption::end_msg()
   {
   size_t last_block = current_position() % cipher->block_size();

   SecureVector<byte> padding(cipher->block_size());
   padder->pad(padding, padding.size(), last_block);

   size_t pad_bytes = padder->pad_bytes(cipher->block_size(), last_block);

   if(pad_bytes)
      Buffered_Filter::write(padding, pad_bytes);
   Buffered_Filter::end_msg();
   }

/*
* Return a CBC mode name
*/
std::string CBC_Encryption::name() const
   {
   return (cipher->name() + "/CBC/" + padder->name());
   }

/*
* CBC Decryption Constructor
*/
CBC_Decryption::CBC_Decryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad) :
   Buffered_Filter(ciph->parallel_bytes(), ciph->block_size()),
   cipher(ciph), padder(pad)
   {
   if(!padder->valid_blocksize(cipher->block_size()))
      throw Invalid_Block_Size(name(), padder->name());

   state.resize(cipher->block_size());
   temp.resize(buffered_block_size());
   }

/*
* CBC Decryption Constructor
*/
CBC_Decryption::CBC_Decryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   Buffered_Filter(ciph->parallel_bytes(), ciph->block_size()),
   cipher(ciph), padder(pad)
   {
   if(!padder->valid_blocksize(cipher->block_size()))
      throw Invalid_Block_Size(name(), padder->name());

   state.resize(cipher->block_size());
   temp.resize(buffered_block_size());

   set_key(key);
   set_iv(iv);
   }

/*
* Set the IV
*/
void CBC_Decryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   buffer_reset();
   }

/*
* Decrypt in CBC mode
*/
void CBC_Decryption::buffered_block(const byte input[], size_t length)
   {
   const size_t blocks_in_temp = temp.size() / cipher->block_size();
   size_t blocks = length / cipher->block_size();

   while(blocks)
      {
      size_t to_proc = std::min<size_t>(blocks, blocks_in_temp);

      cipher->decrypt_n(input, &temp[0], to_proc);

      xor_buf(temp, state, cipher->block_size());

      for(size_t i = 1; i < to_proc; ++i)
         xor_buf(&temp[i * cipher->block_size()],
                 input + (i-1) * cipher->block_size(),
                 cipher->block_size());

      copy_mem(&state[0],
               input + (to_proc - 1) * cipher->block_size(),
               cipher->block_size());

      send(temp, to_proc * cipher->block_size());

      input += to_proc * cipher->block_size();
      blocks -= to_proc;
      }
   }

/*
* Finish encrypting in CBC mode
*/
void CBC_Decryption::buffered_final(const byte input[], size_t length)
   {
   if(length == 0 || length % cipher->block_size() != 0)
      throw Decoding_Error(name() + ": Ciphertext not multiple of block size");

   size_t extra_blocks = (length - 1) / cipher->block_size();

   buffered_block(input, extra_blocks * cipher->block_size());

   input += extra_blocks * cipher->block_size();

   cipher->decrypt(input, temp);
   xor_buf(temp, state, cipher->block_size());
   send(temp, padder->unpad(temp, cipher->block_size()));

   copy_mem(&state[0], input, state.size()); // save for IV chaining
   }

/*
* Decrypt in CBC mode
*/
void CBC_Decryption::write(const byte input[], size_t length)
   {
   Buffered_Filter::write(input, length);
   }

/*
* Finish decrypting in CBC mode
*/
void CBC_Decryption::end_msg()
   {
   Buffered_Filter::end_msg();
   }

/*
* Return a CBC mode name
*/
std::string CBC_Decryption::name() const
   {
   return (cipher->name() + "/CBC/" + padder->name());
   }

}
/*
* CFB Mode
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* CFB Encryption Constructor
*/
CFB_Encryption::CFB_Encryption(BlockCipher* ciph, size_t fback_bits)
   {
   cipher = ciph;
   feedback = fback_bits ? fback_bits / 8: cipher->block_size();

   buffer.resize(cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;

   if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
      throw Invalid_Argument("CFB_Encryption: Invalid feedback size " +
                             to_string(fback_bits));
   }

/*
* CFB Encryption Constructor
*/
CFB_Encryption::CFB_Encryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv,
                               size_t fback_bits)
   {
   cipher = ciph;
   feedback = fback_bits ? fback_bits / 8: cipher->block_size();

   buffer.resize(cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;

   if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
      throw Invalid_Argument("CFB_Encryption: Invalid feedback size " +
                             to_string(fback_bits));

   set_key(key);
   set_iv(iv);
   }

void CFB_Encryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   zeroise(buffer);
   position = 0;

   cipher->encrypt(state, buffer);
   }

/*
* Encrypt data in CFB mode
*/
void CFB_Encryption::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t xored = std::min(feedback - position, length);
      xor_buf(&buffer[position], input, xored);
      send(&buffer[position], xored);
      input += xored;
      length -= xored;
      position += xored;

      if(position == feedback)
         {
         for(size_t j = 0; j != cipher->block_size() - feedback; ++j)
            state[j] = state[j + feedback];
         state.copy(cipher->block_size() - feedback, buffer, feedback);
         cipher->encrypt(state, buffer);
         position = 0;
         }
      }
   }

/*
* CFB Decryption Constructor
*/
CFB_Decryption::CFB_Decryption(BlockCipher* ciph, size_t fback_bits)
   {
   cipher = ciph;
   feedback = fback_bits ? fback_bits / 8: cipher->block_size();

   buffer.resize(cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;

   if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
      throw Invalid_Argument("CFB_Decryption: Invalid feedback size " +
                             to_string(fback_bits));
   }

/*
* CFB Decryption Constructor
*/
CFB_Decryption::CFB_Decryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv,
                               size_t fback_bits)
   {
   cipher = ciph;
   feedback = fback_bits ? fback_bits / 8: cipher->block_size();

   buffer.resize(cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;

   if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
      throw Invalid_Argument("CFB_Decryption: Invalid feedback size " +
                             to_string(fback_bits));

   set_key(key);
   set_iv(iv);
   }

void CFB_Decryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   zeroise(buffer);
   position = 0;

   cipher->encrypt(state, buffer);
   }

/*
* Decrypt data in CFB mode
*/
void CFB_Decryption::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t xored = std::min(feedback - position, length);
      xor_buf(&buffer[position], input, xored);
      send(&buffer[position], xored);
      buffer.copy(position, input, xored);
      input += xored;
      length -= xored;
      position += xored;
      if(position == feedback)
         {
         for(size_t j = 0; j != cipher->block_size() - feedback; ++j)
            state[j] = state[j + feedback];
         state.copy(cipher->block_size() - feedback, buffer, feedback);
         cipher->encrypt(state, buffer);
         position = 0;
         }
      }
   }

}
/*
* CTS Mode
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* CTS Encryption Constructor
*/
CTS_Encryption::CTS_Encryption(BlockCipher* ciph) :
   cipher(ciph)
   {
   buffer.resize(2 * cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;
   }

/*
* CTS Encryption Constructor
*/
CTS_Encryption::CTS_Encryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   cipher(ciph)
   {
   buffer.resize(2 * cipher->block_size());
   state.resize(cipher->block_size());
   position = 0;

   set_key(key);
   set_iv(iv);
   }

/*
* Set the IV
*/
void CTS_Encryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   zeroise(buffer);
   position = 0;
   }

/*
* Encrypt a block
*/
void CTS_Encryption::encrypt(const byte block[])
   {
   xor_buf(state, block, cipher->block_size());
   cipher->encrypt(state);
   send(state, cipher->block_size());
   }

/*
* Encrypt in CTS mode
*/
void CTS_Encryption::write(const byte input[], size_t length)
   {
   size_t copied = std::min<size_t>(buffer.size() - position, length);
   buffer.copy(position, input, copied);
   length -= copied;
   input += copied;
   position += copied;

   if(length == 0) return;

   encrypt(&buffer[0]);
   if(length > cipher->block_size())
      {
      encrypt(&buffer[cipher->block_size()]);
      while(length > 2*cipher->block_size())
         {
         encrypt(input);
         length -= cipher->block_size();
         input += cipher->block_size();
         }
      position = 0;
      }
   else
      {
      copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size());
      position = cipher->block_size();
      }
   buffer.copy(position, input, length);
   position += length;
   }

/*
* Finish encrypting in CTS mode
*/
void CTS_Encryption::end_msg()
   {
   if(position < cipher->block_size() + 1)
      throw Encoding_Error(name() + ": insufficient data to encrypt");

   xor_buf(state, buffer, cipher->block_size());
   cipher->encrypt(state);
   SecureVector<byte> cn = state;
   clear_mem(&buffer[position], buffer.size() - position);
   encrypt(&buffer[cipher->block_size()]);
   send(cn, position - cipher->block_size());
   }

/*
* CTS Decryption Constructor
*/
CTS_Decryption::CTS_Decryption(BlockCipher* ciph) :
   cipher(ciph)
   {
   buffer.resize(2 * cipher->block_size());
   state.resize(cipher->block_size());
   temp.resize(cipher->block_size());
   position = 0;
   }

/*
* CTS Decryption Constructor
*/
CTS_Decryption::CTS_Decryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   cipher(ciph)
   {
   buffer.resize(2 * cipher->block_size());
   state.resize(cipher->block_size());
   temp.resize(cipher->block_size());
   position = 0;

   set_key(key);
   set_iv(iv);
   }

/*
* Set the IV
*/
void CTS_Decryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   state = iv.bits_of();
   zeroise(buffer);
   position = 0;
   }

/*
* Decrypt a block
*/
void CTS_Decryption::decrypt(const byte block[])
   {
   cipher->decrypt(block, &temp[0]);
   xor_buf(temp, state, cipher->block_size());
   send(temp, cipher->block_size());
   state.copy(block, cipher->block_size());
   }

/*
* Decrypt in CTS mode
*/
void CTS_Decryption::write(const byte input[], size_t length)
   {
   size_t copied = std::min<size_t>(buffer.size() - position, length);
   buffer.copy(position, input, copied);
   length -= copied;
   input += copied;
   position += copied;

   if(length == 0) return;

   decrypt(buffer);
   if(length > cipher->block_size())
      {
      decrypt(&buffer[cipher->block_size()]);
      while(length > 2*cipher->block_size())
         {
         decrypt(input);
         length -= cipher->block_size();
         input += cipher->block_size();
         }
      position = 0;
      }
   else
      {
      copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size());
      position = cipher->block_size();
      }
   buffer.copy(position, input, length);
   position += length;
   }

/*
* Finish decrypting in CTS mode
*/
void CTS_Decryption::end_msg()
   {
   cipher->decrypt(buffer, temp);
   xor_buf(temp, &buffer[cipher->block_size()], position - cipher->block_size());

   SecureVector<byte> xn = temp;

   copy_mem(&buffer[position],
            &xn[position - cipher->block_size()],
            buffer.size() - position);

   cipher->decrypt(&buffer[cipher->block_size()], temp);
   xor_buf(temp, state, cipher->block_size());
   send(temp, cipher->block_size());
   send(xn, position - cipher->block_size());
   }

}
/*
* EAX Mode Encryption
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

/*
* EAX MAC-based PRF
*/
SecureVector<byte> eax_prf(byte tag, size_t BLOCK_SIZE,
                           MessageAuthenticationCode* mac,
                           const byte in[], size_t length)
   {
   for(size_t i = 0; i != BLOCK_SIZE - 1; ++i)
      mac->update(0);
   mac->update(tag);
   mac->update(in, length);
   return mac->final();
   }

}

/*
* EAX_Base Constructor
*/
EAX_Base::EAX_Base(BlockCipher* cipher, size_t tag_size) :
   BLOCK_SIZE(cipher->block_size()),
   TAG_SIZE(tag_size ? tag_size / 8 : BLOCK_SIZE),
   cipher_name(cipher->name()),
   ctr_buf(DEFAULT_BUFFERSIZE)
   {
   cmac = new CMAC(cipher->clone());
   ctr = new CTR_BE(cipher); // takes ownership

   if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > cmac->output_length())
      throw Invalid_Argument(name() + ": Bad tag size " + to_string(tag_size));
   }

/*
* Check if a keylength is valid for EAX
*/
bool EAX_Base::valid_keylength(size_t n) const
   {
   if(!ctr->valid_keylength(n))
      return false;
   return true;
   }

/*
* Set the EAX key
*/
void EAX_Base::set_key(const SymmetricKey& key)
   {
   /*
   * These could share the key schedule, which is one nice part of EAX,
   * but it's much easier to ignore that here...
   */
   ctr->set_key(key);
   cmac->set_key(key);

   header_mac = eax_prf(1, BLOCK_SIZE, cmac, 0, 0);
   }

/*
* Do setup at the start of each message
*/
void EAX_Base::start_msg()
   {
   for(size_t i = 0; i != BLOCK_SIZE - 1; ++i)
      cmac->update(0);
   cmac->update(2);
   }

/*
* Set the EAX nonce
*/
void EAX_Base::set_iv(const InitializationVector& iv)
   {
   nonce_mac = eax_prf(0, BLOCK_SIZE, cmac, iv.begin(), iv.length());
   ctr->set_iv(&nonce_mac[0], nonce_mac.size());
   }

/*
* Set the EAX header
*/
void EAX_Base::set_header(const byte header[], size_t length)
   {
   header_mac = eax_prf(1, BLOCK_SIZE, cmac, header, length);
   }

/*
* Return the name of this cipher mode
*/
std::string EAX_Base::name() const
   {
   return (cipher_name + "/EAX");
   }

/*
* Encrypt in EAX mode
*/
void EAX_Encryption::write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t copied = std::min<size_t>(length, ctr_buf.size());

      ctr->cipher(input, &ctr_buf[0], copied);
      cmac->update(&ctr_buf[0], copied);

      send(ctr_buf, copied);
      input += copied;
      length -= copied;
      }
   }

/*
* Finish encrypting in EAX mode
*/
void EAX_Encryption::end_msg()
   {
   SecureVector<byte> data_mac = cmac->final();
   xor_buf(data_mac, nonce_mac, data_mac.size());
   xor_buf(data_mac, header_mac, data_mac.size());

   send(data_mac, TAG_SIZE);
   }

}
/*
* EAX Mode Encryption
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* EAX_Decryption Constructor
*/
EAX_Decryption::EAX_Decryption(BlockCipher* ciph,
                               size_t tag_size) :
   EAX_Base(ciph, tag_size)
   {
   queue.resize(2*TAG_SIZE + DEFAULT_BUFFERSIZE);
   queue_start = queue_end = 0;
   }

/*
* EAX_Decryption Constructor
*/
EAX_Decryption::EAX_Decryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv,
                               size_t tag_size) :
   EAX_Base(ciph, tag_size)
   {
   set_key(key);
   set_iv(iv);
   queue.resize(2*TAG_SIZE + DEFAULT_BUFFERSIZE);
   queue_start = queue_end = 0;
   }

/*
* Decrypt in EAX mode
*/
void EAX_Decryption::write(const byte input[], size_t length)
   {
   while(length)
      {
      const size_t copied = std::min<size_t>(length, queue.size() - queue_end);

      queue.copy(queue_end, input, copied);
      input += copied;
      length -= copied;
      queue_end += copied;

      while((queue_end - queue_start) > TAG_SIZE)
         {
         size_t removed = (queue_end - queue_start) - TAG_SIZE;
         do_write(&queue[queue_start], removed);
         queue_start += removed;
         }

      if(queue_start + TAG_SIZE == queue_end &&
         queue_start >= queue.size() / 2)
         {
         SecureVector<byte> queue_data(TAG_SIZE);
         queue_data.copy(&queue[queue_start], TAG_SIZE);
         queue.copy(&queue_data[0], TAG_SIZE);
         queue_start = 0;
         queue_end = TAG_SIZE;
         }
      }
   }

/*
* Decrypt in EAX mode
*/
void EAX_Decryption::do_write(const byte input[], size_t length)
   {
   while(length)
      {
      size_t copied = std::min<size_t>(length, ctr_buf.size());

      /*
      Process same block with cmac and ctr at the same time to
      help cache locality.
      */
      cmac->update(input, copied);
      ctr->cipher(input, &ctr_buf[0], copied);
      send(ctr_buf, copied);
      input += copied;
      length -= copied;
      }
   }

/*
* Finish decrypting in EAX mode
*/
void EAX_Decryption::end_msg()
   {
   if((queue_end - queue_start) != TAG_SIZE)
      throw Decoding_Error(name() + ": Message authentication failure");

   SecureVector<byte> data_mac = cmac->final();

   for(size_t j = 0; j != TAG_SIZE; ++j)
      if(queue[queue_start+j] != (data_mac[j] ^ nonce_mac[j] ^ header_mac[j]))
         throw Decoding_Error(name() + ": Message authentication failure");

   queue_start = queue_end = 0;
   }

}
/*
* ECB Mode
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* ECB_Encryption Constructor
*/
ECB_Encryption::ECB_Encryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad) :
   Buffered_Filter(ciph->parallel_bytes(), 0)
   {
   cipher = ciph;
   padder = pad;

   temp.resize(buffered_block_size());
   }

/*
* ECB_Encryption Constructor
*/
ECB_Encryption::ECB_Encryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad,
                               const SymmetricKey& key) :
   Buffered_Filter(ciph->parallel_bytes(), 0)
   {
   cipher = ciph;
   padder = pad;

   temp.resize(buffered_block_size());

   cipher->set_key(key);
   }

/*
* ECB_Encryption Destructor
*/
ECB_Encryption::~ECB_Encryption()
   {
   delete cipher;
   delete padder;
   }

/*
* Return an ECB mode name
*/
std::string ECB_Encryption::name() const
   {
   return (cipher->name() + "/ECB/" + padder->name());
   }

/*
* Encrypt in ECB mode
*/
void ECB_Encryption::write(const byte input[], size_t length)
   {
   Buffered_Filter::write(input, length);
   }

/*
* Finish encrypting in ECB mode
*/
void ECB_Encryption::end_msg()
   {
   size_t last_block = current_position() % cipher->block_size();

   SecureVector<byte> padding(cipher->block_size());
   padder->pad(padding, padding.size(), last_block);

   size_t pad_bytes = padder->pad_bytes(cipher->block_size(), last_block);

   if(pad_bytes)
      Buffered_Filter::write(padding, pad_bytes);
   Buffered_Filter::end_msg();
   }

void ECB_Encryption::buffered_block(const byte input[], size_t input_length)
   {
   const size_t blocks_in_temp = temp.size() / cipher->block_size();
   size_t blocks = input_length / cipher->block_size();

   while(blocks)
      {
      size_t to_proc = std::min(blocks, blocks_in_temp);

      cipher->encrypt_n(input, &temp[0], to_proc);

      send(temp, to_proc * cipher->block_size());

      input += to_proc * cipher->block_size();
      blocks -= to_proc;
      }
   }

void ECB_Encryption::buffered_final(const byte input[], size_t input_length)
   {
   if(input_length % cipher->block_size() == 0)
      buffered_block(input, input_length);
   else if(input_length != 0)
      throw Encoding_Error(name() + ": Did not pad to full blocksize");
   }

/*
* ECB_Decryption Constructor
*/
ECB_Decryption::ECB_Decryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad) :
   Buffered_Filter(ciph->parallel_bytes(), 1)
   {
   cipher = ciph;
   padder = pad;

   temp.resize(buffered_block_size());
   }

/*
* ECB_Decryption Constructor
*/
ECB_Decryption::ECB_Decryption(BlockCipher* ciph,
                               BlockCipherModePaddingMethod* pad,
                               const SymmetricKey& key) :
   Buffered_Filter(ciph->parallel_bytes(), 1)
   {
   cipher = ciph;
   padder = pad;

   temp.resize(buffered_block_size());

   cipher->set_key(key);
   }

/*
* ECB_Decryption Destructor
*/
ECB_Decryption::~ECB_Decryption()
   {
   delete cipher;
   delete padder;
   }

/*
* Return an ECB mode name
*/
std::string ECB_Decryption::name() const
   {
   return (cipher->name() + "/ECB/" + padder->name());
   }

/*
* Decrypt in ECB mode
*/
void ECB_Decryption::write(const byte input[], size_t length)
   {
   Buffered_Filter::write(input, length);
   }

/*
* Finish decrypting in ECB mode
*/
void ECB_Decryption::end_msg()
   {
   Buffered_Filter::end_msg();
   }

/*
* Decrypt in ECB mode
*/
void ECB_Decryption::buffered_block(const byte input[], size_t length)
   {
   const size_t blocks_in_temp = temp.size() / cipher->block_size();
   size_t blocks = length / cipher->block_size();

   while(blocks)
      {
      size_t to_proc = std::min(blocks, blocks_in_temp);

      cipher->decrypt_n(input, &temp[0], to_proc);

      send(temp, to_proc * cipher->block_size());

      input += to_proc * cipher->block_size();
      blocks -= to_proc;
      }
   }

/*
* Finish encrypting in ECB mode
*/
void ECB_Decryption::buffered_final(const byte input[], size_t length)
   {
   if(length == 0 || length % cipher->block_size() != 0)
      throw Decoding_Error(name() + ": Ciphertext not multiple of block size");

   size_t extra_blocks = (length - 1) / cipher->block_size();

   buffered_block(input, extra_blocks * cipher->block_size());

   input += extra_blocks * cipher->block_size();

   cipher->decrypt(input, temp);
   send(temp, padder->unpad(temp, cipher->block_size()));
   }

}
/*
* CBC Padding Methods
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Default amount of padding
*/
size_t BlockCipherModePaddingMethod::pad_bytes(size_t bs, size_t pos) const
   {
   return (bs - pos);
   }

/*
* Pad with PKCS #7 Method
*/
void PKCS7_Padding::pad(byte block[], size_t size, size_t position) const
   {
   const size_t bytes_remaining = size - position;
   const byte pad_value = static_cast<byte>(bytes_remaining);

   BOTAN_ASSERT_EQUAL(pad_value, bytes_remaining,
                      "Overflow in PKCS7_Padding");

   for(size_t j = 0; j != size; ++j)
      block[j] = pad_value;
   }

/*
* Unpad with PKCS #7 Method
*/
size_t PKCS7_Padding::unpad(const byte block[], size_t size) const
   {
   size_t position = block[size-1];
   if(position > size)
      throw Decoding_Error(name());
   for(size_t j = size-position; j != size-1; ++j)
      if(block[j] != position)
         throw Decoding_Error(name());
   return (size-position);
   }

/*
* Query if the size is valid for this method
*/
bool PKCS7_Padding::valid_blocksize(size_t size) const
   {
   if(size > 0 && size < 256)
      return true;
   else
      return false;
   }

/*
* Pad with ANSI X9.23 Method
*/
void ANSI_X923_Padding::pad(byte block[], size_t size, size_t position) const
   {
   for(size_t j = 0; j != size-position; ++j)
      block[j] = 0;
   block[size-position-1] = static_cast<byte>(size-position);
   }

/*
* Unpad with ANSI X9.23 Method
*/
size_t ANSI_X923_Padding::unpad(const byte block[], size_t size) const
   {
   size_t position = block[size-1];
   if(position > size)
      throw Decoding_Error(name());
   for(size_t j = size-position; j != size-1; ++j)
      if(block[j] != 0)
         throw Decoding_Error(name());
   return (size-position);
   }

/*
* Query if the size is valid for this method
*/
bool ANSI_X923_Padding::valid_blocksize(size_t size) const
   {
   if(size > 0 && size < 256)
      return true;
   else
      return false;
   }

/*
* Pad with One and Zeros Method
*/
void OneAndZeros_Padding::pad(byte block[], size_t size, size_t) const
   {
   block[0] = 0x80;
   for(size_t j = 1; j != size; ++j)
      block[j] = 0x00;
   }

/*
* Unpad with One and Zeros Method
*/
size_t OneAndZeros_Padding::unpad(const byte block[], size_t size) const
   {
   while(size)
      {
      if(block[size-1] == 0x80)
         break;
      if(block[size-1] != 0x00)
         throw Decoding_Error(name());
      size--;
      }
   if(!size)
      throw Decoding_Error(name());
   return (size-1);
   }

/*
* Query if the size is valid for this method
*/
bool OneAndZeros_Padding::valid_blocksize(size_t size) const
   {
   return (size > 0);
   }

}
/*
* XTS Mode
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <stdexcept>

namespace Botan {

namespace {

void poly_double(byte tweak[], size_t size)
   {
   const byte polynomial = (size == 16) ? 0x87 : 0x1B;

   byte carry = 0;
   for(size_t i = 0; i != size; ++i)
      {
      byte carry2 = (tweak[i] >> 7);
      tweak[i] = (tweak[i] << 1) | carry;
      carry = carry2;
      }

   if(carry)
      tweak[0] ^= polynomial;
   }

/* XTS needs to process at least 2 blocks in parallel
   because block_size+1 bytes are needed at the end
*/
size_t xts_parallelism(BlockCipher* cipher)
   {
   return std::max<size_t>(cipher->parallel_bytes(),
                           2 * cipher->block_size());
   }

}

/*
* XTS_Encryption constructor
*/
XTS_Encryption::XTS_Encryption(BlockCipher* ciph) :
   Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
   cipher(ciph)
   {
   if(cipher->block_size() != 8 && cipher->block_size() != 16)
      throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());

   cipher2 = cipher->clone();
   tweak.resize(buffered_block_size());
   }

/*
* XTS_Encryption constructor
*/
XTS_Encryption::XTS_Encryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
   cipher(ciph)
   {
   if(cipher->block_size() != 8 && cipher->block_size() != 16)
       throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());

   cipher2 = cipher->clone();
   tweak.resize(buffered_block_size());

   set_key(key);
   set_iv(iv);
   }

/*
* Return the name
*/
std::string XTS_Encryption::name() const
   {
   return (cipher->name() + "/XTS");
   }

/*
* Set new tweak
*/
void XTS_Encryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   const size_t blocks_in_tweak = tweak.size() / cipher->block_size();

   tweak.copy(iv.begin(), iv.length());
   cipher2->encrypt(tweak);

   for(size_t i = 1; i < blocks_in_tweak; ++i)
      {
      tweak.copy(i*cipher->block_size(),
                 &tweak[(i-1)*cipher->block_size()],
                 cipher->block_size());

      poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
      }
   }

void XTS_Encryption::set_key(const SymmetricKey& key)
   {
   size_t key_half = key.length() / 2;

   if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
      throw Invalid_Key_Length(name(), key.length());

   cipher->set_key(key.begin(), key_half);
   cipher2->set_key(key.begin() + key_half, key_half);
   }

/*
* Encrypt in XTS mode
*/
void XTS_Encryption::write(const byte input[], size_t length)
   {
   Buffered_Filter::write(input, length);
   }
/*
* Finish encrypting in XTS mode
*/
void XTS_Encryption::end_msg()
   {
   Buffered_Filter::end_msg();
   }

void XTS_Encryption::buffered_block(const byte input[], size_t length)
   {
   const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
   size_t blocks = length / cipher->block_size();

   SecureVector<byte> temp(tweak.size());

   while(blocks)
      {
      size_t to_proc = std::min(blocks, blocks_in_tweak);
      size_t to_proc_bytes = to_proc * cipher->block_size();

      xor_buf(temp, input, tweak, to_proc_bytes);

      cipher->encrypt_n(&temp[0], &temp[0], to_proc);

      xor_buf(temp, tweak, to_proc_bytes);

      send(temp, to_proc_bytes);

      tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
                 cipher->block_size());
      poly_double(&tweak[0], cipher->block_size());

      for(size_t i = 1; i < blocks_in_tweak; ++i)
         {
         tweak.copy(i*cipher->block_size(),
                    &tweak[(i-1)*cipher->block_size()],
                    cipher->block_size());

         poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
         }

      input += to_proc * cipher->block_size();
      blocks -= to_proc;
      }
   }

/*
* Finish encrypting in XTS mode
*/
void XTS_Encryption::buffered_final(const byte input[], size_t length)
   {
   if(length <= cipher->block_size())
      throw Encoding_Error("XTS_Encryption: insufficient data to encrypt");

   if(length % cipher->block_size() == 0)
      {
      buffered_block(input, length);
      }
   else
      { // steal ciphertext

      size_t leftover_blocks =
         ((length / cipher->block_size()) - 1) * cipher->block_size();

      buffered_block(input, leftover_blocks);

      input += leftover_blocks;
      length -= leftover_blocks;

      SecureVector<byte> temp(input, length);

      xor_buf(temp, tweak, cipher->block_size());
      cipher->encrypt(temp);
      xor_buf(temp, tweak, cipher->block_size());

      poly_double(&tweak[0], cipher->block_size());

      for(size_t i = 0; i != length - cipher->block_size(); ++i)
         std::swap(temp[i], temp[i + cipher->block_size()]);

      xor_buf(temp, tweak, cipher->block_size());
      cipher->encrypt(temp);
      xor_buf(temp, tweak, cipher->block_size());

      send(temp, temp.size());
      }

   buffer_reset();
   }

/*
* XTS_Decryption constructor
*/
XTS_Decryption::XTS_Decryption(BlockCipher* ciph) :
   Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
   cipher(ciph)
   {
   if(cipher->block_size() != 8 && cipher->block_size() != 16)
       throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());

   cipher2 = ciph->clone();
   tweak.resize(buffered_block_size());
   }

/*
* XTS_Decryption constructor
*/
XTS_Decryption::XTS_Decryption(BlockCipher* ciph,
                               const SymmetricKey& key,
                               const InitializationVector& iv) :
   Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
   cipher(ciph)
   {
   if(cipher->block_size() != 8 && cipher->block_size() != 16)
       throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());

   cipher2 = ciph->clone();
   tweak.resize(buffered_block_size());

   set_key(key);
   set_iv(iv);
   }

/*
* Return the name
*/
std::string XTS_Decryption::name() const
   {
   return (cipher->name() + "/XTS");
   }

/*
* Set new tweak
*/
void XTS_Decryption::set_iv(const InitializationVector& iv)
   {
   if(!valid_iv_length(iv.length()))
      throw Invalid_IV_Length(name(), iv.length());

   const size_t blocks_in_tweak = tweak.size() / cipher->block_size();

   tweak.copy(iv.begin(), iv.length());
   cipher2->encrypt(tweak);

   for(size_t i = 1; i < blocks_in_tweak; ++i)
      {
      tweak.copy(i*cipher->block_size(),
                 &tweak[(i-1)*cipher->block_size()],
                 cipher->block_size());

      poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
      }
   }

void XTS_Decryption::set_key(const SymmetricKey& key)
   {
   size_t key_half = key.length() / 2;

   if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
      throw Invalid_Key_Length(name(), key.length());

   cipher->set_key(key.begin(), key_half);
   cipher2->set_key(key.begin() + key_half, key_half);
   }

/*
* Decrypt in XTS mode
*/
void XTS_Decryption::write(const byte input[], size_t length)
   {
   Buffered_Filter::write(input, length);
   }

/*
* Finish decrypting in XTS mode
*/
void XTS_Decryption::end_msg()
   {
   Buffered_Filter::end_msg();
   }

void XTS_Decryption::buffered_block(const byte input[], size_t input_length)
   {
   const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
   size_t blocks = input_length / cipher->block_size();

   SecureVector<byte> temp(tweak.size());

   while(blocks)
      {
      size_t to_proc = std::min(blocks, blocks_in_tweak);
      size_t to_proc_bytes = to_proc * cipher->block_size();

      xor_buf(temp, input, tweak, to_proc_bytes);

      cipher->decrypt_n(&temp[0], &temp[0], to_proc);

      xor_buf(temp, tweak, to_proc_bytes);

      send(temp, to_proc_bytes);

      tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
                 cipher->block_size());
      poly_double(&tweak[0], cipher->block_size());

      for(size_t i = 1; i < blocks_in_tweak; ++i)
         {
         tweak.copy(i*cipher->block_size(),
                    &tweak[(i-1)*cipher->block_size()],
                    cipher->block_size());

         poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
         }

      input += to_proc * cipher->block_size();
      blocks -= to_proc;
      }
   }

void XTS_Decryption::buffered_final(const byte input[], size_t length)
   {
   if(length <= cipher->block_size())
      throw Decoding_Error("XTS_Decryption: insufficient data to decrypt");

   if(length % cipher->block_size() == 0)
      {
      buffered_block(input, length);
      }
   else
      {
      size_t leftover_blocks =
         ((length / cipher->block_size()) - 1) * cipher->block_size();

      buffered_block(input, leftover_blocks);

      input += leftover_blocks;
      length -= leftover_blocks;

      SecureVector<byte> temp(input, length);
      SecureVector<byte> tweak_copy(&tweak[0], cipher->block_size());

      poly_double(&tweak_copy[0], cipher->block_size());

      xor_buf(temp, tweak_copy, cipher->block_size());
      cipher->decrypt(temp);
      xor_buf(temp, tweak_copy, cipher->block_size());

      for(size_t i = 0; i != length - cipher->block_size(); ++i)
         std::swap(temp[i], temp[i + cipher->block_size()]);

      xor_buf(temp, tweak, cipher->block_size());
      cipher->decrypt(temp);
      xor_buf(temp, tweak, cipher->block_size());

      send(temp, length);
      }

   buffer_reset();
   }

}
/*
* Pipe Output Buffer
* (C) 1999-2007,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Read data from a message
*/
size_t Output_Buffers::read(byte output[], size_t length,
                            Pipe::message_id msg)
   {
   SecureQueue* q = get(msg);
   if(q)
      return q->read(output, length);
   return 0;
   }

/*
* Peek at data in a message
*/
size_t Output_Buffers::peek(byte output[], size_t length,
                            size_t stream_offset,
                            Pipe::message_id msg) const
   {
   SecureQueue* q = get(msg);
   if(q)
      return q->peek(output, length, stream_offset);
   return 0;
   }

/*
* Check available bytes in a message
*/
size_t Output_Buffers::remaining(Pipe::message_id msg) const
   {
   SecureQueue* q = get(msg);
   if(q)
      return q->size();
   return 0;
   }

/*
* Add a new output queue
*/
void Output_Buffers::add(SecureQueue* queue)
   {
   BOTAN_ASSERT(queue, "argument was NULL");

   BOTAN_ASSERT(buffers.size() < buffers.max_size(),
                "No more room in container");

   buffers.push_back(queue);
   }

/*
* Retire old output queues
*/
void Output_Buffers::retire()
   {
   for(size_t i = 0; i != buffers.size(); ++i)
      if(buffers[i] && buffers[i]->size() == 0)
         {
         delete buffers[i];
         buffers[i] = 0;
         }

   while(buffers.size() && !buffers[0])
      {
      buffers.pop_front();
      offset = offset + Pipe::message_id(1);
      }
   }

/*
* Get a particular output queue
*/
SecureQueue* Output_Buffers::get(Pipe::message_id msg) const
   {
   if(msg < offset)
      return 0;

   BOTAN_ASSERT(msg < message_count(),
                "Message number out of range");

   return buffers[msg-offset];
   }

/*
* Return the total number of messages
*/
Pipe::message_id Output_Buffers::message_count() const
   {
   return (offset + buffers.size());
   }

/*
* Output_Buffers Constructor
*/
Output_Buffers::Output_Buffers()
   {
   offset = 0;
   }

/*
* Output_Buffers Destructor
*/
Output_Buffers::~Output_Buffers()
   {
   for(size_t j = 0; j != buffers.size(); ++j)
      delete buffers[j];
   }

}
/*
* Pipe
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* A Filter that does nothing
*/
class Null_Filter : public Filter
   {
   public:
      void write(const byte input[], size_t length)
         { send(input, length); }

      std::string name() const { return "Null"; }
   };

}

/*
* Pipe Constructor
*/
Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
   {
   init();
   append(f1);
   append(f2);
   append(f3);
   append(f4);
   }

/*
* Pipe Constructor
*/
Pipe::Pipe(Filter* filter_array[], size_t count)
   {
   init();
   for(size_t j = 0; j != count; ++j)
      append(filter_array[j]);
   }

/*
* Pipe Destructor
*/
Pipe::~Pipe()
   {
   destruct(pipe);
   delete outputs;
   }

/*
* Initialize the Pipe
*/
void Pipe::init()
   {
   outputs = new Output_Buffers;
   pipe = 0;
   default_read = 0;
   inside_msg = false;
   }

/*
* Reset the Pipe
*/
void Pipe::reset()
   {
   destruct(pipe);
   pipe = 0;
   inside_msg = false;
   }

/*
* Destroy the Pipe
*/
void Pipe::destruct(Filter* to_kill)
   {
   if(!to_kill || dynamic_cast<SecureQueue*>(to_kill))
      return;
   for(size_t j = 0; j != to_kill->total_ports(); ++j)
      destruct(to_kill->next[j]);
   delete to_kill;
   }

/*
* Test if the Pipe has any data in it
*/
bool Pipe::end_of_data() const
   {
   return (remaining() == 0);
   }

/*
* Set the default read message
*/
void Pipe::set_default_msg(message_id msg)
   {
   if(msg >= message_count())
      throw Invalid_Argument("Pipe::set_default_msg: msg number is too high");
   default_read = msg;
   }

/*
* Process a full message at once
*/
void Pipe::process_msg(const byte input[], size_t length)
   {
   start_msg();
   write(input, length);
   end_msg();
   }

/*
* Process a full message at once
*/
void Pipe::process_msg(const MemoryRegion<byte>& input)
   {
   process_msg(&input[0], input.size());
   }

/*
* Process a full message at once
*/
void Pipe::process_msg(const std::string& input)
   {
   process_msg(reinterpret_cast<const byte*>(input.data()), input.length());
   }

/*
* Process a full message at once
*/
void Pipe::process_msg(DataSource& input)
   {
   start_msg();
   write(input);
   end_msg();
   }

/*
* Start a new message
*/
void Pipe::start_msg()
   {
   if(inside_msg)
      throw Invalid_State("Pipe::start_msg: Message was already started");
   if(pipe == 0)
      pipe = new Null_Filter;
   find_endpoints(pipe);
   pipe->new_msg();
   inside_msg = true;
   }

/*
* End the current message
*/
void Pipe::end_msg()
   {
   if(!inside_msg)
      throw Invalid_State("Pipe::end_msg: Message was already ended");
   pipe->finish_msg();
   clear_endpoints(pipe);
   if(dynamic_cast<Null_Filter*>(pipe))
      {
      delete pipe;
      pipe = 0;
      }
   inside_msg = false;

   outputs->retire();
   }

/*
* Find the endpoints of the Pipe
*/
void Pipe::find_endpoints(Filter* f)
   {
   for(size_t j = 0; j != f->total_ports(); ++j)
      if(f->next[j] && !dynamic_cast<SecureQueue*>(f->next[j]))
         find_endpoints(f->next[j]);
      else
         {
         SecureQueue* q = new SecureQueue;
         f->next[j] = q;
         outputs->add(q);
         }
   }

/*
* Remove the SecureQueues attached to the Filter
*/
void Pipe::clear_endpoints(Filter* f)
   {
   if(!f) return;
   for(size_t j = 0; j != f->total_ports(); ++j)
      {
      if(f->next[j] && dynamic_cast<SecureQueue*>(f->next[j]))
         f->next[j] = 0;
      clear_endpoints(f->next[j]);
      }
   }

/*
* Append a Filter to the Pipe
*/
void Pipe::append(Filter* filter)
   {
   if(inside_msg)
      throw Invalid_State("Cannot append to a Pipe while it is processing");
   if(!filter)
      return;
   if(dynamic_cast<SecureQueue*>(filter))
      throw Invalid_Argument("Pipe::append: SecureQueue cannot be used");
   if(filter->owned)
      throw Invalid_Argument("Filters cannot be shared among multiple Pipes");

   filter->owned = true;

   if(!pipe) pipe = filter;
   else      pipe->attach(filter);
   }

/*
* Prepend a Filter to the Pipe
*/
void Pipe::prepend(Filter* filter)
   {
   if(inside_msg)
      throw Invalid_State("Cannot prepend to a Pipe while it is processing");
   if(!filter)
      return;
   if(dynamic_cast<SecureQueue*>(filter))
      throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used");
   if(filter->owned)
      throw Invalid_Argument("Filters cannot be shared among multiple Pipes");

   filter->owned = true;

   if(pipe) filter->attach(pipe);
   pipe = filter;
   }

/*
* Pop a Filter off the Pipe
*/
void Pipe::pop()
   {
   if(inside_msg)
      throw Invalid_State("Cannot pop off a Pipe while it is processing");

   if(!pipe)
      return;

   if(pipe->total_ports() > 1)
      throw Invalid_State("Cannot pop off a Filter with multiple ports");

   Filter* f = pipe;
   size_t owns = f->owns();
   pipe = pipe->next[0];
   delete f;

   while(owns--)
      {
      f = pipe;
      pipe = pipe->next[0];
      delete f;
      }
   }

/*
* Return the number of messages in this Pipe
*/
Pipe::message_id Pipe::message_count() const
   {
   return outputs->message_count();
   }

/*
* Static Member Variables
*/
const Pipe::message_id Pipe::LAST_MESSAGE =
   static_cast<Pipe::message_id>(-2);

const Pipe::message_id Pipe::DEFAULT_MESSAGE =
   static_cast<Pipe::message_id>(-1);

}
/*
* Pipe I/O
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <iostream>

namespace Botan {

/*
* Write data from a pipe into an ostream
*/
std::ostream& operator<<(std::ostream& stream, Pipe& pipe)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(stream.good() && pipe.remaining())
      {
      size_t got = pipe.read(&buffer[0], buffer.size());
      stream.write(reinterpret_cast<const char*>(&buffer[0]), got);
      }
   if(!stream.good())
      throw Stream_IO_Error("Pipe output operator (iostream) has failed");
   return stream;
   }

/*
* Read data from an istream into a pipe
*/
std::istream& operator>>(std::istream& stream, Pipe& pipe)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(stream.good())
      {
      stream.read(reinterpret_cast<char*>(&buffer[0]), buffer.size());
      pipe.write(&buffer[0], stream.gcount());
      }
   if(stream.bad() || (stream.fail() && !stream.eof()))
      throw Stream_IO_Error("Pipe input operator (iostream) has failed");
   return stream;
   }

}
/*
* Pipe Reading/Writing
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Look up the canonical ID for a queue
*/
Pipe::message_id Pipe::get_message_no(const std::string& func_name,
                                      message_id msg) const
   {
   if(msg == DEFAULT_MESSAGE)
      msg = default_msg();
   else if(msg == LAST_MESSAGE)
      msg = message_count() - 1;

   if(msg >= message_count())
      throw Invalid_Message_Number(func_name, msg);

   return msg;
   }

/*
* Write into a Pipe
*/
void Pipe::write(const byte input[], size_t length)
   {
   if(!inside_msg)
      throw Invalid_State("Cannot write to a Pipe while it is not processing");
   pipe->write(input, length);
   }

/*
* Write into a Pipe
*/
void Pipe::write(const MemoryRegion<byte>& input)
   {
   write(&input[0], input.size());
   }

/*
* Write a string into a Pipe
*/
void Pipe::write(const std::string& str)
   {
   write(reinterpret_cast<const byte*>(str.data()), str.size());
   }

/*
* Write a single byte into a Pipe
*/
void Pipe::write(byte input)
   {
   write(&input, 1);
   }

/*
* Write the contents of a DataSource into a Pipe
*/
void Pipe::write(DataSource& source)
   {
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(!source.end_of_data())
      {
      size_t got = source.read(&buffer[0], buffer.size());
      write(&buffer[0], got);
      }
   }

/*
* Read some data from the pipe
*/
size_t Pipe::read(byte output[], size_t length, message_id msg)
   {
   return outputs->read(output, length, get_message_no("read", msg));
   }

/*
* Read some data from the pipe
*/
size_t Pipe::read(byte output[], size_t length)
   {
   return read(output, length, DEFAULT_MESSAGE);
   }

/*
* Read a single byte from the pipe
*/
size_t Pipe::read(byte& out, message_id msg)
   {
   return read(&out, 1, msg);
   }

/*
* Return all data in the pipe
*/
SecureVector<byte> Pipe::read_all(message_id msg)
   {
   msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg());
   SecureVector<byte> buffer(remaining(msg));
   size_t got = read(&buffer[0], buffer.size(), msg);
   buffer.resize(got);
   return buffer;
   }

/*
* Return all data in the pipe as a string
*/
std::string Pipe::read_all_as_string(message_id msg)
   {
   msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg());
   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   std::string str;
   str.reserve(remaining(msg));

   while(true)
      {
      size_t got = read(&buffer[0], buffer.size(), msg);
      if(got == 0)
         break;
      str.append(reinterpret_cast<const char*>(&buffer[0]), got);
      }

   return str;
   }

/*
* Find out how many bytes are ready to read
*/
size_t Pipe::remaining(message_id msg) const
   {
   return outputs->remaining(get_message_no("remaining", msg));
   }

/*
* Peek at some data in the pipe
*/
size_t Pipe::peek(byte output[], size_t length,
                  size_t offset, message_id msg) const
   {
   return outputs->peek(output, length, offset, get_message_no("peek", msg));
   }

/*
* Peek at some data in the pipe
*/
size_t Pipe::peek(byte output[], size_t length, size_t offset) const
   {
   return peek(output, length, offset, DEFAULT_MESSAGE);
   }

/*
* Peek at a byte in the pipe
*/
size_t Pipe::peek(byte& out, size_t offset, message_id msg) const
   {
   return peek(&out, 1, offset, msg);
   }

}
/*
* PK Filters
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Append to the buffer
*/
void PK_Encryptor_Filter::write(const byte input[], size_t length)
   {
   buffer += std::make_pair(input, length);
   }

/*
* Encrypt the message
*/
void PK_Encryptor_Filter::end_msg()
   {
   send(cipher->encrypt(buffer, rng));
   buffer.clear();
   }

/*
* Append to the buffer
*/
void PK_Decryptor_Filter::write(const byte input[], size_t length)
   {
   buffer += std::make_pair(input, length);
   }

/*
* Decrypt the message
*/
void PK_Decryptor_Filter::end_msg()
   {
   send(cipher->decrypt(buffer));
   buffer.clear();
   }

/*
* Add more data
*/
void PK_Signer_Filter::write(const byte input[], size_t length)
   {
   signer->update(input, length);
   }

/*
* Sign the message
*/
void PK_Signer_Filter::end_msg()
   {
   send(signer->signature(rng));
   }

/*
* Add more data
*/
void PK_Verifier_Filter::write(const byte input[], size_t length)
   {
   verifier->update(input, length);
   }

/*
* Verify the message
*/
void PK_Verifier_Filter::end_msg()
   {
   if(signature.empty())
      throw Invalid_State("PK_Verifier_Filter: No signature to check against");
   bool is_valid = verifier->check_signature(signature);
   send((is_valid ? 1 : 0));
   }

/*
* Set the signature to check
*/
void PK_Verifier_Filter::set_signature(const byte sig[], size_t length)
   {
   signature.resize(length);
   copy_mem(&signature[0], sig, length);
   }

/*
* Set the signature to check
*/
void PK_Verifier_Filter::set_signature(const MemoryRegion<byte>& sig)
   {
   signature = sig;
   }

/*
* PK_Verifier_Filter Constructor
*/
PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, const byte sig[],
                                       size_t length) :
   verifier(v), signature(sig, length)
   {
   }

/*
* PK_Verifier_Filter Constructor
*/
PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v,
                                       const MemoryRegion<byte>& sig) :
   verifier(v), signature(sig)
   {
   }

}
/*
* SecureQueue
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/**
* A node in a SecureQueue
*/
class SecureQueueNode
   {
   public:
      SecureQueueNode() : buffer(DEFAULT_BUFFERSIZE)
         { next = 0; start = end = 0; }

      ~SecureQueueNode() { next = 0; start = end = 0; }

      size_t write(const byte input[], size_t length)
         {
         size_t copied = std::min<size_t>(length, buffer.size() - end);
         copy_mem(&buffer[end], input, copied);
         end += copied;
         return copied;
         }

      size_t read(byte output[], size_t length)
         {
         size_t copied = std::min(length, end - start);
         copy_mem(output, &buffer[start], copied);
         start += copied;
         return copied;
         }

      size_t peek(byte output[], size_t length, size_t offset = 0)
         {
         const size_t left = end - start;
         if(offset >= left) return 0;
         size_t copied = std::min(length, left - offset);
         copy_mem(output, &buffer[start + offset], copied);
         return copied;
         }

      size_t size() const { return (end - start); }
   private:
      friend class SecureQueue;
      SecureQueueNode* next;
      SecureVector<byte> buffer;
      size_t start, end;
   };

/*
* Create a SecureQueue
*/
SecureQueue::SecureQueue()
   {
   set_next(0, 0);
   head = tail = new SecureQueueNode;
   }

/*
* Copy a SecureQueue
*/
SecureQueue::SecureQueue(const SecureQueue& input) :
   Fanout_Filter(), DataSource()
   {
   set_next(0, 0);

   head = tail = new SecureQueueNode;
   SecureQueueNode* temp = input.head;
   while(temp)
      {
      write(&temp->buffer[temp->start], temp->end - temp->start);
      temp = temp->next;
      }
   }

/*
* Destroy this SecureQueue
*/
void SecureQueue::destroy()
   {
   SecureQueueNode* temp = head;
   while(temp)
      {
      SecureQueueNode* holder = temp->next;
      delete temp;
      temp = holder;
      }
   head = tail = 0;
   }

/*
* Copy a SecureQueue
*/
SecureQueue& SecureQueue::operator=(const SecureQueue& input)
   {
   destroy();
   head = tail = new SecureQueueNode;
   SecureQueueNode* temp = input.head;
   while(temp)
      {
      write(&temp->buffer[temp->start], temp->end - temp->start);
      temp = temp->next;
      }
   return (*this);
   }

/*
* Add some bytes to the queue
*/
void SecureQueue::write(const byte input[], size_t length)
   {
   if(!head)
      head = tail = new SecureQueueNode;
   while(length)
      {
      const size_t n = tail->write(input, length);
      input += n;
      length -= n;
      if(length)
         {
         tail->next = new SecureQueueNode;
         tail = tail->next;
         }
      }
   }

/*
* Read some bytes from the queue
*/
size_t SecureQueue::read(byte output[], size_t length)
   {
   size_t got = 0;
   while(length && head)
      {
      const size_t n = head->read(output, length);
      output += n;
      got += n;
      length -= n;
      if(head->size() == 0)
         {
         SecureQueueNode* holder = head->next;
         delete head;
         head = holder;
         }
      }
   return got;
   }

/*
* Read data, but do not remove it from queue
*/
size_t SecureQueue::peek(byte output[], size_t length, size_t offset) const
   {
   SecureQueueNode* current = head;

   while(offset && current)
      {
      if(offset >= current->size())
         {
         offset -= current->size();
         current = current->next;
         }
      else
         break;
      }

   size_t got = 0;
   while(length && current)
      {
      const size_t n = current->peek(output, length, offset);
      offset = 0;
      output += n;
      got += n;
      length -= n;
      current = current->next;
      }
   return got;
   }

/*
* Return how many bytes the queue holds
*/
size_t SecureQueue::size() const
   {
   SecureQueueNode* current = head;
   size_t count = 0;

   while(current)
      {
      count += current->size();
      current = current->next;
      }
   return count;
   }

/*
* Test if the queue has any data in it
*/
bool SecureQueue::end_of_data() const
   {
   return (size() == 0);
   }

}
/*
* Blue Midnight Wish 512 (Round 2 tweaked)
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

inline u64bit S0(u64bit X)
   {
   return (X >> 1) ^ (X << 3) ^ rotate_left(X, 4) ^ rotate_left(X, 37);
   }

inline u64bit S1(u64bit X)
   {
   return (X >> 1) ^ (X << 2) ^ rotate_left(X, 13) ^ rotate_left(X, 43);
   }

inline u64bit S2(u64bit X)
   {
   return (X >> 2) ^ (X << 1) ^ rotate_left(X, 19) ^ rotate_left(X, 53);
   }

inline u64bit S3(u64bit X)
   {
   return (X >> 2) ^ (X << 2) ^ rotate_left(X, 28) ^ rotate_left(X, 59);
   }

inline u64bit S4(u64bit X)
   {
   return (X >> 1) ^ X;
   }

/**
* Blue Midnight Wish 512 compression function
*/
void BMW_512_compress(u64bit H[16], const u64bit M[16], u64bit Q[32])
   {
   const size_t EXPAND_1_ROUNDS = 2;

   for(size_t i = 0; i != 16; ++i)
      Q[i] = H[i] ^ M[i];

   Q[16] = Q[ 5] - Q[ 7] + Q[10] + Q[13] + Q[14];
   Q[17] = Q[ 6] - Q[ 8] + Q[11] + Q[14] - Q[15];
   Q[18] = Q[ 0] + Q[ 7] + Q[ 9] - Q[12] + Q[15];
   Q[19] = Q[ 0] - Q[ 1] + Q[ 8] - Q[10] + Q[13];
   Q[20] = Q[ 1] + Q[ 2] + Q[ 9] - Q[11] - Q[14];
   Q[21] = Q[ 3] - Q[ 2] + Q[10] - Q[12] + Q[15];
   Q[22] = Q[ 4] - Q[ 0] - Q[ 3] - Q[11] + Q[13];
   Q[23] = Q[ 1] - Q[ 4] - Q[ 5] - Q[12] - Q[14];
   Q[24] = Q[ 2] - Q[ 5] - Q[ 6] + Q[13] - Q[15];
   Q[25] = Q[ 0] - Q[ 3] + Q[ 6] - Q[ 7] + Q[14];
   Q[26] = Q[ 8] - Q[ 1] - Q[ 4] - Q[ 7] + Q[15];
   Q[27] = Q[ 8] - Q[ 0] - Q[ 2] - Q[ 5] + Q[ 9];
   Q[28] = Q[ 1] + Q[ 3] - Q[ 6] - Q[ 9] + Q[10];
   Q[29] = Q[ 2] + Q[ 4] + Q[ 7] + Q[10] + Q[11];
   Q[30] = Q[ 3] - Q[ 5] + Q[ 8] - Q[11] - Q[12];
   Q[31] = Q[12] - Q[ 4] - Q[ 6] - Q[ 9] + Q[13];

   Q[ 0] = S0(Q[16]) + H[ 1];
   Q[ 1] = S1(Q[17]) + H[ 2];
   Q[ 2] = S2(Q[18]) + H[ 3];
   Q[ 3] = S3(Q[19]) + H[ 4];
   Q[ 4] = S4(Q[20]) + H[ 5];
   Q[ 5] = S0(Q[21]) + H[ 6];
   Q[ 6] = S1(Q[22]) + H[ 7];
   Q[ 7] = S2(Q[23]) + H[ 8];
   Q[ 8] = S3(Q[24]) + H[ 9];
   Q[ 9] = S4(Q[25]) + H[10];
   Q[10] = S0(Q[26]) + H[11];
   Q[11] = S1(Q[27]) + H[12];
   Q[12] = S2(Q[28]) + H[13];
   Q[13] = S3(Q[29]) + H[14];
   Q[14] = S4(Q[30]) + H[15];
   Q[15] = S0(Q[31]) + H[ 0];

   for(size_t i = 16; i != 16 + EXPAND_1_ROUNDS; ++i)
      {
      Q[i] = S1(Q[i-16]) + S2(Q[i-15]) + S3(Q[i-14]) + S0(Q[i-13]) +
             S1(Q[i-12]) + S2(Q[i-11]) + S3(Q[i-10]) + S0(Q[i- 9]) +
             S1(Q[i- 8]) + S2(Q[i- 7]) + S3(Q[i- 6]) + S0(Q[i- 5]) +
             S1(Q[i- 4]) + S2(Q[i- 3]) + S3(Q[i- 2]) + S0(Q[i- 1]) +
             ((rotate_left(M[(i-16) % 16], ((i-16)%16) + 1) +
               rotate_left(M[(i-13) % 16], ((i-13)%16) + 1) -
               rotate_left(M[(i- 6) % 16], ((i-6)%16) + 1) +
               (0x0555555555555555ULL * i)) ^ H[(i-16+7)%16]);
      }

   for(size_t i = 16 + EXPAND_1_ROUNDS; i != 32; ++i)
      {
      Q[i] = Q[i-16] + rotate_left(Q[i-15],  5) +
             Q[i-14] + rotate_left(Q[i-13], 11) +
             Q[i-12] + rotate_left(Q[i-11], 27) +
             Q[i-10] + rotate_left(Q[i- 9], 32) +
             Q[i- 8] + rotate_left(Q[i- 7], 37) +
             Q[i- 6] + rotate_left(Q[i- 5], 43) +
             Q[i- 4] + rotate_left(Q[i- 3], 53) +
             S4(Q[i - 2]) + ((Q[i-1] >> 2) ^ Q[i-1]) +
             ((rotate_left(M[(i-16) % 16], ((i-16)%16 + 1)) +
               rotate_left(M[(i-13) % 16], ((i-13)%16 + 1)) -
               rotate_left(M[(i- 6) % 16], ((i-6)%16 + 1)) +
               (0x0555555555555555ULL * i)) ^ H[(i-16+7)%16]);
      }

   u64bit XL = Q[16] ^ Q[17] ^ Q[18] ^ Q[19] ^
               Q[20] ^ Q[21] ^ Q[22] ^ Q[23];

   u64bit XH = Q[24] ^ Q[25] ^ Q[26] ^ Q[27] ^
               Q[28] ^ Q[29] ^ Q[30] ^ Q[31];

   XH ^= XL;

   H[ 0] = ((XH <<  5) ^ (Q[16] >> 5) ^ M[0]) + (XL ^ Q[24] ^ Q[0]);
   H[ 1] = ((XH >>  7) ^ (Q[17] << 8) ^ M[1]) + (XL ^ Q[25] ^ Q[1]);
   H[ 2] = ((XH >>  5) ^ (Q[18] << 5) ^ M[2]) + (XL ^ Q[26] ^ Q[2]);
   H[ 3] = ((XH >>  1) ^ (Q[19] << 5) ^ M[3]) + (XL ^ Q[27] ^ Q[3]);
   H[ 4] = ((XH >>  3) ^ (Q[20]     ) ^ M[4]) + (XL ^ Q[28] ^ Q[4]);
   H[ 5] = ((XH <<  6) ^ (Q[21] >> 6) ^ M[5]) + (XL ^ Q[29] ^ Q[5]);
   H[ 6] = ((XH >>  4) ^ (Q[22] << 6) ^ M[6]) + (XL ^ Q[30] ^ Q[6]);
   H[ 7] = ((XH >> 11) ^ (Q[23] << 2) ^ M[7]) + (XL ^ Q[31] ^ Q[7]);

   H[ 8] = rotate_left(H[4],  9) + (XH ^ Q[24] ^ M[ 8]) + ((XL << 8) ^ Q[23] ^ Q[ 8]);
   H[ 9] = rotate_left(H[5], 10) + (XH ^ Q[25] ^ M[ 9]) + ((XL >> 6) ^ Q[16] ^ Q[ 9]);
   H[10] = rotate_left(H[6], 11) + (XH ^ Q[26] ^ M[10]) + ((XL << 6) ^ Q[17] ^ Q[10]);
   H[11] = rotate_left(H[7], 12) + (XH ^ Q[27] ^ M[11]) + ((XL << 4) ^ Q[18] ^ Q[11]);
   H[12] = rotate_left(H[0], 13) + (XH ^ Q[28] ^ M[12]) + ((XL >> 3) ^ Q[19] ^ Q[12]);
   H[13] = rotate_left(H[1], 14) + (XH ^ Q[29] ^ M[13]) + ((XL >> 4) ^ Q[20] ^ Q[13]);
   H[14] = rotate_left(H[2], 15) + (XH ^ Q[30] ^ M[14]) + ((XL >> 7) ^ Q[21] ^ Q[14]);
   H[15] = rotate_left(H[3], 16) + (XH ^ Q[31] ^ M[15]) + ((XL >> 2) ^ Q[22] ^ Q[15]);
   }

}

void BMW_512::compress_n(const byte input[], size_t blocks)
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&M[0], input, M.size());

      BMW_512_compress(&H[0], &M[0], &Q[0]);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void BMW_512::copy_out(byte output[])
   {
   u64bit final[16] = {
      0xAAAAAAAAAAAAAAA0ULL,  0xAAAAAAAAAAAAAAA1ULL,
      0xAAAAAAAAAAAAAAA2ULL,  0xAAAAAAAAAAAAAAA3ULL,
      0xAAAAAAAAAAAAAAA4ULL,  0xAAAAAAAAAAAAAAA5ULL,
      0xAAAAAAAAAAAAAAA6ULL,  0xAAAAAAAAAAAAAAA7ULL,
      0xAAAAAAAAAAAAAAA8ULL,  0xAAAAAAAAAAAAAAA9ULL,
      0xAAAAAAAAAAAAAAAAULL,  0xAAAAAAAAAAAAAAABULL,
      0xAAAAAAAAAAAAAAACULL,  0xAAAAAAAAAAAAAAADULL,
      0xAAAAAAAAAAAAAAAEULL,  0xAAAAAAAAAAAAAAAFULL };

   BMW_512_compress(final, &H[0], &Q[0]);

   for(size_t i = 0; i != output_length(); i += 8)
      store_le(final[8 + i/8], output + i);
   }

/*
* Clear memory of sensitive data
*/
void BMW_512::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   zeroise(Q);

   H[ 0] = 0x8081828384858687ULL;
   H[ 1] = 0x88898A8B8C8D8E8FULL;
   H[ 2] = 0x9091929394959697ULL;
   H[ 3] = 0x98999A9B9C9D9E9FULL;
   H[ 4] = 0xA0A1A2A3A4A5A6A7ULL;
   H[ 5] = 0xA8A9AAABACADAEAFULL;
   H[ 6] = 0xB0B1B2B3B4B5B6B7ULL;
   H[ 7] = 0xB8B9BABBBCBDBEBFULL;
   H[ 8] = 0xC0C1C2C3C4C5C6C7ULL;
   H[ 9] = 0xC8C9CACBCCCDCECFULL;
   H[10] = 0xD0D1D2D3D4D5D6D7ULL;
   H[11] = 0xD8D9DADBDCDDDEDFULL;
   H[12] = 0xE0E1E2E3E4E5E6E7ULL;
   H[13] = 0xE8E9EAEBECEDEEEFULL;
   H[14] = 0xF0F1F2F3F4F5F6F7ULL;
   H[15] = 0xF8F9FAFBFCFDFEFFULL;
   }

}
/*
* Comb4P hash combiner
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

namespace {

void comb4p_round(MemoryRegion<byte>& out,
                  const MemoryRegion<byte>& in,
                  byte round_no,
                  HashFunction* h1,
                  HashFunction* h2)
   {
   h1->update(round_no);
   h2->update(round_no);

   h1->update(&in[0], in.size());
   h2->update(&in[0], in.size());

   SecureVector<byte> h_buf = h1->final();
   xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size()));

   h_buf = h2->final();
   xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size()));
   }

}

Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) :
   hash1(h1), hash2(h2)
   {
   if(hash1->name() == hash2->name())
      throw std::invalid_argument("Comb4P: Must use two distinct hashes");

   if(hash1->output_length() != hash2->output_length())
      throw std::invalid_argument("Comb4P: Incompatible hashes " +
                                  hash1->name() + " and " +
                                  hash2->name());

   clear();
   }

size_t Comb4P::hash_block_size() const
   {
   if(hash1->hash_block_size() == hash2->hash_block_size())
      return hash1->hash_block_size();

   /*
   * Return LCM of the block sizes? This would probably be OK for
   * HMAC, which is the main thing relying on knowing the block size.
   */
   return 0;
   }

void Comb4P::clear()
   {
   hash1->clear();
   hash2->clear();

   // Prep for processing next message, if any
   hash1->update(0);
   hash2->update(0);
   }

void Comb4P::add_data(const byte input[], size_t length)
   {
   hash1->update(input, length);
   hash2->update(input, length);
   }

void Comb4P::final_result(byte out[])
   {
   SecureVector<byte> h1 = hash1->final();
   SecureVector<byte> h2 = hash2->final();

   // First round
   xor_buf(&h1[0], &h2[0], std::min(h1.size(), h2.size()));

   // Second round
   comb4p_round(h2, h1, 1, hash1, hash2);

   // Third round
   comb4p_round(h1, h2, 2, hash1, hash2);

   copy_mem(out            , &h1[0], h1.size());
   copy_mem(out + h1.size(), &h2[0], h2.size());

   // Prep for processing next message, if any
   hash1->update(0);
   hash2->update(0);
   }

}

/*
* GOST 34.11
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/**
* GOST 34.11 Constructor
*/
GOST_34_11::GOST_34_11() :
   cipher(GOST_28147_89_Params("R3411_CryptoPro")),
   buffer(32),
   sum(32),
   hash(32)
   {
   count = 0;
   position = 0;
   }

void GOST_34_11::clear()
   {
   cipher.clear();
   zeroise(sum);
   zeroise(hash);
   count = 0;
   position = 0;
   }

/**
* Hash additional inputs
*/
void GOST_34_11::add_data(const byte input[], size_t length)
   {
   count += length;

   if(position)
      {
      buffer.copy(position, input, length);

      if(position + length >= hash_block_size())
         {
         compress_n(&buffer[0], 1);
         input += (hash_block_size() - position);
         length -= (hash_block_size() - position);
         position = 0;
         }
      }

   const size_t full_blocks = length / hash_block_size();
   const size_t remaining   = length % hash_block_size();

   if(full_blocks)
      compress_n(input, full_blocks);

   buffer.copy(position, input + full_blocks * hash_block_size(), remaining);
   position += remaining;
   }

/**
* The GOST 34.11 compression function
*/
void GOST_34_11::compress_n(const byte input[], size_t blocks)
   {
   for(size_t i = 0; i != blocks; ++i)
      {
      for(u16bit j = 0, carry = 0; j != 32; ++j)
         {
         u16bit s = sum[j] + input[32*i+j] + carry;
         carry = get_byte(0, s);
         sum[j] = get_byte(1, s);
         }

      byte S[32] = { 0 };

      u64bit U[4], V[4];
      load_be(U, &hash[0], 4);
      load_be(V, input + 32*i, 4);

      for(size_t j = 0; j != 4; ++j)
         {
         byte key[32] = { 0 };

         // P transformation
         for(size_t k = 0; k != 4; ++k)
            for(size_t l = 0; l != 8; ++l)
               key[4*l+k] = get_byte(l, U[k]) ^ get_byte(l, V[k]);

         cipher.set_key(key, 32);
         cipher.encrypt(&hash[8*j], S + 8*j);

         if(j == 3)
            break;

         // A(x)
         u64bit A_U = U[0];
         U[0] = U[1];
         U[1] = U[2];
         U[2] = U[3];
         U[3] = U[0] ^ A_U;

         if(j == 1) // C_3
            {
            U[0] ^= 0x00FF00FF00FF00FFULL;
            U[1] ^= 0xFF00FF00FF00FF00ULL;
            U[2] ^= 0x00FFFF00FF0000FFULL;
            U[3] ^= 0xFF000000FFFF00FFULL;
            }

         // A(A(x))
         u64bit AA_V_1 = V[0] ^ V[1];
         u64bit AA_V_2 = V[1] ^ V[2];
         V[0] = V[2];
         V[1] = V[3];
         V[2] = AA_V_1;
         V[3] = AA_V_2;
         }

      byte S2[32] = { 0 };

      // 12 rounds of psi
      S2[ 0] = S[24];
      S2[ 1] = S[25];
      S2[ 2] = S[26];
      S2[ 3] = S[27];
      S2[ 4] = S[28];
      S2[ 5] = S[29];
      S2[ 6] = S[30];
      S2[ 7] = S[31];
      S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30];
      S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31];
      S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30];
      S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31];
      S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
      S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
      S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28];
      S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29];
      S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30];
      S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31];
      S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28];
      S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29];
      S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30];
      S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31];
      S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30];
      S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31];
      S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26];
      S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27];
      S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28];
      S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29];
      S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30];
      S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31];
      S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28];
      S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29];

      xor_buf(S, S2, input + 32*i, 32);

      S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30];
      S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31];

      copy_mem(S, S+2, 30);
      S[30] = S2[0];
      S[31] = S2[1];

      xor_buf(S, &hash[0], 32);

      // 61 rounds of psi
      S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30];
      S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31];
      S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28];
      S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29];
      S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30];
      S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31];
      S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30];
      S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31];
      S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
      S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
      S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28];
      S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29];
      S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30];
      S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31];
      S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24];
      S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25];
      S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26];
      S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27];
      S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28];
      S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29];
      S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30];
      S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31];
      S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^
               S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30];
      S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^
               S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31];
      S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^
               S[24] ^ S[26] ^ S[28];
      S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^
               S[25] ^ S[27] ^ S[29];
      S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^
               S[26] ^ S[28] ^ S[30];
      S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^
               S[27] ^ S[29] ^ S[31];
      S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28];
      S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29];
      S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30];
      S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31];

      hash.copy(S2, 32);
      }
   }

/**
* Produce the final GOST 34.11 output
*/
void GOST_34_11::final_result(byte out[])
   {
   if(position)
      {
      clear_mem(&buffer[0] + position, buffer.size() - position);
      compress_n(&buffer[0], 1);
      }

   SecureVector<byte> length_buf(32);
   const u64bit bit_count = count * 8;
   store_le(bit_count, &length_buf[0]);

   SecureVector<byte> sum_buf = sum;

   compress_n(&length_buf[0], 1);
   compress_n(&sum_buf[0], 1);

   copy_mem(out, &hash[0], 32);

   clear();
   }

}
/*
* HAS-160
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace HAS_160_F {

/*
* HAS-160 F1 Function
*/
inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E,
               u32bit msg, u32bit rot)
   {
   E += rotate_left(A, rot) + (D ^ (B & (C ^ D))) + msg;
   B  = rotate_left(B, 10);
   }

/*
* HAS-160 F2 Function
*/
inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E,
               u32bit msg, u32bit rot)
   {
   E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x5A827999;
   B  = rotate_left(B, 17);
   }

/*
* HAS-160 F3 Function
*/
inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E,
               u32bit msg, u32bit rot)
   {
   E += rotate_left(A, rot) + (C ^ (B | ~D)) + msg + 0x6ED9EBA1;
   B  = rotate_left(B, 25);
   }

/*
* HAS-160 F4 Function
*/
inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E,
               u32bit msg, u32bit rot)
   {
   E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x8F1BBCDC;
   B  = rotate_left(B, 30);
   }

}

/*
* HAS-160 Compression Function
*/
void HAS_160::compress_n(const byte input[], size_t blocks)
   {
   using namespace HAS_160_F;

   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4];

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&X[0], input, 16);

      X[16] = X[ 0] ^ X[ 1] ^ X[ 2] ^ X[ 3];
      X[17] = X[ 4] ^ X[ 5] ^ X[ 6] ^ X[ 7];
      X[18] = X[ 8] ^ X[ 9] ^ X[10] ^ X[11];
      X[19] = X[12] ^ X[13] ^ X[14] ^ X[15];
      F1(A,B,C,D,E,X[18], 5);   F1(E,A,B,C,D,X[ 0],11);
      F1(D,E,A,B,C,X[ 1], 7);   F1(C,D,E,A,B,X[ 2],15);
      F1(B,C,D,E,A,X[ 3], 6);   F1(A,B,C,D,E,X[19],13);
      F1(E,A,B,C,D,X[ 4], 8);   F1(D,E,A,B,C,X[ 5],14);
      F1(C,D,E,A,B,X[ 6], 7);   F1(B,C,D,E,A,X[ 7],12);
      F1(A,B,C,D,E,X[16], 9);   F1(E,A,B,C,D,X[ 8],11);
      F1(D,E,A,B,C,X[ 9], 8);   F1(C,D,E,A,B,X[10],15);
      F1(B,C,D,E,A,X[11], 6);   F1(A,B,C,D,E,X[17],12);
      F1(E,A,B,C,D,X[12], 9);   F1(D,E,A,B,C,X[13],14);
      F1(C,D,E,A,B,X[14], 5);   F1(B,C,D,E,A,X[15],13);

      X[16] = X[ 3] ^ X[ 6] ^ X[ 9] ^ X[12];
      X[17] = X[ 2] ^ X[ 5] ^ X[ 8] ^ X[15];
      X[18] = X[ 1] ^ X[ 4] ^ X[11] ^ X[14];
      X[19] = X[ 0] ^ X[ 7] ^ X[10] ^ X[13];
      F2(A,B,C,D,E,X[18], 5);   F2(E,A,B,C,D,X[ 3],11);
      F2(D,E,A,B,C,X[ 6], 7);   F2(C,D,E,A,B,X[ 9],15);
      F2(B,C,D,E,A,X[12], 6);   F2(A,B,C,D,E,X[19],13);
      F2(E,A,B,C,D,X[15], 8);   F2(D,E,A,B,C,X[ 2],14);
      F2(C,D,E,A,B,X[ 5], 7);   F2(B,C,D,E,A,X[ 8],12);
      F2(A,B,C,D,E,X[16], 9);   F2(E,A,B,C,D,X[11],11);
      F2(D,E,A,B,C,X[14], 8);   F2(C,D,E,A,B,X[ 1],15);
      F2(B,C,D,E,A,X[ 4], 6);   F2(A,B,C,D,E,X[17],12);
      F2(E,A,B,C,D,X[ 7], 9);   F2(D,E,A,B,C,X[10],14);
      F2(C,D,E,A,B,X[13], 5);   F2(B,C,D,E,A,X[ 0],13);

      X[16] = X[ 5] ^ X[ 7] ^ X[12] ^ X[14];
      X[17] = X[ 0] ^ X[ 2] ^ X[ 9] ^ X[11];
      X[18] = X[ 4] ^ X[ 6] ^ X[13] ^ X[15];
      X[19] = X[ 1] ^ X[ 3] ^ X[ 8] ^ X[10];
      F3(A,B,C,D,E,X[18], 5);   F3(E,A,B,C,D,X[12],11);
      F3(D,E,A,B,C,X[ 5], 7);   F3(C,D,E,A,B,X[14],15);
      F3(B,C,D,E,A,X[ 7], 6);   F3(A,B,C,D,E,X[19],13);
      F3(E,A,B,C,D,X[ 0], 8);   F3(D,E,A,B,C,X[ 9],14);
      F3(C,D,E,A,B,X[ 2], 7);   F3(B,C,D,E,A,X[11],12);
      F3(A,B,C,D,E,X[16], 9);   F3(E,A,B,C,D,X[ 4],11);
      F3(D,E,A,B,C,X[13], 8);   F3(C,D,E,A,B,X[ 6],15);
      F3(B,C,D,E,A,X[15], 6);   F3(A,B,C,D,E,X[17],12);
      F3(E,A,B,C,D,X[ 8], 9);   F3(D,E,A,B,C,X[ 1],14);
      F3(C,D,E,A,B,X[10], 5);   F3(B,C,D,E,A,X[ 3],13);

      X[16] = X[ 2] ^ X[ 7] ^ X[ 8] ^ X[13];
      X[17] = X[ 3] ^ X[ 4] ^ X[ 9] ^ X[14];
      X[18] = X[ 0] ^ X[ 5] ^ X[10] ^ X[15];
      X[19] = X[ 1] ^ X[ 6] ^ X[11] ^ X[12];
      F4(A,B,C,D,E,X[18], 5);   F4(E,A,B,C,D,X[ 7],11);
      F4(D,E,A,B,C,X[ 2], 7);   F4(C,D,E,A,B,X[13],15);
      F4(B,C,D,E,A,X[ 8], 6);   F4(A,B,C,D,E,X[19],13);
      F4(E,A,B,C,D,X[ 3], 8);   F4(D,E,A,B,C,X[14],14);
      F4(C,D,E,A,B,X[ 9], 7);   F4(B,C,D,E,A,X[ 4],12);
      F4(A,B,C,D,E,X[16], 9);   F4(E,A,B,C,D,X[15],11);
      F4(D,E,A,B,C,X[10], 8);   F4(C,D,E,A,B,X[ 5],15);
      F4(B,C,D,E,A,X[ 0], 6);   F4(A,B,C,D,E,X[17],12);
      F4(E,A,B,C,D,X[11], 9);   F4(D,E,A,B,C,X[ 6],14);
      F4(C,D,E,A,B,X[ 1], 5);   F4(B,C,D,E,A,X[12],13);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void HAS_160::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_le(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void HAS_160::clear()
   {
   MDx_HashFunction::clear();
   zeroise(X);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   digest[4] = 0xC3D2E1F0;
   }

}
/*
* Keccak
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

void keccak_f_1600(u64bit A[25])
   {
   static const u64bit RC[24] = {
      0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808AULL,
      0x8000000080008000ULL, 0x000000000000808BULL, 0x0000000080000001ULL,
      0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008AULL,
      0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000AULL,
      0x000000008000808BULL, 0x800000000000008BULL, 0x8000000000008089ULL,
      0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
      0x000000000000800AULL, 0x800000008000000AULL, 0x8000000080008081ULL,
      0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
   };

   for(size_t i = 0; i != 24; ++i)
      {
      const u64bit C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
      const u64bit C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
      const u64bit C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
      const u64bit C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
      const u64bit C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];

      const u64bit D0 = rotate_left(C0, 1) ^ C3;
      const u64bit D1 = rotate_left(C1, 1) ^ C4;
      const u64bit D2 = rotate_left(C2, 1) ^ C0;
      const u64bit D3 = rotate_left(C3, 1) ^ C1;
      const u64bit D4 = rotate_left(C4, 1) ^ C2;

      const u64bit B00 = A[ 0] ^ D1;
      const u64bit B01 = rotate_left(A[ 6] ^ D2, 44);
      const u64bit B02 = rotate_left(A[12] ^ D3, 43);
      const u64bit B03 = rotate_left(A[18] ^ D4, 21);
      const u64bit B04 = rotate_left(A[24] ^ D0, 14);
      const u64bit B05 = rotate_left(A[ 3] ^ D4, 28);
      const u64bit B06 = rotate_left(A[ 9] ^ D0, 20);
      const u64bit B07 = rotate_left(A[10] ^ D1, 3);
      const u64bit B08 = rotate_left(A[16] ^ D2, 45);
      const u64bit B09 = rotate_left(A[22] ^ D3, 61);
      const u64bit B10 = rotate_left(A[ 1] ^ D2, 1);
      const u64bit B11 = rotate_left(A[ 7] ^ D3, 6);
      const u64bit B12 = rotate_left(A[13] ^ D4, 25);
      const u64bit B13 = rotate_left(A[19] ^ D0, 8);
      const u64bit B14 = rotate_left(A[20] ^ D1, 18);
      const u64bit B15 = rotate_left(A[ 4] ^ D0, 27);
      const u64bit B16 = rotate_left(A[ 5] ^ D1, 36);
      const u64bit B17 = rotate_left(A[11] ^ D2, 10);
      const u64bit B18 = rotate_left(A[17] ^ D3, 15);
      const u64bit B19 = rotate_left(A[23] ^ D4, 56);
      const u64bit B20 = rotate_left(A[ 2] ^ D3, 62);
      const u64bit B21 = rotate_left(A[ 8] ^ D4, 55);
      const u64bit B22 = rotate_left(A[14] ^ D0, 39);
      const u64bit B23 = rotate_left(A[15] ^ D1, 41);
      const u64bit B24 = rotate_left(A[21] ^ D2, 2);

      A[ 0] = B00 ^ (~B01 & B02);
      A[ 1] = B01 ^ (~B02 & B03);
      A[ 2] = B02 ^ (~B03 & B04);
      A[ 3] = B03 ^ (~B04 & B00);
      A[ 4] = B04 ^ (~B00 & B01);
      A[ 5] = B05 ^ (~B06 & B07);
      A[ 6] = B06 ^ (~B07 & B08);
      A[ 7] = B07 ^ (~B08 & B09);
      A[ 8] = B08 ^ (~B09 & B05);
      A[ 9] = B09 ^ (~B05 & B06);
      A[10] = B10 ^ (~B11 & B12);
      A[11] = B11 ^ (~B12 & B13);
      A[12] = B12 ^ (~B13 & B14);
      A[13] = B13 ^ (~B14 & B10);
      A[14] = B14 ^ (~B10 & B11);
      A[15] = B15 ^ (~B16 & B17);
      A[16] = B16 ^ (~B17 & B18);
      A[17] = B17 ^ (~B18 & B19);
      A[18] = B18 ^ (~B19 & B15);
      A[19] = B19 ^ (~B15 & B16);
      A[20] = B20 ^ (~B21 & B22);
      A[21] = B21 ^ (~B22 & B23);
      A[22] = B22 ^ (~B23 & B24);
      A[23] = B23 ^ (~B24 & B20);
      A[24] = B24 ^ (~B20 & B21);

      A[0] ^= RC[i];
      }
   }

}

Keccak_1600::Keccak_1600(size_t output_bits) :
   output_bits(output_bits),
   bitrate(1600 - 2*output_bits),
   S(25),
   S_pos(0)
   {
   // We only support the parameters for the SHA-3 proposal

   if(output_bits != 224 && output_bits != 256 &&
      output_bits != 384 && output_bits != 512)
      throw Invalid_Argument("Keccak_1600: Invalid output length " +
                             to_string(output_bits));
   }

std::string Keccak_1600::name() const
   {
   return "Keccak-1600(" + to_string(output_bits) + ")";
   }

HashFunction* Keccak_1600::clone() const
   {
   return new Keccak_1600(output_bits);
   }

void Keccak_1600::clear()
   {
   zeroise(S);
   S_pos = 0;
   }

void Keccak_1600::add_data(const byte input[], size_t length)
   {
   if(length == 0)
      return;

   while(length)
      {
      size_t to_take = std::min(length, bitrate / 8 - S_pos);

      length -= to_take;

      while(to_take && S_pos % 8)
         {
         S[S_pos / 8] ^= static_cast<u64bit>(input[0]) << (8 * (S_pos % 8));

         ++S_pos;
         ++input;
         --to_take;
         }

      while(to_take && to_take % 8 == 0)
         {
         S[S_pos / 8] ^= load_le<u64bit>(input, 0);
         S_pos += 8;
         input += 8;
         to_take -= 8;
         }

      while(to_take)
         {
         S[S_pos / 8] ^= static_cast<u64bit>(input[0]) << (8 * (S_pos % 8));

         ++S_pos;
         ++input;
         --to_take;
         }

      if(S_pos == bitrate / 8)
         {
         keccak_f_1600(&S[0]);
         S_pos = 0;
         }
      }
   }

void Keccak_1600::final_result(byte output[])
   {
   MemoryVector<byte> padding(bitrate / 8 - S_pos);

   padding[0] = 0x01;
   padding[padding.size()-1] |= 0x80;

   add_data(padding, padding.size());

   /*
   * We never have to run the permutation again because we only support
   * limited output lengths
   */
   for(size_t i = 0; i != output_bits/8; ++i)
      output[i] = get_byte(7 - (i % 8), S[i/8]);

   clear();
   }

}
/*
* MD2
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/**
* MD2 Compression Function
*/
void MD2::hash(const byte input[])
   {
   static const byte SBOX[256] = {
      0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1,
      0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C,
      0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C,
      0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
      0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
      0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F,
      0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 0x80, 0x7F, 0x5D, 0x9A,
      0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
      0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A,
      0xAC, 0x56, 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
      0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, 0x70, 0x59,
      0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
      0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69,
      0x34, 0x40, 0x7E, 0x0F, 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A,
      0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
      0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
      0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08,
      0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D,
      0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E,
      0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
      0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33,
      0x9F, 0x11, 0x83, 0x14 };

   X.copy(16, input, hash_block_size());
   xor_buf(&X[32], &X[0], &X[16], hash_block_size());
   byte T = 0;

   for(size_t i = 0; i != 18; ++i)
      {
      for(size_t k = 0; k != 48; k += 8)
         {
         T = X[k  ] ^= SBOX[T]; T = X[k+1] ^= SBOX[T];
         T = X[k+2] ^= SBOX[T]; T = X[k+3] ^= SBOX[T];
         T = X[k+4] ^= SBOX[T]; T = X[k+5] ^= SBOX[T];
         T = X[k+6] ^= SBOX[T]; T = X[k+7] ^= SBOX[T];
         }

      T += static_cast<byte>(i);
      }

   T = checksum[15];
   for(size_t i = 0; i != hash_block_size(); ++i)
      T = checksum[i] ^= SBOX[input[i] ^ T];
   }

/**
* Update the hash
*/
void MD2::add_data(const byte input[], size_t length)
   {
   buffer.copy(position, input, length);

   if(position + length >= hash_block_size())
      {
      hash(&buffer[0]);
      input += (hash_block_size() - position);
      length -= (hash_block_size() - position);
      while(length >= hash_block_size())
         {
         hash(input);
         input += hash_block_size();
         length -= hash_block_size();
         }
      buffer.copy(input, length);
      position = 0;
      }
   position += length;
   }

/**
* Finalize a MD2 Hash
*/
void MD2::final_result(byte output[])
   {
   for(size_t i = position; i != hash_block_size(); ++i)
      buffer[i] = static_cast<byte>(hash_block_size() - position);

   hash(&buffer[0]);
   hash(&checksum[0]);
   copy_mem(output, &X[0], output_length());
   clear();
   }

/**
* Clear memory of sensitive data
*/
void MD2::clear()
   {
   zeroise(X);
   zeroise(checksum);
   zeroise(buffer);
   position = 0;
   }

}
/*
* MD4
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* MD4 FF Function
*/
inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S)
   {
   A += (D ^ (B & (C ^ D))) + M;
   A  = rotate_left(A, S);
   }

/*
* MD4 GG Function
*/
inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S)
   {
   A += ((B & C) | (D & (B | C))) + M + 0x5A827999;
   A  = rotate_left(A, S);
   }

/*
* MD4 HH Function
*/
inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S)
   {
   A += (B ^ C ^ D) + M + 0x6ED9EBA1;
   A  = rotate_left(A, S);
   }

}

/*
* MD4 Compression Function
*/
void MD4::compress_n(const byte input[], size_t blocks)
   {
   u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3];

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&M[0], input, M.size());

      FF(A,B,C,D,M[ 0], 3);   FF(D,A,B,C,M[ 1], 7);
      FF(C,D,A,B,M[ 2],11);   FF(B,C,D,A,M[ 3],19);
      FF(A,B,C,D,M[ 4], 3);   FF(D,A,B,C,M[ 5], 7);
      FF(C,D,A,B,M[ 6],11);   FF(B,C,D,A,M[ 7],19);
      FF(A,B,C,D,M[ 8], 3);   FF(D,A,B,C,M[ 9], 7);
      FF(C,D,A,B,M[10],11);   FF(B,C,D,A,M[11],19);
      FF(A,B,C,D,M[12], 3);   FF(D,A,B,C,M[13], 7);
      FF(C,D,A,B,M[14],11);   FF(B,C,D,A,M[15],19);

      GG(A,B,C,D,M[ 0], 3);   GG(D,A,B,C,M[ 4], 5);
      GG(C,D,A,B,M[ 8], 9);   GG(B,C,D,A,M[12],13);
      GG(A,B,C,D,M[ 1], 3);   GG(D,A,B,C,M[ 5], 5);
      GG(C,D,A,B,M[ 9], 9);   GG(B,C,D,A,M[13],13);
      GG(A,B,C,D,M[ 2], 3);   GG(D,A,B,C,M[ 6], 5);
      GG(C,D,A,B,M[10], 9);   GG(B,C,D,A,M[14],13);
      GG(A,B,C,D,M[ 3], 3);   GG(D,A,B,C,M[ 7], 5);
      GG(C,D,A,B,M[11], 9);   GG(B,C,D,A,M[15],13);

      HH(A,B,C,D,M[ 0], 3);   HH(D,A,B,C,M[ 8], 9);
      HH(C,D,A,B,M[ 4],11);   HH(B,C,D,A,M[12],15);
      HH(A,B,C,D,M[ 2], 3);   HH(D,A,B,C,M[10], 9);
      HH(C,D,A,B,M[ 6],11);   HH(B,C,D,A,M[14],15);
      HH(A,B,C,D,M[ 1], 3);   HH(D,A,B,C,M[ 9], 9);
      HH(C,D,A,B,M[ 5],11);   HH(B,C,D,A,M[13],15);
      HH(A,B,C,D,M[ 3], 3);   HH(D,A,B,C,M[11], 9);
      HH(C,D,A,B,M[ 7],11);   HH(B,C,D,A,M[15],15);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void MD4::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_le(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void MD4::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   }

}
/*
* MD5
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* MD5 FF Function
*/
inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg,
               byte S, u32bit magic)
   {
   A += (D ^ (B & (C ^ D))) + msg + magic;
   A  = rotate_left(A, S) + B;
   }

/*
* MD5 GG Function
*/
inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg,
               byte S, u32bit magic)
   {
   A += (C ^ (D & (B ^ C))) + msg + magic;
   A  = rotate_left(A, S) + B;
   }

/*
* MD5 HH Function
*/
inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg,
               byte S, u32bit magic)
   {
   A += (B ^ C ^ D) + msg + magic;
   A  = rotate_left(A, S) + B;
   }

/*
* MD5 II Function
*/
inline void II(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg,
               byte S, u32bit magic)
   {
   A += (C ^ (B | ~D)) + msg + magic;
   A  = rotate_left(A, S) + B;
   }

}

/*
* MD5 Compression Function
*/
void MD5::compress_n(const byte input[], size_t blocks)
   {
   u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3];

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&M[0], input, M.size());

      FF(A,B,C,D,M[ 0], 7,0xD76AA478);   FF(D,A,B,C,M[ 1],12,0xE8C7B756);
      FF(C,D,A,B,M[ 2],17,0x242070DB);   FF(B,C,D,A,M[ 3],22,0xC1BDCEEE);
      FF(A,B,C,D,M[ 4], 7,0xF57C0FAF);   FF(D,A,B,C,M[ 5],12,0x4787C62A);
      FF(C,D,A,B,M[ 6],17,0xA8304613);   FF(B,C,D,A,M[ 7],22,0xFD469501);
      FF(A,B,C,D,M[ 8], 7,0x698098D8);   FF(D,A,B,C,M[ 9],12,0x8B44F7AF);
      FF(C,D,A,B,M[10],17,0xFFFF5BB1);   FF(B,C,D,A,M[11],22,0x895CD7BE);
      FF(A,B,C,D,M[12], 7,0x6B901122);   FF(D,A,B,C,M[13],12,0xFD987193);
      FF(C,D,A,B,M[14],17,0xA679438E);   FF(B,C,D,A,M[15],22,0x49B40821);

      GG(A,B,C,D,M[ 1], 5,0xF61E2562);   GG(D,A,B,C,M[ 6], 9,0xC040B340);
      GG(C,D,A,B,M[11],14,0x265E5A51);   GG(B,C,D,A,M[ 0],20,0xE9B6C7AA);
      GG(A,B,C,D,M[ 5], 5,0xD62F105D);   GG(D,A,B,C,M[10], 9,0x02441453);
      GG(C,D,A,B,M[15],14,0xD8A1E681);   GG(B,C,D,A,M[ 4],20,0xE7D3FBC8);
      GG(A,B,C,D,M[ 9], 5,0x21E1CDE6);   GG(D,A,B,C,M[14], 9,0xC33707D6);
      GG(C,D,A,B,M[ 3],14,0xF4D50D87);   GG(B,C,D,A,M[ 8],20,0x455A14ED);
      GG(A,B,C,D,M[13], 5,0xA9E3E905);   GG(D,A,B,C,M[ 2], 9,0xFCEFA3F8);
      GG(C,D,A,B,M[ 7],14,0x676F02D9);   GG(B,C,D,A,M[12],20,0x8D2A4C8A);

      HH(A,B,C,D,M[ 5], 4,0xFFFA3942);   HH(D,A,B,C,M[ 8],11,0x8771F681);
      HH(C,D,A,B,M[11],16,0x6D9D6122);   HH(B,C,D,A,M[14],23,0xFDE5380C);
      HH(A,B,C,D,M[ 1], 4,0xA4BEEA44);   HH(D,A,B,C,M[ 4],11,0x4BDECFA9);
      HH(C,D,A,B,M[ 7],16,0xF6BB4B60);   HH(B,C,D,A,M[10],23,0xBEBFBC70);
      HH(A,B,C,D,M[13], 4,0x289B7EC6);   HH(D,A,B,C,M[ 0],11,0xEAA127FA);
      HH(C,D,A,B,M[ 3],16,0xD4EF3085);   HH(B,C,D,A,M[ 6],23,0x04881D05);
      HH(A,B,C,D,M[ 9], 4,0xD9D4D039);   HH(D,A,B,C,M[12],11,0xE6DB99E5);
      HH(C,D,A,B,M[15],16,0x1FA27CF8);   HH(B,C,D,A,M[ 2],23,0xC4AC5665);

      II(A,B,C,D,M[ 0], 6,0xF4292244);   II(D,A,B,C,M[ 7],10,0x432AFF97);
      II(C,D,A,B,M[14],15,0xAB9423A7);   II(B,C,D,A,M[ 5],21,0xFC93A039);
      II(A,B,C,D,M[12], 6,0x655B59C3);   II(D,A,B,C,M[ 3],10,0x8F0CCC92);
      II(C,D,A,B,M[10],15,0xFFEFF47D);   II(B,C,D,A,M[ 1],21,0x85845DD1);
      II(A,B,C,D,M[ 8], 6,0x6FA87E4F);   II(D,A,B,C,M[15],10,0xFE2CE6E0);
      II(C,D,A,B,M[ 6],15,0xA3014314);   II(B,C,D,A,M[13],21,0x4E0811A1);
      II(A,B,C,D,M[ 4], 6,0xF7537E82);   II(D,A,B,C,M[11],10,0xBD3AF235);
      II(C,D,A,B,M[ 2],15,0x2AD7D2BB);   II(B,C,D,A,M[ 9],21,0xEB86D391);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void MD5::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_le(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void MD5::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   }

}
/*
* Merkle-Damgard Hash Function
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* MDx_HashFunction Constructor
*/
MDx_HashFunction::MDx_HashFunction(size_t block_len,
                                   bool byte_end,
                                   bool bit_end,
                                   size_t cnt_size) :
   buffer(block_len),
   BIG_BYTE_ENDIAN(byte_end),
   BIG_BIT_ENDIAN(bit_end),
   COUNT_SIZE(cnt_size)
   {
   count = position = 0;
   }

/*
* Clear memory of sensitive data
*/
void MDx_HashFunction::clear()
   {
   zeroise(buffer);
   count = position = 0;
   }

/*
* Update the hash
*/
void MDx_HashFunction::add_data(const byte input[], size_t length)
   {
   count += length;

   if(position)
      {
      buffer.copy(position, input, length);

      if(position + length >= buffer.size())
         {
         compress_n(&buffer[0], 1);
         input += (buffer.size() - position);
         length -= (buffer.size() - position);
         position = 0;
         }
      }

   const size_t full_blocks = length / buffer.size();
   const size_t remaining   = length % buffer.size();

   if(full_blocks)
      compress_n(input, full_blocks);

   buffer.copy(position, input + full_blocks * buffer.size(), remaining);
   position += remaining;
   }

/*
* Finalize a hash
*/
void MDx_HashFunction::final_result(byte output[])
   {
   buffer[position] = (BIG_BIT_ENDIAN ? 0x80 : 0x01);
   for(size_t i = position+1; i != buffer.size(); ++i)
      buffer[i] = 0;

   if(position >= buffer.size() - COUNT_SIZE)
      {
      compress_n(&buffer[0], 1);
      zeroise(buffer);
      }

   write_count(&buffer[buffer.size() - COUNT_SIZE]);

   compress_n(&buffer[0], 1);
   copy_out(output);
   clear();
   }

/*
* Write the count bits to the buffer
*/
void MDx_HashFunction::write_count(byte out[])
   {
   if(COUNT_SIZE < 8)
      throw Invalid_State("MDx_HashFunction::write_count: COUNT_SIZE < 8");
   if(COUNT_SIZE >= output_length() || COUNT_SIZE >= hash_block_size())
      throw Invalid_Argument("MDx_HashFunction: COUNT_SIZE is too big");

   const u64bit bit_count = count * 8;

   if(BIG_BYTE_ENDIAN)
      store_be(bit_count, out + COUNT_SIZE - 8);
   else
      store_le(bit_count, out + COUNT_SIZE - 8);
   }

}
/*
* Parallel
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Update the hash
*/
void Parallel::add_data(const byte input[], size_t length)
   {
   for(size_t i = 0; i != hashes.size(); ++i)
      hashes[i]->update(input, length);
   }

/*
* Finalize the hash
*/
void Parallel::final_result(byte hash[])
   {
   size_t offset = 0;
   for(size_t i = 0; i != hashes.size(); ++i)
      {
      hashes[i]->final(hash + offset);
      offset += hashes[i]->output_length();
      }
   }

/*
* Return output size
*/
size_t Parallel::output_length() const
   {
   size_t sum = 0;
   for(size_t i = 0; i != hashes.size(); ++i)
      sum += hashes[i]->output_length();
   return sum;
   }

/*
* Return the name of this type
*/
std::string Parallel::name() const
   {
   std::string hash_names;
   for(size_t i = 0; i != hashes.size(); ++i)
      {
      if(i)
         hash_names += ',';
      hash_names += hashes[i]->name();
      }
   return "Parallel(" + hash_names + ")";
   }

/*
* Return a clone of this object
*/
HashFunction* Parallel::clone() const
   {
   std::vector<HashFunction*> hash_copies;
   for(size_t i = 0; i != hashes.size(); ++i)
      hash_copies.push_back(hashes[i]->clone());
   return new Parallel(hash_copies);
   }

/*
* Clear memory of sensitive data
*/
void Parallel::clear()
   {
   for(size_t i = 0; i != hashes.size(); ++i)
      hashes[i]->clear();
   }

/*
* Parallel Constructor
*/
Parallel::Parallel(const std::vector<HashFunction*>& hash_in) :
   hashes(hash_in)
   {
   }

/*
* Parallel Destructor
*/
Parallel::~Parallel()
   {
   for(size_t i = 0; i != hashes.size(); ++i)
      delete hashes[i];
   }

}
/*
* RIPEMD-128
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace RIPEMD_128_F {

/*
* RIPEMD-128 F1 Function
*/
inline void F1(u32bit& A, u32bit B, u32bit C, u32bit D,
               u32bit msg, u32bit shift)
   {
   A += (B ^ C ^ D) + msg;
   A  = rotate_left(A, shift);
   }

/*
* RIPEMD-128 F2 Function
*/
inline void F2(u32bit& A, u32bit B, u32bit C, u32bit D,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (D ^ (B & (C ^ D))) + msg + magic;
   A  = rotate_left(A, shift);
   }

/*
* RIPEMD-128 F3 Function
*/
inline void F3(u32bit& A, u32bit B, u32bit C, u32bit D,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (D ^ (B | ~C)) + msg + magic;
   A  = rotate_left(A, shift);
   }

/*
* RIPEMD-128 F4 Function
*/
inline void F4(u32bit& A, u32bit B, u32bit C, u32bit D,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (C ^ (D & (B ^ C))) + msg + magic;
   A  = rotate_left(A, shift);
   }

}

/*
* RIPEMD-128 Compression Function
*/
void RIPEMD_128::compress_n(const byte input[], size_t blocks)
   {
   using namespace RIPEMD_128_F;

   const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1,
                MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0x50A28BE6,
                MAGIC6 = 0x5C4DD124, MAGIC7 = 0x6D703EF3;

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&M[0], input, M.size());

      u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1,
             C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1;

      F1(A1,B1,C1,D1,M[ 0],11       );   F4(A2,B2,C2,D2,M[ 5], 8,MAGIC5);
      F1(D1,A1,B1,C1,M[ 1],14       );   F4(D2,A2,B2,C2,M[14], 9,MAGIC5);
      F1(C1,D1,A1,B1,M[ 2],15       );   F4(C2,D2,A2,B2,M[ 7], 9,MAGIC5);
      F1(B1,C1,D1,A1,M[ 3],12       );   F4(B2,C2,D2,A2,M[ 0],11,MAGIC5);
      F1(A1,B1,C1,D1,M[ 4], 5       );   F4(A2,B2,C2,D2,M[ 9],13,MAGIC5);
      F1(D1,A1,B1,C1,M[ 5], 8       );   F4(D2,A2,B2,C2,M[ 2],15,MAGIC5);
      F1(C1,D1,A1,B1,M[ 6], 7       );   F4(C2,D2,A2,B2,M[11],15,MAGIC5);
      F1(B1,C1,D1,A1,M[ 7], 9       );   F4(B2,C2,D2,A2,M[ 4], 5,MAGIC5);
      F1(A1,B1,C1,D1,M[ 8],11       );   F4(A2,B2,C2,D2,M[13], 7,MAGIC5);
      F1(D1,A1,B1,C1,M[ 9],13       );   F4(D2,A2,B2,C2,M[ 6], 7,MAGIC5);
      F1(C1,D1,A1,B1,M[10],14       );   F4(C2,D2,A2,B2,M[15], 8,MAGIC5);
      F1(B1,C1,D1,A1,M[11],15       );   F4(B2,C2,D2,A2,M[ 8],11,MAGIC5);
      F1(A1,B1,C1,D1,M[12], 6       );   F4(A2,B2,C2,D2,M[ 1],14,MAGIC5);
      F1(D1,A1,B1,C1,M[13], 7       );   F4(D2,A2,B2,C2,M[10],14,MAGIC5);
      F1(C1,D1,A1,B1,M[14], 9       );   F4(C2,D2,A2,B2,M[ 3],12,MAGIC5);
      F1(B1,C1,D1,A1,M[15], 8       );   F4(B2,C2,D2,A2,M[12], 6,MAGIC5);

      F2(A1,B1,C1,D1,M[ 7], 7,MAGIC2);   F3(A2,B2,C2,D2,M[ 6], 9,MAGIC6);
      F2(D1,A1,B1,C1,M[ 4], 6,MAGIC2);   F3(D2,A2,B2,C2,M[11],13,MAGIC6);
      F2(C1,D1,A1,B1,M[13], 8,MAGIC2);   F3(C2,D2,A2,B2,M[ 3],15,MAGIC6);
      F2(B1,C1,D1,A1,M[ 1],13,MAGIC2);   F3(B2,C2,D2,A2,M[ 7], 7,MAGIC6);
      F2(A1,B1,C1,D1,M[10],11,MAGIC2);   F3(A2,B2,C2,D2,M[ 0],12,MAGIC6);
      F2(D1,A1,B1,C1,M[ 6], 9,MAGIC2);   F3(D2,A2,B2,C2,M[13], 8,MAGIC6);
      F2(C1,D1,A1,B1,M[15], 7,MAGIC2);   F3(C2,D2,A2,B2,M[ 5], 9,MAGIC6);
      F2(B1,C1,D1,A1,M[ 3],15,MAGIC2);   F3(B2,C2,D2,A2,M[10],11,MAGIC6);
      F2(A1,B1,C1,D1,M[12], 7,MAGIC2);   F3(A2,B2,C2,D2,M[14], 7,MAGIC6);
      F2(D1,A1,B1,C1,M[ 0],12,MAGIC2);   F3(D2,A2,B2,C2,M[15], 7,MAGIC6);
      F2(C1,D1,A1,B1,M[ 9],15,MAGIC2);   F3(C2,D2,A2,B2,M[ 8],12,MAGIC6);
      F2(B1,C1,D1,A1,M[ 5], 9,MAGIC2);   F3(B2,C2,D2,A2,M[12], 7,MAGIC6);
      F2(A1,B1,C1,D1,M[ 2],11,MAGIC2);   F3(A2,B2,C2,D2,M[ 4], 6,MAGIC6);
      F2(D1,A1,B1,C1,M[14], 7,MAGIC2);   F3(D2,A2,B2,C2,M[ 9],15,MAGIC6);
      F2(C1,D1,A1,B1,M[11],13,MAGIC2);   F3(C2,D2,A2,B2,M[ 1],13,MAGIC6);
      F2(B1,C1,D1,A1,M[ 8],12,MAGIC2);   F3(B2,C2,D2,A2,M[ 2],11,MAGIC6);

      F3(A1,B1,C1,D1,M[ 3],11,MAGIC3);   F2(A2,B2,C2,D2,M[15], 9,MAGIC7);
      F3(D1,A1,B1,C1,M[10],13,MAGIC3);   F2(D2,A2,B2,C2,M[ 5], 7,MAGIC7);
      F3(C1,D1,A1,B1,M[14], 6,MAGIC3);   F2(C2,D2,A2,B2,M[ 1],15,MAGIC7);
      F3(B1,C1,D1,A1,M[ 4], 7,MAGIC3);   F2(B2,C2,D2,A2,M[ 3],11,MAGIC7);
      F3(A1,B1,C1,D1,M[ 9],14,MAGIC3);   F2(A2,B2,C2,D2,M[ 7], 8,MAGIC7);
      F3(D1,A1,B1,C1,M[15], 9,MAGIC3);   F2(D2,A2,B2,C2,M[14], 6,MAGIC7);
      F3(C1,D1,A1,B1,M[ 8],13,MAGIC3);   F2(C2,D2,A2,B2,M[ 6], 6,MAGIC7);
      F3(B1,C1,D1,A1,M[ 1],15,MAGIC3);   F2(B2,C2,D2,A2,M[ 9],14,MAGIC7);
      F3(A1,B1,C1,D1,M[ 2],14,MAGIC3);   F2(A2,B2,C2,D2,M[11],12,MAGIC7);
      F3(D1,A1,B1,C1,M[ 7], 8,MAGIC3);   F2(D2,A2,B2,C2,M[ 8],13,MAGIC7);
      F3(C1,D1,A1,B1,M[ 0],13,MAGIC3);   F2(C2,D2,A2,B2,M[12], 5,MAGIC7);
      F3(B1,C1,D1,A1,M[ 6], 6,MAGIC3);   F2(B2,C2,D2,A2,M[ 2],14,MAGIC7);
      F3(A1,B1,C1,D1,M[13], 5,MAGIC3);   F2(A2,B2,C2,D2,M[10],13,MAGIC7);
      F3(D1,A1,B1,C1,M[11],12,MAGIC3);   F2(D2,A2,B2,C2,M[ 0],13,MAGIC7);
      F3(C1,D1,A1,B1,M[ 5], 7,MAGIC3);   F2(C2,D2,A2,B2,M[ 4], 7,MAGIC7);
      F3(B1,C1,D1,A1,M[12], 5,MAGIC3);   F2(B2,C2,D2,A2,M[13], 5,MAGIC7);

      F4(A1,B1,C1,D1,M[ 1],11,MAGIC4);   F1(A2,B2,C2,D2,M[ 8],15       );
      F4(D1,A1,B1,C1,M[ 9],12,MAGIC4);   F1(D2,A2,B2,C2,M[ 6], 5       );
      F4(C1,D1,A1,B1,M[11],14,MAGIC4);   F1(C2,D2,A2,B2,M[ 4], 8       );
      F4(B1,C1,D1,A1,M[10],15,MAGIC4);   F1(B2,C2,D2,A2,M[ 1],11       );
      F4(A1,B1,C1,D1,M[ 0],14,MAGIC4);   F1(A2,B2,C2,D2,M[ 3],14       );
      F4(D1,A1,B1,C1,M[ 8],15,MAGIC4);   F1(D2,A2,B2,C2,M[11],14       );
      F4(C1,D1,A1,B1,M[12], 9,MAGIC4);   F1(C2,D2,A2,B2,M[15], 6       );
      F4(B1,C1,D1,A1,M[ 4], 8,MAGIC4);   F1(B2,C2,D2,A2,M[ 0],14       );
      F4(A1,B1,C1,D1,M[13], 9,MAGIC4);   F1(A2,B2,C2,D2,M[ 5], 6       );
      F4(D1,A1,B1,C1,M[ 3],14,MAGIC4);   F1(D2,A2,B2,C2,M[12], 9       );
      F4(C1,D1,A1,B1,M[ 7], 5,MAGIC4);   F1(C2,D2,A2,B2,M[ 2],12       );
      F4(B1,C1,D1,A1,M[15], 6,MAGIC4);   F1(B2,C2,D2,A2,M[13], 9       );
      F4(A1,B1,C1,D1,M[14], 8,MAGIC4);   F1(A2,B2,C2,D2,M[ 9],12       );
      F4(D1,A1,B1,C1,M[ 5], 6,MAGIC4);   F1(D2,A2,B2,C2,M[ 7], 5       );
      F4(C1,D1,A1,B1,M[ 6], 5,MAGIC4);   F1(C2,D2,A2,B2,M[10],15       );
      F4(B1,C1,D1,A1,M[ 2],12,MAGIC4);   F1(B2,C2,D2,A2,M[14], 8       );

      D2        = digest[1] + C1 + D2;
      digest[1] = digest[2] + D1 + A2;
      digest[2] = digest[3] + A1 + B2;
      digest[3] = digest[0] + B1 + C2;
      digest[0] = D2;

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void RIPEMD_128::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_le(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void RIPEMD_128::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   }

}
/*
* RIPEMD-160
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* RIPEMD-160 F1 Function
*/
inline void F1(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E,
               u32bit msg, u32bit shift)
   {
   A += (B ^ C ^ D) + msg;
   A  = rotate_left(A, shift) + E;
   C  = rotate_left(C, 10);
   }

/*
* RIPEMD-160 F2 Function
*/
inline void F2(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (D ^ (B & (C ^ D))) + msg + magic;
   A  = rotate_left(A, shift) + E;
   C  = rotate_left(C, 10);
   }

/*
* RIPEMD-160 F3 Function
*/
inline void F3(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (D ^ (B | ~C)) + msg + magic;
   A  = rotate_left(A, shift) + E;
   C  = rotate_left(C, 10);
   }

/*
* RIPEMD-160 F4 Function
*/
inline void F4(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (C ^ (D & (B ^ C))) + msg + magic;
   A  = rotate_left(A, shift) + E;
   C  = rotate_left(C, 10);
   }

/*
* RIPEMD-160 F5 Function
*/
inline void F5(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E,
               u32bit msg, u32bit shift, u32bit magic)
   {
   A += (B ^ (C | ~D)) + msg + magic;
   A  = rotate_left(A, shift) + E;
   C  = rotate_left(C, 10);
   }

}

/*
* RIPEMD-160 Compression Function
*/
void RIPEMD_160::compress_n(const byte input[], size_t blocks)
   {
   const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1,
                MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E,
                MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124,
                MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9;

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&M[0], input, M.size());

      u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1,
             C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1,
             E1 = digest[4], E2 = E1;

      F1(A1,B1,C1,D1,E1,M[ 0],11       );  F5(A2,B2,C2,D2,E2,M[ 5], 8,MAGIC6);
      F1(E1,A1,B1,C1,D1,M[ 1],14       );  F5(E2,A2,B2,C2,D2,M[14], 9,MAGIC6);
      F1(D1,E1,A1,B1,C1,M[ 2],15       );  F5(D2,E2,A2,B2,C2,M[ 7], 9,MAGIC6);
      F1(C1,D1,E1,A1,B1,M[ 3],12       );  F5(C2,D2,E2,A2,B2,M[ 0],11,MAGIC6);
      F1(B1,C1,D1,E1,A1,M[ 4], 5       );  F5(B2,C2,D2,E2,A2,M[ 9],13,MAGIC6);
      F1(A1,B1,C1,D1,E1,M[ 5], 8       );  F5(A2,B2,C2,D2,E2,M[ 2],15,MAGIC6);
      F1(E1,A1,B1,C1,D1,M[ 6], 7       );  F5(E2,A2,B2,C2,D2,M[11],15,MAGIC6);
      F1(D1,E1,A1,B1,C1,M[ 7], 9       );  F5(D2,E2,A2,B2,C2,M[ 4], 5,MAGIC6);
      F1(C1,D1,E1,A1,B1,M[ 8],11       );  F5(C2,D2,E2,A2,B2,M[13], 7,MAGIC6);
      F1(B1,C1,D1,E1,A1,M[ 9],13       );  F5(B2,C2,D2,E2,A2,M[ 6], 7,MAGIC6);
      F1(A1,B1,C1,D1,E1,M[10],14       );  F5(A2,B2,C2,D2,E2,M[15], 8,MAGIC6);
      F1(E1,A1,B1,C1,D1,M[11],15       );  F5(E2,A2,B2,C2,D2,M[ 8],11,MAGIC6);
      F1(D1,E1,A1,B1,C1,M[12], 6       );  F5(D2,E2,A2,B2,C2,M[ 1],14,MAGIC6);
      F1(C1,D1,E1,A1,B1,M[13], 7       );  F5(C2,D2,E2,A2,B2,M[10],14,MAGIC6);
      F1(B1,C1,D1,E1,A1,M[14], 9       );  F5(B2,C2,D2,E2,A2,M[ 3],12,MAGIC6);
      F1(A1,B1,C1,D1,E1,M[15], 8       );  F5(A2,B2,C2,D2,E2,M[12], 6,MAGIC6);

      F2(E1,A1,B1,C1,D1,M[ 7], 7,MAGIC2);  F4(E2,A2,B2,C2,D2,M[ 6], 9,MAGIC7);
      F2(D1,E1,A1,B1,C1,M[ 4], 6,MAGIC2);  F4(D2,E2,A2,B2,C2,M[11],13,MAGIC7);
      F2(C1,D1,E1,A1,B1,M[13], 8,MAGIC2);  F4(C2,D2,E2,A2,B2,M[ 3],15,MAGIC7);
      F2(B1,C1,D1,E1,A1,M[ 1],13,MAGIC2);  F4(B2,C2,D2,E2,A2,M[ 7], 7,MAGIC7);
      F2(A1,B1,C1,D1,E1,M[10],11,MAGIC2);  F4(A2,B2,C2,D2,E2,M[ 0],12,MAGIC7);
      F2(E1,A1,B1,C1,D1,M[ 6], 9,MAGIC2);  F4(E2,A2,B2,C2,D2,M[13], 8,MAGIC7);
      F2(D1,E1,A1,B1,C1,M[15], 7,MAGIC2);  F4(D2,E2,A2,B2,C2,M[ 5], 9,MAGIC7);
      F2(C1,D1,E1,A1,B1,M[ 3],15,MAGIC2);  F4(C2,D2,E2,A2,B2,M[10],11,MAGIC7);
      F2(B1,C1,D1,E1,A1,M[12], 7,MAGIC2);  F4(B2,C2,D2,E2,A2,M[14], 7,MAGIC7);
      F2(A1,B1,C1,D1,E1,M[ 0],12,MAGIC2);  F4(A2,B2,C2,D2,E2,M[15], 7,MAGIC7);
      F2(E1,A1,B1,C1,D1,M[ 9],15,MAGIC2);  F4(E2,A2,B2,C2,D2,M[ 8],12,MAGIC7);
      F2(D1,E1,A1,B1,C1,M[ 5], 9,MAGIC2);  F4(D2,E2,A2,B2,C2,M[12], 7,MAGIC7);
      F2(C1,D1,E1,A1,B1,M[ 2],11,MAGIC2);  F4(C2,D2,E2,A2,B2,M[ 4], 6,MAGIC7);
      F2(B1,C1,D1,E1,A1,M[14], 7,MAGIC2);  F4(B2,C2,D2,E2,A2,M[ 9],15,MAGIC7);
      F2(A1,B1,C1,D1,E1,M[11],13,MAGIC2);  F4(A2,B2,C2,D2,E2,M[ 1],13,MAGIC7);
      F2(E1,A1,B1,C1,D1,M[ 8],12,MAGIC2);  F4(E2,A2,B2,C2,D2,M[ 2],11,MAGIC7);

      F3(D1,E1,A1,B1,C1,M[ 3],11,MAGIC3);  F3(D2,E2,A2,B2,C2,M[15], 9,MAGIC8);
      F3(C1,D1,E1,A1,B1,M[10],13,MAGIC3);  F3(C2,D2,E2,A2,B2,M[ 5], 7,MAGIC8);
      F3(B1,C1,D1,E1,A1,M[14], 6,MAGIC3);  F3(B2,C2,D2,E2,A2,M[ 1],15,MAGIC8);
      F3(A1,B1,C1,D1,E1,M[ 4], 7,MAGIC3);  F3(A2,B2,C2,D2,E2,M[ 3],11,MAGIC8);
      F3(E1,A1,B1,C1,D1,M[ 9],14,MAGIC3);  F3(E2,A2,B2,C2,D2,M[ 7], 8,MAGIC8);
      F3(D1,E1,A1,B1,C1,M[15], 9,MAGIC3);  F3(D2,E2,A2,B2,C2,M[14], 6,MAGIC8);
      F3(C1,D1,E1,A1,B1,M[ 8],13,MAGIC3);  F3(C2,D2,E2,A2,B2,M[ 6], 6,MAGIC8);
      F3(B1,C1,D1,E1,A1,M[ 1],15,MAGIC3);  F3(B2,C2,D2,E2,A2,M[ 9],14,MAGIC8);
      F3(A1,B1,C1,D1,E1,M[ 2],14,MAGIC3);  F3(A2,B2,C2,D2,E2,M[11],12,MAGIC8);
      F3(E1,A1,B1,C1,D1,M[ 7], 8,MAGIC3);  F3(E2,A2,B2,C2,D2,M[ 8],13,MAGIC8);
      F3(D1,E1,A1,B1,C1,M[ 0],13,MAGIC3);  F3(D2,E2,A2,B2,C2,M[12], 5,MAGIC8);
      F3(C1,D1,E1,A1,B1,M[ 6], 6,MAGIC3);  F3(C2,D2,E2,A2,B2,M[ 2],14,MAGIC8);
      F3(B1,C1,D1,E1,A1,M[13], 5,MAGIC3);  F3(B2,C2,D2,E2,A2,M[10],13,MAGIC8);
      F3(A1,B1,C1,D1,E1,M[11],12,MAGIC3);  F3(A2,B2,C2,D2,E2,M[ 0],13,MAGIC8);
      F3(E1,A1,B1,C1,D1,M[ 5], 7,MAGIC3);  F3(E2,A2,B2,C2,D2,M[ 4], 7,MAGIC8);
      F3(D1,E1,A1,B1,C1,M[12], 5,MAGIC3);  F3(D2,E2,A2,B2,C2,M[13], 5,MAGIC8);

      F4(C1,D1,E1,A1,B1,M[ 1],11,MAGIC4);  F2(C2,D2,E2,A2,B2,M[ 8],15,MAGIC9);
      F4(B1,C1,D1,E1,A1,M[ 9],12,MAGIC4);  F2(B2,C2,D2,E2,A2,M[ 6], 5,MAGIC9);
      F4(A1,B1,C1,D1,E1,M[11],14,MAGIC4);  F2(A2,B2,C2,D2,E2,M[ 4], 8,MAGIC9);
      F4(E1,A1,B1,C1,D1,M[10],15,MAGIC4);  F2(E2,A2,B2,C2,D2,M[ 1],11,MAGIC9);
      F4(D1,E1,A1,B1,C1,M[ 0],14,MAGIC4);  F2(D2,E2,A2,B2,C2,M[ 3],14,MAGIC9);
      F4(C1,D1,E1,A1,B1,M[ 8],15,MAGIC4);  F2(C2,D2,E2,A2,B2,M[11],14,MAGIC9);
      F4(B1,C1,D1,E1,A1,M[12], 9,MAGIC4);  F2(B2,C2,D2,E2,A2,M[15], 6,MAGIC9);
      F4(A1,B1,C1,D1,E1,M[ 4], 8,MAGIC4);  F2(A2,B2,C2,D2,E2,M[ 0],14,MAGIC9);
      F4(E1,A1,B1,C1,D1,M[13], 9,MAGIC4);  F2(E2,A2,B2,C2,D2,M[ 5], 6,MAGIC9);
      F4(D1,E1,A1,B1,C1,M[ 3],14,MAGIC4);  F2(D2,E2,A2,B2,C2,M[12], 9,MAGIC9);
      F4(C1,D1,E1,A1,B1,M[ 7], 5,MAGIC4);  F2(C2,D2,E2,A2,B2,M[ 2],12,MAGIC9);
      F4(B1,C1,D1,E1,A1,M[15], 6,MAGIC4);  F2(B2,C2,D2,E2,A2,M[13], 9,MAGIC9);
      F4(A1,B1,C1,D1,E1,M[14], 8,MAGIC4);  F2(A2,B2,C2,D2,E2,M[ 9],12,MAGIC9);
      F4(E1,A1,B1,C1,D1,M[ 5], 6,MAGIC4);  F2(E2,A2,B2,C2,D2,M[ 7], 5,MAGIC9);
      F4(D1,E1,A1,B1,C1,M[ 6], 5,MAGIC4);  F2(D2,E2,A2,B2,C2,M[10],15,MAGIC9);
      F4(C1,D1,E1,A1,B1,M[ 2],12,MAGIC4);  F2(C2,D2,E2,A2,B2,M[14], 8,MAGIC9);

      F5(B1,C1,D1,E1,A1,M[ 4], 9,MAGIC5);  F1(B2,C2,D2,E2,A2,M[12], 8       );
      F5(A1,B1,C1,D1,E1,M[ 0],15,MAGIC5);  F1(A2,B2,C2,D2,E2,M[15], 5       );
      F5(E1,A1,B1,C1,D1,M[ 5], 5,MAGIC5);  F1(E2,A2,B2,C2,D2,M[10],12       );
      F5(D1,E1,A1,B1,C1,M[ 9],11,MAGIC5);  F1(D2,E2,A2,B2,C2,M[ 4], 9       );
      F5(C1,D1,E1,A1,B1,M[ 7], 6,MAGIC5);  F1(C2,D2,E2,A2,B2,M[ 1],12       );
      F5(B1,C1,D1,E1,A1,M[12], 8,MAGIC5);  F1(B2,C2,D2,E2,A2,M[ 5], 5       );
      F5(A1,B1,C1,D1,E1,M[ 2],13,MAGIC5);  F1(A2,B2,C2,D2,E2,M[ 8],14       );
      F5(E1,A1,B1,C1,D1,M[10],12,MAGIC5);  F1(E2,A2,B2,C2,D2,M[ 7], 6       );
      F5(D1,E1,A1,B1,C1,M[14], 5,MAGIC5);  F1(D2,E2,A2,B2,C2,M[ 6], 8       );
      F5(C1,D1,E1,A1,B1,M[ 1],12,MAGIC5);  F1(C2,D2,E2,A2,B2,M[ 2],13       );
      F5(B1,C1,D1,E1,A1,M[ 3],13,MAGIC5);  F1(B2,C2,D2,E2,A2,M[13], 6       );
      F5(A1,B1,C1,D1,E1,M[ 8],14,MAGIC5);  F1(A2,B2,C2,D2,E2,M[14], 5       );
      F5(E1,A1,B1,C1,D1,M[11],11,MAGIC5);  F1(E2,A2,B2,C2,D2,M[ 0],15       );
      F5(D1,E1,A1,B1,C1,M[ 6], 8,MAGIC5);  F1(D2,E2,A2,B2,C2,M[ 3],13       );
      F5(C1,D1,E1,A1,B1,M[15], 5,MAGIC5);  F1(C2,D2,E2,A2,B2,M[ 9],11       );
      F5(B1,C1,D1,E1,A1,M[13], 6,MAGIC5);  F1(B2,C2,D2,E2,A2,M[11],11       );

      C1        = digest[1] + C1 + D2;
      digest[1] = digest[2] + D1 + E2;
      digest[2] = digest[3] + E1 + A2;
      digest[3] = digest[4] + A1 + B2;
      digest[4] = digest[0] + B1 + C2;
      digest[0] = C1;

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void RIPEMD_160::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_le(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void RIPEMD_160::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   digest[4] = 0xC3D2E1F0;
   }

}
/*
* SHA-160
* (C) 1999-2008,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace SHA1_F {

namespace {

/*
* SHA-160 F1 Function
*/
inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*
* SHA-160 F2 Function
*/
inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*
* SHA-160 F3 Function
*/
inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*
* SHA-160 F4 Function
*/
inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

}

}

/*
* SHA-160 Compression Function
*/
void SHA_160::compress_n(const byte input[], size_t blocks)
   {
   using namespace SHA1_F;

   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4];

   for(size_t i = 0; i != blocks; ++i)
      {
      load_be(&W[0], input, 16);

      for(size_t j = 16; j != 80; j += 8)
         {
         W[j  ] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1);
         W[j+1] = rotate_left((W[j-2] ^ W[j-7] ^ W[j-13] ^ W[j-15]), 1);
         W[j+2] = rotate_left((W[j-1] ^ W[j-6] ^ W[j-12] ^ W[j-14]), 1);
         W[j+3] = rotate_left((W[j  ] ^ W[j-5] ^ W[j-11] ^ W[j-13]), 1);
         W[j+4] = rotate_left((W[j+1] ^ W[j-4] ^ W[j-10] ^ W[j-12]), 1);
         W[j+5] = rotate_left((W[j+2] ^ W[j-3] ^ W[j- 9] ^ W[j-11]), 1);
         W[j+6] = rotate_left((W[j+3] ^ W[j-2] ^ W[j- 8] ^ W[j-10]), 1);
         W[j+7] = rotate_left((W[j+4] ^ W[j-1] ^ W[j- 7] ^ W[j- 9]), 1);
         }

      F1(A, B, C, D, E, W[ 0]);   F1(E, A, B, C, D, W[ 1]);
      F1(D, E, A, B, C, W[ 2]);   F1(C, D, E, A, B, W[ 3]);
      F1(B, C, D, E, A, W[ 4]);   F1(A, B, C, D, E, W[ 5]);
      F1(E, A, B, C, D, W[ 6]);   F1(D, E, A, B, C, W[ 7]);
      F1(C, D, E, A, B, W[ 8]);   F1(B, C, D, E, A, W[ 9]);
      F1(A, B, C, D, E, W[10]);   F1(E, A, B, C, D, W[11]);
      F1(D, E, A, B, C, W[12]);   F1(C, D, E, A, B, W[13]);
      F1(B, C, D, E, A, W[14]);   F1(A, B, C, D, E, W[15]);
      F1(E, A, B, C, D, W[16]);   F1(D, E, A, B, C, W[17]);
      F1(C, D, E, A, B, W[18]);   F1(B, C, D, E, A, W[19]);

      F2(A, B, C, D, E, W[20]);   F2(E, A, B, C, D, W[21]);
      F2(D, E, A, B, C, W[22]);   F2(C, D, E, A, B, W[23]);
      F2(B, C, D, E, A, W[24]);   F2(A, B, C, D, E, W[25]);
      F2(E, A, B, C, D, W[26]);   F2(D, E, A, B, C, W[27]);
      F2(C, D, E, A, B, W[28]);   F2(B, C, D, E, A, W[29]);
      F2(A, B, C, D, E, W[30]);   F2(E, A, B, C, D, W[31]);
      F2(D, E, A, B, C, W[32]);   F2(C, D, E, A, B, W[33]);
      F2(B, C, D, E, A, W[34]);   F2(A, B, C, D, E, W[35]);
      F2(E, A, B, C, D, W[36]);   F2(D, E, A, B, C, W[37]);
      F2(C, D, E, A, B, W[38]);   F2(B, C, D, E, A, W[39]);

      F3(A, B, C, D, E, W[40]);   F3(E, A, B, C, D, W[41]);
      F3(D, E, A, B, C, W[42]);   F3(C, D, E, A, B, W[43]);
      F3(B, C, D, E, A, W[44]);   F3(A, B, C, D, E, W[45]);
      F3(E, A, B, C, D, W[46]);   F3(D, E, A, B, C, W[47]);
      F3(C, D, E, A, B, W[48]);   F3(B, C, D, E, A, W[49]);
      F3(A, B, C, D, E, W[50]);   F3(E, A, B, C, D, W[51]);
      F3(D, E, A, B, C, W[52]);   F3(C, D, E, A, B, W[53]);
      F3(B, C, D, E, A, W[54]);   F3(A, B, C, D, E, W[55]);
      F3(E, A, B, C, D, W[56]);   F3(D, E, A, B, C, W[57]);
      F3(C, D, E, A, B, W[58]);   F3(B, C, D, E, A, W[59]);

      F4(A, B, C, D, E, W[60]);   F4(E, A, B, C, D, W[61]);
      F4(D, E, A, B, C, W[62]);   F4(C, D, E, A, B, W[63]);
      F4(B, C, D, E, A, W[64]);   F4(A, B, C, D, E, W[65]);
      F4(E, A, B, C, D, W[66]);   F4(D, E, A, B, C, W[67]);
      F4(C, D, E, A, B, W[68]);   F4(B, C, D, E, A, W[69]);
      F4(A, B, C, D, E, W[70]);   F4(E, A, B, C, D, W[71]);
      F4(D, E, A, B, C, W[72]);   F4(C, D, E, A, B, W[73]);
      F4(B, C, D, E, A, W[74]);   F4(A, B, C, D, E, W[75]);
      F4(E, A, B, C, D, W[76]);   F4(D, E, A, B, C, W[77]);
      F4(C, D, E, A, B, W[78]);   F4(B, C, D, E, A, W[79]);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void SHA_160::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_be(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void SHA_160::clear()
   {
   MDx_HashFunction::clear();
   zeroise(W);
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   digest[4] = 0xC3D2E1F0;
   }

}
/*
* SHA-{224,256}
* (C) 1999-2010 Jack Lloyd
*     2007 FlexSecure GmbH
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

namespace SHA2_32 {

/*
* SHA-256 Rho Function
*/
inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^
           rotate_right(X, rot3));
   }

/*
* SHA-256 Sigma Function
*/
inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift));
   }

/*
* SHA-256 F1 Function
*
* Use a macro as many compilers won't inline a function this big,
* even though it is much faster if inlined.
*/
#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic)   \
   do {                                                            \
      H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + M1;  \
      D += H;                                                      \
      H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C));          \
      M1 += sigma(M2, 17, 19, 10) + M3 + sigma(M4, 7, 18, 3);      \
   } while(0);

/*
* SHA-224 / SHA-256 compression function
*/
void compress(MemoryRegion<u32bit>& digest,
              const byte input[], size_t blocks)
   {
   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4], F = digest[5],
          G = digest[6], H = digest[7];

   for(size_t i = 0; i != blocks; ++i)
      {
      u32bit W00 = load_be<u32bit>(input,  0);
      u32bit W01 = load_be<u32bit>(input,  1);
      u32bit W02 = load_be<u32bit>(input,  2);
      u32bit W03 = load_be<u32bit>(input,  3);
      u32bit W04 = load_be<u32bit>(input,  4);
      u32bit W05 = load_be<u32bit>(input,  5);
      u32bit W06 = load_be<u32bit>(input,  6);
      u32bit W07 = load_be<u32bit>(input,  7);
      u32bit W08 = load_be<u32bit>(input,  8);
      u32bit W09 = load_be<u32bit>(input,  9);
      u32bit W10 = load_be<u32bit>(input, 10);
      u32bit W11 = load_be<u32bit>(input, 11);
      u32bit W12 = load_be<u32bit>(input, 12);
      u32bit W13 = load_be<u32bit>(input, 13);
      u32bit W14 = load_be<u32bit>(input, 14);
      u32bit W15 = load_be<u32bit>(input, 15);

      SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98);
      SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491);
      SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF);
      SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5);
      SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B);
      SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1);
      SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4);
      SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5);
      SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98);
      SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01);
      SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE);
      SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3);
      SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74);
      SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE);
      SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7);
      SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174);
      SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1);
      SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786);
      SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6);
      SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC);
      SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F);
      SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA);
      SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC);
      SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA);
      SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152);
      SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D);
      SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8);
      SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7);
      SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3);
      SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147);
      SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351);
      SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967);
      SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85);
      SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138);
      SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC);
      SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13);
      SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354);
      SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB);
      SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E);
      SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85);
      SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1);
      SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B);
      SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70);
      SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3);
      SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819);
      SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624);
      SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585);
      SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070);
      SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116);
      SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08);
      SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C);
      SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5);
      SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3);
      SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A);
      SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F);
      SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3);
      SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE);
      SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F);
      SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814);
      SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208);
      SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA);
      SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB);
      SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7);
      SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);
      F = (digest[5] += F);
      G = (digest[6] += G);
      H = (digest[7] += H);

      input += 64;
      }
   }

}

}

/*
* SHA-224 compression function
*/
void SHA_224::compress_n(const byte input[], size_t blocks)
   {
   SHA2_32::compress(digest, input, blocks);
   }

/*
* Copy out the digest
*/
void SHA_224::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_be(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void SHA_224::clear()
   {
   MDx_HashFunction::clear();
   digest[0] = 0xC1059ED8;
   digest[1] = 0x367CD507;
   digest[2] = 0x3070DD17;
   digest[3] = 0xF70E5939;
   digest[4] = 0xFFC00B31;
   digest[5] = 0x68581511;
   digest[6] = 0x64F98FA7;
   digest[7] = 0xBEFA4FA4;
   }

/*
* SHA-256 compression function
*/
void SHA_256::compress_n(const byte input[], size_t blocks)
   {
   SHA2_32::compress(digest, input, blocks);
   }

/*
* Copy out the digest
*/
void SHA_256::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 4)
      store_be(digest[i/4], output + i);
   }

/*
* Clear memory of sensitive data
*/
void SHA_256::clear()
   {
   MDx_HashFunction::clear();
   digest[0] = 0x6A09E667;
   digest[1] = 0xBB67AE85;
   digest[2] = 0x3C6EF372;
   digest[3] = 0xA54FF53A;
   digest[4] = 0x510E527F;
   digest[5] = 0x9B05688C;
   digest[6] = 0x1F83D9AB;
   digest[7] = 0x5BE0CD19;
   }

}
/*
* SHA-{384,512}
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

namespace SHA2_64 {

/*
* SHA-{384,512} Rho Function
*/
inline u64bit rho(u64bit X, u32bit rot1, u32bit rot2, u32bit rot3)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^
           rotate_right(X, rot3));
   }

/*
* SHA-{384,512} Sigma Function
*/
inline u64bit sigma(u64bit X, u32bit rot1, u32bit rot2, u32bit shift)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift));
   }

/*
* SHA-512 F1 Function
*
* Use a macro as many compilers won't inline a function this big,
* even though it is much faster if inlined.
*/
#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic)   \
   do {                                                            \
      H += magic + rho(E, 14, 18, 41) + ((E & F) ^ (~E & G)) + M1; \
      D += H;                                                      \
      H += rho(A, 28, 34, 39) + ((A & B) | ((A | B) & C));         \
      M1 += sigma(M2, 19, 61, 6) + M3 + sigma(M4, 1, 8, 7);        \
   } while(0);

/*
* SHA-{384,512} Compression Function
*/
void compress(MemoryRegion<u64bit>& digest,
              const byte input[], size_t blocks)
   {
   u64bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4], F = digest[5],
          G = digest[6], H = digest[7];

   for(size_t i = 0; i != blocks; ++i)
      {
      u64bit W00 = load_be<u64bit>(input,  0);
      u64bit W01 = load_be<u64bit>(input,  1);
      u64bit W02 = load_be<u64bit>(input,  2);
      u64bit W03 = load_be<u64bit>(input,  3);
      u64bit W04 = load_be<u64bit>(input,  4);
      u64bit W05 = load_be<u64bit>(input,  5);
      u64bit W06 = load_be<u64bit>(input,  6);
      u64bit W07 = load_be<u64bit>(input,  7);
      u64bit W08 = load_be<u64bit>(input,  8);
      u64bit W09 = load_be<u64bit>(input,  9);
      u64bit W10 = load_be<u64bit>(input, 10);
      u64bit W11 = load_be<u64bit>(input, 11);
      u64bit W12 = load_be<u64bit>(input, 12);
      u64bit W13 = load_be<u64bit>(input, 13);
      u64bit W14 = load_be<u64bit>(input, 14);
      u64bit W15 = load_be<u64bit>(input, 15);

      SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CDULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2FULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBCULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9BULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBEULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28CULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896FULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235ULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5ULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4ULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFABULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213FULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826FULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFCULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AEDULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DFULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DEULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6ULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353BULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791ULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202AULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99ULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACBULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373ULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3ULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FCULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72ULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439ECULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915ULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532BULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619CULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1EULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178ULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBAULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6ULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAEULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471BULL);
      SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84ULL);
      SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493ULL);
      SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBCULL);
      SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4CULL);
      SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6ULL);
      SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2AULL);
      SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAECULL);
      SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817ULL);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);
      F = (digest[5] += F);
      G = (digest[6] += G);
      H = (digest[7] += H);

      input += 128;
      }
   }

}

}

/*
* SHA-384 compression function
*/
void SHA_384::compress_n(const byte input[], size_t blocks)
   {
   SHA2_64::compress(digest, input, blocks);
   }

/*
* Copy out the digest
*/
void SHA_384::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 8)
      store_be(digest[i/8], output + i);
   }

/*
* Clear memory of sensitive data
*/
void SHA_384::clear()
   {
   MDx_HashFunction::clear();
   digest[0] = 0xCBBB9D5DC1059ED8ULL;
   digest[1] = 0x629A292A367CD507ULL;
   digest[2] = 0x9159015A3070DD17ULL;
   digest[3] = 0x152FECD8F70E5939ULL;
   digest[4] = 0x67332667FFC00B31ULL;
   digest[5] = 0x8EB44A8768581511ULL;
   digest[6] = 0xDB0C2E0D64F98FA7ULL;
   digest[7] = 0x47B5481DBEFA4FA4ULL;
   }

/*
* SHA-512 compression function
*/
void SHA_512::compress_n(const byte input[], size_t blocks)
   {
   SHA2_64::compress(digest, input, blocks);
   }

/*
* Copy out the digest
*/
void SHA_512::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 8)
      store_be(digest[i/8], output + i);
   }

/*
* Clear memory of sensitive data
*/
void SHA_512::clear()
   {
   MDx_HashFunction::clear();
   digest[0] = 0x6A09E667F3BCC908ULL;
   digest[1] = 0xBB67AE8584CAA73BULL;
   digest[2] = 0x3C6EF372FE94F82BULL;
   digest[3] = 0xA54FF53A5F1D36F1ULL;
   digest[4] = 0x510E527FADE682D1ULL;
   digest[5] = 0x9B05688C2B3E6C1FULL;
   digest[6] = 0x1F83D9ABFB41BD6BULL;
   digest[7] = 0x5BE0CD19137E2179ULL;
   }

}
/*
* The Skein-512 hash function
* (C) 2009-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

enum type_code {
   SKEIN_KEY = 0,
   SKEIN_CONFIG = 4,
   SKEIN_PERSONALIZATION = 8,
   SKEIN_PUBLIC_KEY = 12,
   SKEIN_KEY_IDENTIFIER = 16,
   SKEIN_NONCE = 20,
   SKEIN_MSG = 48,
   SKEIN_OUTPUT = 63
};

void ubi_512(MemoryRegion<u64bit>& H,
             MemoryRegion<u64bit>& T,
             const byte msg[], size_t msg_len)
   {
   do
      {
      const size_t to_proc = std::min<size_t>(msg_len, 64);
      T[0] += to_proc;

      u64bit M[8] = { 0 };

      load_le(M, msg, to_proc / 8);

      if(to_proc % 8)
         {
         for(size_t j = 0; j != to_proc % 8; ++j)
           M[to_proc/8] |= static_cast<u64bit>(msg[8*(to_proc/8)+j]) << (8*j);
         }

      H[8] = H[0] ^ H[1] ^ H[2] ^ H[3] ^
             H[4] ^ H[5] ^ H[6] ^ H[7] ^ 0x1BD11BDAA9FC1A22ULL;

      T[2] = T[0] ^ T[1];

      u64bit X0 = M[0] + H[0];
      u64bit X1 = M[1] + H[1];
      u64bit X2 = M[2] + H[2];
      u64bit X3 = M[3] + H[3];
      u64bit X4 = M[4] + H[4];
      u64bit X5 = M[5] + H[5] + T[0];
      u64bit X6 = M[6] + H[6] + T[1];
      u64bit X7 = M[7] + H[7];

#define THREEFISH_ROUND(I1,I2,I3,I4,I5,I6,I7,I8,ROT1,ROT2,ROT3,ROT4)   \
      do {                                                             \
         X##I1 += X##I2; X##I2 = rotate_left(X##I2, ROT1) ^ X##I1;     \
         X##I3 += X##I4; X##I4 = rotate_left(X##I4, ROT2) ^ X##I3;     \
         X##I5 += X##I6; X##I6 = rotate_left(X##I6, ROT3) ^ X##I5;     \
         X##I7 += X##I8; X##I8 = rotate_left(X##I8, ROT4) ^ X##I7;     \
      } while(0);

#define THREEFISH_INJECT_KEY(r)                 \
      do {                                      \
         X0 += H[(r  ) % 9];                    \
         X1 += H[(r+1) % 9];                    \
         X2 += H[(r+2) % 9];                    \
         X3 += H[(r+3) % 9];                    \
         X4 += H[(r+4) % 9];                    \
         X5 += H[(r+5) % 9] + T[(r  ) % 3];     \
         X6 += H[(r+6) % 9] + T[(r+1) % 3];     \
         X7 += H[(r+7) % 9] + (r);              \
      } while(0);

#define THREEFISH_8_ROUNDS(R1,R2)                         \
      do {                                                \
         THREEFISH_ROUND(0,1,2,3,4,5,6,7, 46,36,19,37);   \
         THREEFISH_ROUND(2,1,4,7,6,5,0,3, 33,27,14,42);   \
         THREEFISH_ROUND(4,1,6,3,0,5,2,7, 17,49,36,39);   \
         THREEFISH_ROUND(6,1,0,7,2,5,4,3, 44, 9,54,56);   \
                                                          \
         THREEFISH_INJECT_KEY(R1);                        \
                                                          \
         THREEFISH_ROUND(0,1,2,3,4,5,6,7, 39,30,34,24);   \
         THREEFISH_ROUND(2,1,4,7,6,5,0,3, 13,50,10,17);   \
         THREEFISH_ROUND(4,1,6,3,0,5,2,7, 25,29,39,43);   \
         THREEFISH_ROUND(6,1,0,7,2,5,4,3,  8,35,56,22);   \
                                                          \
         THREEFISH_INJECT_KEY(R2);                        \
      } while(0);

      THREEFISH_8_ROUNDS(1,2);
      THREEFISH_8_ROUNDS(3,4);
      THREEFISH_8_ROUNDS(5,6);
      THREEFISH_8_ROUNDS(7,8);
      THREEFISH_8_ROUNDS(9,10);
      THREEFISH_8_ROUNDS(11,12);
      THREEFISH_8_ROUNDS(13,14);
      THREEFISH_8_ROUNDS(15,16);
      THREEFISH_8_ROUNDS(17,18);

      // message feed forward
      H[0] = X0 ^ M[0];
      H[1] = X1 ^ M[1];
      H[2] = X2 ^ M[2];
      H[3] = X3 ^ M[3];
      H[4] = X4 ^ M[4];
      H[5] = X5 ^ M[5];
      H[6] = X6 ^ M[6];
      H[7] = X7 ^ M[7];

      // clear first flag if set
      T[1] &= ~(static_cast<u64bit>(1) << 62);

      msg_len -= to_proc;
      msg += to_proc;
      } while(msg_len);
   }

void reset_tweak(MemoryRegion<u64bit>& T,
                 type_code type, bool final)
   {
   T[0] = 0;

   T[1] = (static_cast<u64bit>(type) << 56) |
          (static_cast<u64bit>(1) << 62) |
          (static_cast<u64bit>(final) << 63);
   }

void initial_block(MemoryRegion<u64bit>& H,
                   MemoryRegion<u64bit>& T,
                   size_t output_bits,
                   const std::string& personalization)
   {
   zeroise(H);

   // ASCII("SHA3") followed by version (0x0001) code
   byte config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 };
   store_le(u32bit(output_bits), config_str + 8);

   reset_tweak(T, SKEIN_CONFIG, true);
   ubi_512(H, T, config_str, sizeof(config_str));

   if(personalization != "")
      {
      /*
        This is a limitation of this implementation, and not of the
        algorithm specification. Could be fixed relatively easily, but
        doesn't seem worth the trouble.
      */
      if(personalization.length() > 64)
         throw Invalid_Argument("Skein personalization must be <= 64 bytes");

      const byte* bits = reinterpret_cast<const byte*>(personalization.data());

      reset_tweak(T, SKEIN_PERSONALIZATION, true);
      ubi_512(H, T, bits, personalization.length());
      }

   reset_tweak(T, SKEIN_MSG, false);
   }

}

Skein_512::Skein_512(size_t arg_output_bits,
                     const std::string& arg_personalization) :
   personalization(arg_personalization),
   output_bits(arg_output_bits),
   H(9), T(3), buffer(64), buf_pos(0)
   {
   if(output_bits == 0 || output_bits % 8 != 0 || output_bits > 64*1024)
      throw Invalid_Argument("Bad output bits size for Skein-512");

   initial_block(H, T, output_bits, personalization);
   }

std::string Skein_512::name() const
   {
   if(personalization != "")
      return "Skein-512(" + to_string(output_bits) + "," + personalization + ")";
   return "Skein-512(" + to_string(output_bits) + ")";
   }

HashFunction* Skein_512::clone() const
   {
   return new Skein_512(output_bits, personalization);
   }

void Skein_512::clear()
   {
   zeroise(H);
   zeroise(T);
   zeroise(buffer);
   buf_pos = 0;
   }

void Skein_512::add_data(const byte input[], size_t length)
   {
   if(length == 0)
      return;

   if(buf_pos)
      {
      buffer.copy(buf_pos, input, length);
      if(buf_pos + length > 64)
         {
         ubi_512(H, T, &buffer[0], buffer.size());

         input += (64 - buf_pos);
         length -= (64 - buf_pos);
         buf_pos = 0;
         }
      }

   const size_t full_blocks = (length - 1) / 64;

   if(full_blocks)
      ubi_512(H, T, input, 64*full_blocks);

   length -= full_blocks * 64;

   buffer.copy(buf_pos, input + full_blocks * 64, length);
   buf_pos += length;
   }

void Skein_512::final_result(byte out[])
   {
   T[1] |= (static_cast<u64bit>(1) << 63); // final block flag

   for(size_t i = buf_pos; i != buffer.size(); ++i)
      buffer[i] = 0;

   ubi_512(H, T, &buffer[0], buf_pos);

   byte counter[8] = { 0 };

   size_t out_bytes = output_bits / 8;

   SecureVector<u64bit> H_out(9);

   while(out_bytes)
      {
      const size_t to_proc = std::min<size_t>(out_bytes, 64);

      H_out.copy(&H[0], 8);

      reset_tweak(T, SKEIN_OUTPUT, true);
      ubi_512(H_out, T, counter, sizeof(counter));

      for(size_t i = 0; i != to_proc; ++i)
         out[i] = get_byte(7-i%8, H_out[i/8]);

      out_bytes -= to_proc;
      out += to_proc;

      for(size_t i = 0; i != sizeof(counter); ++i)
         if(++counter[i])
            break;
      }

   buf_pos = 0;
   initial_block(H, T, output_bits, personalization);
   }

}
/*
* S-Box Tables for Tiger
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u64bit Tiger::SBOX1[256] = {
   0x02AAB17CF7E90C5EULL, 0xAC424B03E243A8ECULL, 0x72CD5BE30DD5FCD3ULL,
   0x6D019B93F6F97F3AULL, 0xCD9978FFD21F9193ULL, 0x7573A1C9708029E2ULL,
   0xB164326B922A83C3ULL, 0x46883EEE04915870ULL, 0xEAACE3057103ECE6ULL,
   0xC54169B808A3535CULL, 0x4CE754918DDEC47CULL, 0x0AA2F4DFDC0DF40CULL,
   0x10B76F18A74DBEFAULL, 0xC6CCB6235AD1AB6AULL, 0x13726121572FE2FFULL,
   0x1A488C6F199D921EULL, 0x4BC9F9F4DA0007CAULL, 0x26F5E6F6E85241C7ULL,
   0x859079DBEA5947B6ULL, 0x4F1885C5C99E8C92ULL, 0xD78E761EA96F864BULL,
   0x8E36428C52B5C17DULL, 0x69CF6827373063C1ULL, 0xB607C93D9BB4C56EULL,
   0x7D820E760E76B5EAULL, 0x645C9CC6F07FDC42ULL, 0xBF38A078243342E0ULL,
   0x5F6B343C9D2E7D04ULL, 0xF2C28AEB600B0EC6ULL, 0x6C0ED85F7254BCACULL,
   0x71592281A4DB4FE5ULL, 0x1967FA69CE0FED9FULL, 0xFD5293F8B96545DBULL,
   0xC879E9D7F2A7600BULL, 0x860248920193194EULL, 0xA4F9533B2D9CC0B3ULL,
   0x9053836C15957613ULL, 0xDB6DCF8AFC357BF1ULL, 0x18BEEA7A7A370F57ULL,
   0x037117CA50B99066ULL, 0x6AB30A9774424A35ULL, 0xF4E92F02E325249BULL,
   0x7739DB07061CCAE1ULL, 0xD8F3B49CECA42A05ULL, 0xBD56BE3F51382F73ULL,
   0x45FAED5843B0BB28ULL, 0x1C813D5C11BF1F83ULL, 0x8AF0E4B6D75FA169ULL,
   0x33EE18A487AD9999ULL, 0x3C26E8EAB1C94410ULL, 0xB510102BC0A822F9ULL,
   0x141EEF310CE6123BULL, 0xFC65B90059DDB154ULL, 0xE0158640C5E0E607ULL,
   0x884E079826C3A3CFULL, 0x930D0D9523C535FDULL, 0x35638D754E9A2B00ULL,
   0x4085FCCF40469DD5ULL, 0xC4B17AD28BE23A4CULL, 0xCAB2F0FC6A3E6A2EULL,
   0x2860971A6B943FCDULL, 0x3DDE6EE212E30446ULL, 0x6222F32AE01765AEULL,
   0x5D550BB5478308FEULL, 0xA9EFA98DA0EDA22AULL, 0xC351A71686C40DA7ULL,
   0x1105586D9C867C84ULL, 0xDCFFEE85FDA22853ULL, 0xCCFBD0262C5EEF76ULL,
   0xBAF294CB8990D201ULL, 0xE69464F52AFAD975ULL, 0x94B013AFDF133E14ULL,
   0x06A7D1A32823C958ULL, 0x6F95FE5130F61119ULL, 0xD92AB34E462C06C0ULL,
   0xED7BDE33887C71D2ULL, 0x79746D6E6518393EULL, 0x5BA419385D713329ULL,
   0x7C1BA6B948A97564ULL, 0x31987C197BFDAC67ULL, 0xDE6C23C44B053D02ULL,
   0x581C49FED002D64DULL, 0xDD474D6338261571ULL, 0xAA4546C3E473D062ULL,
   0x928FCE349455F860ULL, 0x48161BBACAAB94D9ULL, 0x63912430770E6F68ULL,
   0x6EC8A5E602C6641CULL, 0x87282515337DDD2BULL, 0x2CDA6B42034B701BULL,
   0xB03D37C181CB096DULL, 0xE108438266C71C6FULL, 0x2B3180C7EB51B255ULL,
   0xDF92B82F96C08BBCULL, 0x5C68C8C0A632F3BAULL, 0x5504CC861C3D0556ULL,
   0xABBFA4E55FB26B8FULL, 0x41848B0AB3BACEB4ULL, 0xB334A273AA445D32ULL,
   0xBCA696F0A85AD881ULL, 0x24F6EC65B528D56CULL, 0x0CE1512E90F4524AULL,
   0x4E9DD79D5506D35AULL, 0x258905FAC6CE9779ULL, 0x2019295B3E109B33ULL,
   0xF8A9478B73A054CCULL, 0x2924F2F934417EB0ULL, 0x3993357D536D1BC4ULL,
   0x38A81AC21DB6FF8BULL, 0x47C4FBF17D6016BFULL, 0x1E0FAADD7667E3F5ULL,
   0x7ABCFF62938BEB96ULL, 0xA78DAD948FC179C9ULL, 0x8F1F98B72911E50DULL,
   0x61E48EAE27121A91ULL, 0x4D62F7AD31859808ULL, 0xECEBA345EF5CEAEBULL,
   0xF5CEB25EBC9684CEULL, 0xF633E20CB7F76221ULL, 0xA32CDF06AB8293E4ULL,
   0x985A202CA5EE2CA4ULL, 0xCF0B8447CC8A8FB1ULL, 0x9F765244979859A3ULL,
   0xA8D516B1A1240017ULL, 0x0BD7BA3EBB5DC726ULL, 0xE54BCA55B86ADB39ULL,
   0x1D7A3AFD6C478063ULL, 0x519EC608E7669EDDULL, 0x0E5715A2D149AA23ULL,
   0x177D4571848FF194ULL, 0xEEB55F3241014C22ULL, 0x0F5E5CA13A6E2EC2ULL,
   0x8029927B75F5C361ULL, 0xAD139FABC3D6E436ULL, 0x0D5DF1A94CCF402FULL,
   0x3E8BD948BEA5DFC8ULL, 0xA5A0D357BD3FF77EULL, 0xA2D12E251F74F645ULL,
   0x66FD9E525E81A082ULL, 0x2E0C90CE7F687A49ULL, 0xC2E8BCBEBA973BC5ULL,
   0x000001BCE509745FULL, 0x423777BBE6DAB3D6ULL, 0xD1661C7EAEF06EB5ULL,
   0xA1781F354DAACFD8ULL, 0x2D11284A2B16AFFCULL, 0xF1FC4F67FA891D1FULL,
   0x73ECC25DCB920ADAULL, 0xAE610C22C2A12651ULL, 0x96E0A810D356B78AULL,
   0x5A9A381F2FE7870FULL, 0xD5AD62EDE94E5530ULL, 0xD225E5E8368D1427ULL,
   0x65977B70C7AF4631ULL, 0x99F889B2DE39D74FULL, 0x233F30BF54E1D143ULL,
   0x9A9675D3D9A63C97ULL, 0x5470554FF334F9A8ULL, 0x166ACB744A4F5688ULL,
   0x70C74CAAB2E4AEADULL, 0xF0D091646F294D12ULL, 0x57B82A89684031D1ULL,
   0xEFD95A5A61BE0B6BULL, 0x2FBD12E969F2F29AULL, 0x9BD37013FEFF9FE8ULL,
   0x3F9B0404D6085A06ULL, 0x4940C1F3166CFE15ULL, 0x09542C4DCDF3DEFBULL,
   0xB4C5218385CD5CE3ULL, 0xC935B7DC4462A641ULL, 0x3417F8A68ED3B63FULL,
   0xB80959295B215B40ULL, 0xF99CDAEF3B8C8572ULL, 0x018C0614F8FCB95DULL,
   0x1B14ACCD1A3ACDF3ULL, 0x84D471F200BB732DULL, 0xC1A3110E95E8DA16ULL,
   0x430A7220BF1A82B8ULL, 0xB77E090D39DF210EULL, 0x5EF4BD9F3CD05E9DULL,
   0x9D4FF6DA7E57A444ULL, 0xDA1D60E183D4A5F8ULL, 0xB287C38417998E47ULL,
   0xFE3EDC121BB31886ULL, 0xC7FE3CCC980CCBEFULL, 0xE46FB590189BFD03ULL,
   0x3732FD469A4C57DCULL, 0x7EF700A07CF1AD65ULL, 0x59C64468A31D8859ULL,
   0x762FB0B4D45B61F6ULL, 0x155BAED099047718ULL, 0x68755E4C3D50BAA6ULL,
   0xE9214E7F22D8B4DFULL, 0x2ADDBF532EAC95F4ULL, 0x32AE3909B4BD0109ULL,
   0x834DF537B08E3450ULL, 0xFA209DA84220728DULL, 0x9E691D9B9EFE23F7ULL,
   0x0446D288C4AE8D7FULL, 0x7B4CC524E169785BULL, 0x21D87F0135CA1385ULL,
   0xCEBB400F137B8AA5ULL, 0x272E2B66580796BEULL, 0x3612264125C2B0DEULL,
   0x057702BDAD1EFBB2ULL, 0xD4BABB8EACF84BE9ULL, 0x91583139641BC67BULL,
   0x8BDC2DE08036E024ULL, 0x603C8156F49F68EDULL, 0xF7D236F7DBEF5111ULL,
   0x9727C4598AD21E80ULL, 0xA08A0896670A5FD7ULL, 0xCB4A8F4309EBA9CBULL,
   0x81AF564B0F7036A1ULL, 0xC0B99AA778199ABDULL, 0x959F1EC83FC8E952ULL,
   0x8C505077794A81B9ULL, 0x3ACAAF8F056338F0ULL, 0x07B43F50627A6778ULL,
   0x4A44AB49F5ECCC77ULL, 0x3BC3D6E4B679EE98ULL, 0x9CC0D4D1CF14108CULL,
   0x4406C00B206BC8A0ULL, 0x82A18854C8D72D89ULL, 0x67E366B35C3C432CULL,
   0xB923DD61102B37F2ULL, 0x56AB2779D884271DULL, 0xBE83E1B0FF1525AFULL,
   0xFB7C65D4217E49A9ULL, 0x6BDBE0E76D48E7D4ULL, 0x08DF828745D9179EULL,
   0x22EA6A9ADD53BD34ULL, 0xE36E141C5622200AULL, 0x7F805D1B8CB750EEULL,
   0xAFE5C7A59F58E837ULL, 0xE27F996A4FB1C23CULL, 0xD3867DFB0775F0D0ULL,
   0xD0E673DE6E88891AULL, 0x123AEB9EAFB86C25ULL, 0x30F1D5D5C145B895ULL,
   0xBB434A2DEE7269E7ULL, 0x78CB67ECF931FA38ULL, 0xF33B0372323BBF9CULL,
   0x52D66336FB279C74ULL, 0x505F33AC0AFB4EAAULL, 0xE8A5CD99A2CCE187ULL,
   0x534974801E2D30BBULL, 0x8D2D5711D5876D90ULL, 0x1F1A412891BC038EULL,
   0xD6E2E71D82E56648ULL, 0x74036C3A497732B7ULL, 0x89B67ED96361F5ABULL,
   0xFFED95D8F1EA02A2ULL, 0xE72B3BD61464D43DULL, 0xA6300F170BDC4820ULL,
   0xEBC18760ED78A77AULL };

const u64bit Tiger::SBOX2[256] = {
   0xE6A6BE5A05A12138ULL, 0xB5A122A5B4F87C98ULL, 0x563C6089140B6990ULL,
   0x4C46CB2E391F5DD5ULL, 0xD932ADDBC9B79434ULL, 0x08EA70E42015AFF5ULL,
   0xD765A6673E478CF1ULL, 0xC4FB757EAB278D99ULL, 0xDF11C6862D6E0692ULL,
   0xDDEB84F10D7F3B16ULL, 0x6F2EF604A665EA04ULL, 0x4A8E0F0FF0E0DFB3ULL,
   0xA5EDEEF83DBCBA51ULL, 0xFC4F0A2A0EA4371EULL, 0xE83E1DA85CB38429ULL,
   0xDC8FF882BA1B1CE2ULL, 0xCD45505E8353E80DULL, 0x18D19A00D4DB0717ULL,
   0x34A0CFEDA5F38101ULL, 0x0BE77E518887CAF2ULL, 0x1E341438B3C45136ULL,
   0xE05797F49089CCF9ULL, 0xFFD23F9DF2591D14ULL, 0x543DDA228595C5CDULL,
   0x661F81FD99052A33ULL, 0x8736E641DB0F7B76ULL, 0x15227725418E5307ULL,
   0xE25F7F46162EB2FAULL, 0x48A8B2126C13D9FEULL, 0xAFDC541792E76EEAULL,
   0x03D912BFC6D1898FULL, 0x31B1AAFA1B83F51BULL, 0xF1AC2796E42AB7D9ULL,
   0x40A3A7D7FCD2EBACULL, 0x1056136D0AFBBCC5ULL, 0x7889E1DD9A6D0C85ULL,
   0xD33525782A7974AAULL, 0xA7E25D09078AC09BULL, 0xBD4138B3EAC6EDD0ULL,
   0x920ABFBE71EB9E70ULL, 0xA2A5D0F54FC2625CULL, 0xC054E36B0B1290A3ULL,
   0xF6DD59FF62FE932BULL, 0x3537354511A8AC7DULL, 0xCA845E9172FADCD4ULL,
   0x84F82B60329D20DCULL, 0x79C62CE1CD672F18ULL, 0x8B09A2ADD124642CULL,
   0xD0C1E96A19D9E726ULL, 0x5A786A9B4BA9500CULL, 0x0E020336634C43F3ULL,
   0xC17B474AEB66D822ULL, 0x6A731AE3EC9BAAC2ULL, 0x8226667AE0840258ULL,
   0x67D4567691CAECA5ULL, 0x1D94155C4875ADB5ULL, 0x6D00FD985B813FDFULL,
   0x51286EFCB774CD06ULL, 0x5E8834471FA744AFULL, 0xF72CA0AEE761AE2EULL,
   0xBE40E4CDAEE8E09AULL, 0xE9970BBB5118F665ULL, 0x726E4BEB33DF1964ULL,
   0x703B000729199762ULL, 0x4631D816F5EF30A7ULL, 0xB880B5B51504A6BEULL,
   0x641793C37ED84B6CULL, 0x7B21ED77F6E97D96ULL, 0x776306312EF96B73ULL,
   0xAE528948E86FF3F4ULL, 0x53DBD7F286A3F8F8ULL, 0x16CADCE74CFC1063ULL,
   0x005C19BDFA52C6DDULL, 0x68868F5D64D46AD3ULL, 0x3A9D512CCF1E186AULL,
   0x367E62C2385660AEULL, 0xE359E7EA77DCB1D7ULL, 0x526C0773749ABE6EULL,
   0x735AE5F9D09F734BULL, 0x493FC7CC8A558BA8ULL, 0xB0B9C1533041AB45ULL,
   0x321958BA470A59BDULL, 0x852DB00B5F46C393ULL, 0x91209B2BD336B0E5ULL,
   0x6E604F7D659EF19FULL, 0xB99A8AE2782CCB24ULL, 0xCCF52AB6C814C4C7ULL,
   0x4727D9AFBE11727BULL, 0x7E950D0C0121B34DULL, 0x756F435670AD471FULL,
   0xF5ADD442615A6849ULL, 0x4E87E09980B9957AULL, 0x2ACFA1DF50AEE355ULL,
   0xD898263AFD2FD556ULL, 0xC8F4924DD80C8FD6ULL, 0xCF99CA3D754A173AULL,
   0xFE477BACAF91BF3CULL, 0xED5371F6D690C12DULL, 0x831A5C285E687094ULL,
   0xC5D3C90A3708A0A4ULL, 0x0F7F903717D06580ULL, 0x19F9BB13B8FDF27FULL,
   0xB1BD6F1B4D502843ULL, 0x1C761BA38FFF4012ULL, 0x0D1530C4E2E21F3BULL,
   0x8943CE69A7372C8AULL, 0xE5184E11FEB5CE66ULL, 0x618BDB80BD736621ULL,
   0x7D29BAD68B574D0BULL, 0x81BB613E25E6FE5BULL, 0x071C9C10BC07913FULL,
   0xC7BEEB7909AC2D97ULL, 0xC3E58D353BC5D757ULL, 0xEB017892F38F61E8ULL,
   0xD4EFFB9C9B1CC21AULL, 0x99727D26F494F7ABULL, 0xA3E063A2956B3E03ULL,
   0x9D4A8B9A4AA09C30ULL, 0x3F6AB7D500090FB4ULL, 0x9CC0F2A057268AC0ULL,
   0x3DEE9D2DEDBF42D1ULL, 0x330F49C87960A972ULL, 0xC6B2720287421B41ULL,
   0x0AC59EC07C00369CULL, 0xEF4EAC49CB353425ULL, 0xF450244EEF0129D8ULL,
   0x8ACC46E5CAF4DEB6ULL, 0x2FFEAB63989263F7ULL, 0x8F7CB9FE5D7A4578ULL,
   0x5BD8F7644E634635ULL, 0x427A7315BF2DC900ULL, 0x17D0C4AA2125261CULL,
   0x3992486C93518E50ULL, 0xB4CBFEE0A2D7D4C3ULL, 0x7C75D6202C5DDD8DULL,
   0xDBC295D8E35B6C61ULL, 0x60B369D302032B19ULL, 0xCE42685FDCE44132ULL,
   0x06F3DDB9DDF65610ULL, 0x8EA4D21DB5E148F0ULL, 0x20B0FCE62FCD496FULL,
   0x2C1B912358B0EE31ULL, 0xB28317B818F5A308ULL, 0xA89C1E189CA6D2CFULL,
   0x0C6B18576AAADBC8ULL, 0xB65DEAA91299FAE3ULL, 0xFB2B794B7F1027E7ULL,
   0x04E4317F443B5BEBULL, 0x4B852D325939D0A6ULL, 0xD5AE6BEEFB207FFCULL,
   0x309682B281C7D374ULL, 0xBAE309A194C3B475ULL, 0x8CC3F97B13B49F05ULL,
   0x98A9422FF8293967ULL, 0x244B16B01076FF7CULL, 0xF8BF571C663D67EEULL,
   0x1F0D6758EEE30DA1ULL, 0xC9B611D97ADEB9B7ULL, 0xB7AFD5887B6C57A2ULL,
   0x6290AE846B984FE1ULL, 0x94DF4CDEACC1A5FDULL, 0x058A5BD1C5483AFFULL,
   0x63166CC142BA3C37ULL, 0x8DB8526EB2F76F40ULL, 0xE10880036F0D6D4EULL,
   0x9E0523C9971D311DULL, 0x45EC2824CC7CD691ULL, 0x575B8359E62382C9ULL,
   0xFA9E400DC4889995ULL, 0xD1823ECB45721568ULL, 0xDAFD983B8206082FULL,
   0xAA7D29082386A8CBULL, 0x269FCD4403B87588ULL, 0x1B91F5F728BDD1E0ULL,
   0xE4669F39040201F6ULL, 0x7A1D7C218CF04ADEULL, 0x65623C29D79CE5CEULL,
   0x2368449096C00BB1ULL, 0xAB9BF1879DA503BAULL, 0xBC23ECB1A458058EULL,
   0x9A58DF01BB401ECCULL, 0xA070E868A85F143DULL, 0x4FF188307DF2239EULL,
   0x14D565B41A641183ULL, 0xEE13337452701602ULL, 0x950E3DCF3F285E09ULL,
   0x59930254B9C80953ULL, 0x3BF299408930DA6DULL, 0xA955943F53691387ULL,
   0xA15EDECAA9CB8784ULL, 0x29142127352BE9A0ULL, 0x76F0371FFF4E7AFBULL,
   0x0239F450274F2228ULL, 0xBB073AF01D5E868BULL, 0xBFC80571C10E96C1ULL,
   0xD267088568222E23ULL, 0x9671A3D48E80B5B0ULL, 0x55B5D38AE193BB81ULL,
   0x693AE2D0A18B04B8ULL, 0x5C48B4ECADD5335FULL, 0xFD743B194916A1CAULL,
   0x2577018134BE98C4ULL, 0xE77987E83C54A4ADULL, 0x28E11014DA33E1B9ULL,
   0x270CC59E226AA213ULL, 0x71495F756D1A5F60ULL, 0x9BE853FB60AFEF77ULL,
   0xADC786A7F7443DBFULL, 0x0904456173B29A82ULL, 0x58BC7A66C232BD5EULL,
   0xF306558C673AC8B2ULL, 0x41F639C6B6C9772AULL, 0x216DEFE99FDA35DAULL,
   0x11640CC71C7BE615ULL, 0x93C43694565C5527ULL, 0xEA038E6246777839ULL,
   0xF9ABF3CE5A3E2469ULL, 0x741E768D0FD312D2ULL, 0x0144B883CED652C6ULL,
   0xC20B5A5BA33F8552ULL, 0x1AE69633C3435A9DULL, 0x97A28CA4088CFDECULL,
   0x8824A43C1E96F420ULL, 0x37612FA66EEEA746ULL, 0x6B4CB165F9CF0E5AULL,
   0x43AA1C06A0ABFB4AULL, 0x7F4DC26FF162796BULL, 0x6CBACC8E54ED9B0FULL,
   0xA6B7FFEFD2BB253EULL, 0x2E25BC95B0A29D4FULL, 0x86D6A58BDEF1388CULL,
   0xDED74AC576B6F054ULL, 0x8030BDBC2B45805DULL, 0x3C81AF70E94D9289ULL,
   0x3EFF6DDA9E3100DBULL, 0xB38DC39FDFCC8847ULL, 0x123885528D17B87EULL,
   0xF2DA0ED240B1B642ULL, 0x44CEFADCD54BF9A9ULL, 0x1312200E433C7EE6ULL,
   0x9FFCC84F3A78C748ULL, 0xF0CD1F72248576BBULL, 0xEC6974053638CFE4ULL,
   0x2BA7B67C0CEC4E4CULL, 0xAC2F4DF3E5CE32EDULL, 0xCB33D14326EA4C11ULL,
   0xA4E9044CC77E58BCULL, 0x5F513293D934FCEFULL, 0x5DC9645506E55444ULL,
   0x50DE418F317DE40AULL, 0x388CB31A69DDE259ULL, 0x2DB4A83455820A86ULL,
   0x9010A91E84711AE9ULL, 0x4DF7F0B7B1498371ULL, 0xD62A2EABC0977179ULL,
   0x22FAC097AA8D5C0EULL };

const u64bit Tiger::SBOX3[256] = {
   0xF49FCC2FF1DAF39BULL, 0x487FD5C66FF29281ULL, 0xE8A30667FCDCA83FULL,
   0x2C9B4BE3D2FCCE63ULL, 0xDA3FF74B93FBBBC2ULL, 0x2FA165D2FE70BA66ULL,
   0xA103E279970E93D4ULL, 0xBECDEC77B0E45E71ULL, 0xCFB41E723985E497ULL,
   0xB70AAA025EF75017ULL, 0xD42309F03840B8E0ULL, 0x8EFC1AD035898579ULL,
   0x96C6920BE2B2ABC5ULL, 0x66AF4163375A9172ULL, 0x2174ABDCCA7127FBULL,
   0xB33CCEA64A72FF41ULL, 0xF04A4933083066A5ULL, 0x8D970ACDD7289AF5ULL,
   0x8F96E8E031C8C25EULL, 0xF3FEC02276875D47ULL, 0xEC7BF310056190DDULL,
   0xF5ADB0AEBB0F1491ULL, 0x9B50F8850FD58892ULL, 0x4975488358B74DE8ULL,
   0xA3354FF691531C61ULL, 0x0702BBE481D2C6EEULL, 0x89FB24057DEDED98ULL,
   0xAC3075138596E902ULL, 0x1D2D3580172772EDULL, 0xEB738FC28E6BC30DULL,
   0x5854EF8F63044326ULL, 0x9E5C52325ADD3BBEULL, 0x90AA53CF325C4623ULL,
   0xC1D24D51349DD067ULL, 0x2051CFEEA69EA624ULL, 0x13220F0A862E7E4FULL,
   0xCE39399404E04864ULL, 0xD9C42CA47086FCB7ULL, 0x685AD2238A03E7CCULL,
   0x066484B2AB2FF1DBULL, 0xFE9D5D70EFBF79ECULL, 0x5B13B9DD9C481854ULL,
   0x15F0D475ED1509ADULL, 0x0BEBCD060EC79851ULL, 0xD58C6791183AB7F8ULL,
   0xD1187C5052F3EEE4ULL, 0xC95D1192E54E82FFULL, 0x86EEA14CB9AC6CA2ULL,
   0x3485BEB153677D5DULL, 0xDD191D781F8C492AULL, 0xF60866BAA784EBF9ULL,
   0x518F643BA2D08C74ULL, 0x8852E956E1087C22ULL, 0xA768CB8DC410AE8DULL,
   0x38047726BFEC8E1AULL, 0xA67738B4CD3B45AAULL, 0xAD16691CEC0DDE19ULL,
   0xC6D4319380462E07ULL, 0xC5A5876D0BA61938ULL, 0x16B9FA1FA58FD840ULL,
   0x188AB1173CA74F18ULL, 0xABDA2F98C99C021FULL, 0x3E0580AB134AE816ULL,
   0x5F3B05B773645ABBULL, 0x2501A2BE5575F2F6ULL, 0x1B2F74004E7E8BA9ULL,
   0x1CD7580371E8D953ULL, 0x7F6ED89562764E30ULL, 0xB15926FF596F003DULL,
   0x9F65293DA8C5D6B9ULL, 0x6ECEF04DD690F84CULL, 0x4782275FFF33AF88ULL,
   0xE41433083F820801ULL, 0xFD0DFE409A1AF9B5ULL, 0x4325A3342CDB396BULL,
   0x8AE77E62B301B252ULL, 0xC36F9E9F6655615AULL, 0x85455A2D92D32C09ULL,
   0xF2C7DEA949477485ULL, 0x63CFB4C133A39EBAULL, 0x83B040CC6EBC5462ULL,
   0x3B9454C8FDB326B0ULL, 0x56F56A9E87FFD78CULL, 0x2DC2940D99F42BC6ULL,
   0x98F7DF096B096E2DULL, 0x19A6E01E3AD852BFULL, 0x42A99CCBDBD4B40BULL,
   0xA59998AF45E9C559ULL, 0x366295E807D93186ULL, 0x6B48181BFAA1F773ULL,
   0x1FEC57E2157A0A1DULL, 0x4667446AF6201AD5ULL, 0xE615EBCACFB0F075ULL,
   0xB8F31F4F68290778ULL, 0x22713ED6CE22D11EULL, 0x3057C1A72EC3C93BULL,
   0xCB46ACC37C3F1F2FULL, 0xDBB893FD02AAF50EULL, 0x331FD92E600B9FCFULL,
   0xA498F96148EA3AD6ULL, 0xA8D8426E8B6A83EAULL, 0xA089B274B7735CDCULL,
   0x87F6B3731E524A11ULL, 0x118808E5CBC96749ULL, 0x9906E4C7B19BD394ULL,
   0xAFED7F7E9B24A20CULL, 0x6509EADEEB3644A7ULL, 0x6C1EF1D3E8EF0EDEULL,
   0xB9C97D43E9798FB4ULL, 0xA2F2D784740C28A3ULL, 0x7B8496476197566FULL,
   0x7A5BE3E6B65F069DULL, 0xF96330ED78BE6F10ULL, 0xEEE60DE77A076A15ULL,
   0x2B4BEE4AA08B9BD0ULL, 0x6A56A63EC7B8894EULL, 0x02121359BA34FEF4ULL,
   0x4CBF99F8283703FCULL, 0x398071350CAF30C8ULL, 0xD0A77A89F017687AULL,
   0xF1C1A9EB9E423569ULL, 0x8C7976282DEE8199ULL, 0x5D1737A5DD1F7ABDULL,
   0x4F53433C09A9FA80ULL, 0xFA8B0C53DF7CA1D9ULL, 0x3FD9DCBC886CCB77ULL,
   0xC040917CA91B4720ULL, 0x7DD00142F9D1DCDFULL, 0x8476FC1D4F387B58ULL,
   0x23F8E7C5F3316503ULL, 0x032A2244E7E37339ULL, 0x5C87A5D750F5A74BULL,
   0x082B4CC43698992EULL, 0xDF917BECB858F63CULL, 0x3270B8FC5BF86DDAULL,
   0x10AE72BB29B5DD76ULL, 0x576AC94E7700362BULL, 0x1AD112DAC61EFB8FULL,
   0x691BC30EC5FAA427ULL, 0xFF246311CC327143ULL, 0x3142368E30E53206ULL,
   0x71380E31E02CA396ULL, 0x958D5C960AAD76F1ULL, 0xF8D6F430C16DA536ULL,
   0xC8FFD13F1BE7E1D2ULL, 0x7578AE66004DDBE1ULL, 0x05833F01067BE646ULL,
   0xBB34B5AD3BFE586DULL, 0x095F34C9A12B97F0ULL, 0x247AB64525D60CA8ULL,
   0xDCDBC6F3017477D1ULL, 0x4A2E14D4DECAD24DULL, 0xBDB5E6D9BE0A1EEBULL,
   0x2A7E70F7794301ABULL, 0xDEF42D8A270540FDULL, 0x01078EC0A34C22C1ULL,
   0xE5DE511AF4C16387ULL, 0x7EBB3A52BD9A330AULL, 0x77697857AA7D6435ULL,
   0x004E831603AE4C32ULL, 0xE7A21020AD78E312ULL, 0x9D41A70C6AB420F2ULL,
   0x28E06C18EA1141E6ULL, 0xD2B28CBD984F6B28ULL, 0x26B75F6C446E9D83ULL,
   0xBA47568C4D418D7FULL, 0xD80BADBFE6183D8EULL, 0x0E206D7F5F166044ULL,
   0xE258A43911CBCA3EULL, 0x723A1746B21DC0BCULL, 0xC7CAA854F5D7CDD3ULL,
   0x7CAC32883D261D9CULL, 0x7690C26423BA942CULL, 0x17E55524478042B8ULL,
   0xE0BE477656A2389FULL, 0x4D289B5E67AB2DA0ULL, 0x44862B9C8FBBFD31ULL,
   0xB47CC8049D141365ULL, 0x822C1B362B91C793ULL, 0x4EB14655FB13DFD8ULL,
   0x1ECBBA0714E2A97BULL, 0x6143459D5CDE5F14ULL, 0x53A8FBF1D5F0AC89ULL,
   0x97EA04D81C5E5B00ULL, 0x622181A8D4FDB3F3ULL, 0xE9BCD341572A1208ULL,
   0x1411258643CCE58AULL, 0x9144C5FEA4C6E0A4ULL, 0x0D33D06565CF620FULL,
   0x54A48D489F219CA1ULL, 0xC43E5EAC6D63C821ULL, 0xA9728B3A72770DAFULL,
   0xD7934E7B20DF87EFULL, 0xE35503B61A3E86E5ULL, 0xCAE321FBC819D504ULL,
   0x129A50B3AC60BFA6ULL, 0xCD5E68EA7E9FB6C3ULL, 0xB01C90199483B1C7ULL,
   0x3DE93CD5C295376CULL, 0xAED52EDF2AB9AD13ULL, 0x2E60F512C0A07884ULL,
   0xBC3D86A3E36210C9ULL, 0x35269D9B163951CEULL, 0x0C7D6E2AD0CDB5FAULL,
   0x59E86297D87F5733ULL, 0x298EF221898DB0E7ULL, 0x55000029D1A5AA7EULL,
   0x8BC08AE1B5061B45ULL, 0xC2C31C2B6C92703AULL, 0x94CC596BAF25EF42ULL,
   0x0A1D73DB22540456ULL, 0x04B6A0F9D9C4179AULL, 0xEFFDAFA2AE3D3C60ULL,
   0xF7C8075BB49496C4ULL, 0x9CC5C7141D1CD4E3ULL, 0x78BD1638218E5534ULL,
   0xB2F11568F850246AULL, 0xEDFABCFA9502BC29ULL, 0x796CE5F2DA23051BULL,
   0xAAE128B0DC93537CULL, 0x3A493DA0EE4B29AEULL, 0xB5DF6B2C416895D7ULL,
   0xFCABBD25122D7F37ULL, 0x70810B58105DC4B1ULL, 0xE10FDD37F7882A90ULL,
   0x524DCAB5518A3F5CULL, 0x3C9E85878451255BULL, 0x4029828119BD34E2ULL,
   0x74A05B6F5D3CECCBULL, 0xB610021542E13ECAULL, 0x0FF979D12F59E2ACULL,
   0x6037DA27E4F9CC50ULL, 0x5E92975A0DF1847DULL, 0xD66DE190D3E623FEULL,
   0x5032D6B87B568048ULL, 0x9A36B7CE8235216EULL, 0x80272A7A24F64B4AULL,
   0x93EFED8B8C6916F7ULL, 0x37DDBFF44CCE1555ULL, 0x4B95DB5D4B99BD25ULL,
   0x92D3FDA169812FC0ULL, 0xFB1A4A9A90660BB6ULL, 0x730C196946A4B9B2ULL,
   0x81E289AA7F49DA68ULL, 0x64669A0F83B1A05FULL, 0x27B3FF7D9644F48BULL,
   0xCC6B615C8DB675B3ULL, 0x674F20B9BCEBBE95ULL, 0x6F31238275655982ULL,
   0x5AE488713E45CF05ULL, 0xBF619F9954C21157ULL, 0xEABAC46040A8EAE9ULL,
   0x454C6FE9F2C0C1CDULL, 0x419CF6496412691CULL, 0xD3DC3BEF265B0F70ULL,
   0x6D0E60F5C3578A9EULL };

const u64bit Tiger::SBOX4[256] = {
   0x5B0E608526323C55ULL, 0x1A46C1A9FA1B59F5ULL, 0xA9E245A17C4C8FFAULL,
   0x65CA5159DB2955D7ULL, 0x05DB0A76CE35AFC2ULL, 0x81EAC77EA9113D45ULL,
   0x528EF88AB6AC0A0DULL, 0xA09EA253597BE3FFULL, 0x430DDFB3AC48CD56ULL,
   0xC4B3A67AF45CE46FULL, 0x4ECECFD8FBE2D05EULL, 0x3EF56F10B39935F0ULL,
   0x0B22D6829CD619C6ULL, 0x17FD460A74DF2069ULL, 0x6CF8CC8E8510ED40ULL,
   0xD6C824BF3A6ECAA7ULL, 0x61243D581A817049ULL, 0x048BACB6BBC163A2ULL,
   0xD9A38AC27D44CC32ULL, 0x7FDDFF5BAAF410ABULL, 0xAD6D495AA804824BULL,
   0xE1A6A74F2D8C9F94ULL, 0xD4F7851235DEE8E3ULL, 0xFD4B7F886540D893ULL,
   0x247C20042AA4BFDAULL, 0x096EA1C517D1327CULL, 0xD56966B4361A6685ULL,
   0x277DA5C31221057DULL, 0x94D59893A43ACFF7ULL, 0x64F0C51CCDC02281ULL,
   0x3D33BCC4FF6189DBULL, 0xE005CB184CE66AF1ULL, 0xFF5CCD1D1DB99BEAULL,
   0xB0B854A7FE42980FULL, 0x7BD46A6A718D4B9FULL, 0xD10FA8CC22A5FD8CULL,
   0xD31484952BE4BD31ULL, 0xC7FA975FCB243847ULL, 0x4886ED1E5846C407ULL,
   0x28CDDB791EB70B04ULL, 0xC2B00BE2F573417FULL, 0x5C9590452180F877ULL,
   0x7A6BDDFFF370EB00ULL, 0xCE509E38D6D9D6A4ULL, 0xEBEB0F00647FA702ULL,
   0x1DCC06CF76606F06ULL, 0xE4D9F28BA286FF0AULL, 0xD85A305DC918C262ULL,
   0x475B1D8732225F54ULL, 0x2D4FB51668CCB5FEULL, 0xA679B9D9D72BBA20ULL,
   0x53841C0D912D43A5ULL, 0x3B7EAA48BF12A4E8ULL, 0x781E0E47F22F1DDFULL,
   0xEFF20CE60AB50973ULL, 0x20D261D19DFFB742ULL, 0x16A12B03062A2E39ULL,
   0x1960EB2239650495ULL, 0x251C16FED50EB8B8ULL, 0x9AC0C330F826016EULL,
   0xED152665953E7671ULL, 0x02D63194A6369570ULL, 0x5074F08394B1C987ULL,
   0x70BA598C90B25CE1ULL, 0x794A15810B9742F6ULL, 0x0D5925E9FCAF8C6CULL,
   0x3067716CD868744EULL, 0x910AB077E8D7731BULL, 0x6A61BBDB5AC42F61ULL,
   0x93513EFBF0851567ULL, 0xF494724B9E83E9D5ULL, 0xE887E1985C09648DULL,
   0x34B1D3C675370CFDULL, 0xDC35E433BC0D255DULL, 0xD0AAB84234131BE0ULL,
   0x08042A50B48B7EAFULL, 0x9997C4EE44A3AB35ULL, 0x829A7B49201799D0ULL,
   0x263B8307B7C54441ULL, 0x752F95F4FD6A6CA6ULL, 0x927217402C08C6E5ULL,
   0x2A8AB754A795D9EEULL, 0xA442F7552F72943DULL, 0x2C31334E19781208ULL,
   0x4FA98D7CEAEE6291ULL, 0x55C3862F665DB309ULL, 0xBD0610175D53B1F3ULL,
   0x46FE6CB840413F27ULL, 0x3FE03792DF0CFA59ULL, 0xCFE700372EB85E8FULL,
   0xA7BE29E7ADBCE118ULL, 0xE544EE5CDE8431DDULL, 0x8A781B1B41F1873EULL,
   0xA5C94C78A0D2F0E7ULL, 0x39412E2877B60728ULL, 0xA1265EF3AFC9A62CULL,
   0xBCC2770C6A2506C5ULL, 0x3AB66DD5DCE1CE12ULL, 0xE65499D04A675B37ULL,
   0x7D8F523481BFD216ULL, 0x0F6F64FCEC15F389ULL, 0x74EFBE618B5B13C8ULL,
   0xACDC82B714273E1DULL, 0xDD40BFE003199D17ULL, 0x37E99257E7E061F8ULL,
   0xFA52626904775AAAULL, 0x8BBBF63A463D56F9ULL, 0xF0013F1543A26E64ULL,
   0xA8307E9F879EC898ULL, 0xCC4C27A4150177CCULL, 0x1B432F2CCA1D3348ULL,
   0xDE1D1F8F9F6FA013ULL, 0x606602A047A7DDD6ULL, 0xD237AB64CC1CB2C7ULL,
   0x9B938E7225FCD1D3ULL, 0xEC4E03708E0FF476ULL, 0xFEB2FBDA3D03C12DULL,
   0xAE0BCED2EE43889AULL, 0x22CB8923EBFB4F43ULL, 0x69360D013CF7396DULL,
   0x855E3602D2D4E022ULL, 0x073805BAD01F784CULL, 0x33E17A133852F546ULL,
   0xDF4874058AC7B638ULL, 0xBA92B29C678AA14AULL, 0x0CE89FC76CFAADCDULL,
   0x5F9D4E0908339E34ULL, 0xF1AFE9291F5923B9ULL, 0x6E3480F60F4A265FULL,
   0xEEBF3A2AB29B841CULL, 0xE21938A88F91B4ADULL, 0x57DFEFF845C6D3C3ULL,
   0x2F006B0BF62CAAF2ULL, 0x62F479EF6F75EE78ULL, 0x11A55AD41C8916A9ULL,
   0xF229D29084FED453ULL, 0x42F1C27B16B000E6ULL, 0x2B1F76749823C074ULL,
   0x4B76ECA3C2745360ULL, 0x8C98F463B91691BDULL, 0x14BCC93CF1ADE66AULL,
   0x8885213E6D458397ULL, 0x8E177DF0274D4711ULL, 0xB49B73B5503F2951ULL,
   0x10168168C3F96B6BULL, 0x0E3D963B63CAB0AEULL, 0x8DFC4B5655A1DB14ULL,
   0xF789F1356E14DE5CULL, 0x683E68AF4E51DAC1ULL, 0xC9A84F9D8D4B0FD9ULL,
   0x3691E03F52A0F9D1ULL, 0x5ED86E46E1878E80ULL, 0x3C711A0E99D07150ULL,
   0x5A0865B20C4E9310ULL, 0x56FBFC1FE4F0682EULL, 0xEA8D5DE3105EDF9BULL,
   0x71ABFDB12379187AULL, 0x2EB99DE1BEE77B9CULL, 0x21ECC0EA33CF4523ULL,
   0x59A4D7521805C7A1ULL, 0x3896F5EB56AE7C72ULL, 0xAA638F3DB18F75DCULL,
   0x9F39358DABE9808EULL, 0xB7DEFA91C00B72ACULL, 0x6B5541FD62492D92ULL,
   0x6DC6DEE8F92E4D5BULL, 0x353F57ABC4BEEA7EULL, 0x735769D6DA5690CEULL,
   0x0A234AA642391484ULL, 0xF6F9508028F80D9DULL, 0xB8E319A27AB3F215ULL,
   0x31AD9C1151341A4DULL, 0x773C22A57BEF5805ULL, 0x45C7561A07968633ULL,
   0xF913DA9E249DBE36ULL, 0xDA652D9B78A64C68ULL, 0x4C27A97F3BC334EFULL,
   0x76621220E66B17F4ULL, 0x967743899ACD7D0BULL, 0xF3EE5BCAE0ED6782ULL,
   0x409F753600C879FCULL, 0x06D09A39B5926DB6ULL, 0x6F83AEB0317AC588ULL,
   0x01E6CA4A86381F21ULL, 0x66FF3462D19F3025ULL, 0x72207C24DDFD3BFBULL,
   0x4AF6B6D3E2ECE2EBULL, 0x9C994DBEC7EA08DEULL, 0x49ACE597B09A8BC4ULL,
   0xB38C4766CF0797BAULL, 0x131B9373C57C2A75ULL, 0xB1822CCE61931E58ULL,
   0x9D7555B909BA1C0CULL, 0x127FAFDD937D11D2ULL, 0x29DA3BADC66D92E4ULL,
   0xA2C1D57154C2ECBCULL, 0x58C5134D82F6FE24ULL, 0x1C3AE3515B62274FULL,
   0xE907C82E01CB8126ULL, 0xF8ED091913E37FCBULL, 0x3249D8F9C80046C9ULL,
   0x80CF9BEDE388FB63ULL, 0x1881539A116CF19EULL, 0x5103F3F76BD52457ULL,
   0x15B7E6F5AE47F7A8ULL, 0xDBD7C6DED47E9CCFULL, 0x44E55C410228BB1AULL,
   0xB647D4255EDB4E99ULL, 0x5D11882BB8AAFC30ULL, 0xF5098BBB29D3212AULL,
   0x8FB5EA14E90296B3ULL, 0x677B942157DD025AULL, 0xFB58E7C0A390ACB5ULL,
   0x89D3674C83BD4A01ULL, 0x9E2DA4DF4BF3B93BULL, 0xFCC41E328CAB4829ULL,
   0x03F38C96BA582C52ULL, 0xCAD1BDBD7FD85DB2ULL, 0xBBB442C16082AE83ULL,
   0xB95FE86BA5DA9AB0ULL, 0xB22E04673771A93FULL, 0x845358C9493152D8ULL,
   0xBE2A488697B4541EULL, 0x95A2DC2DD38E6966ULL, 0xC02C11AC923C852BULL,
   0x2388B1990DF2A87BULL, 0x7C8008FA1B4F37BEULL, 0x1F70D0C84D54E503ULL,
   0x5490ADEC7ECE57D4ULL, 0x002B3C27D9063A3AULL, 0x7EAEA3848030A2BFULL,
   0xC602326DED2003C0ULL, 0x83A7287D69A94086ULL, 0xC57A5FCB30F57A8AULL,
   0xB56844E479EBE779ULL, 0xA373B40F05DCBCE9ULL, 0xD71A786E88570EE2ULL,
   0x879CBACDBDE8F6A0ULL, 0x976AD1BCC164A32FULL, 0xAB21E25E9666D78BULL,
   0x901063AAE5E5C33CULL, 0x9818B34448698D90ULL, 0xE36487AE3E1E8ABBULL,
   0xAFBDF931893BDCB4ULL, 0x6345A0DC5FBBD519ULL, 0x8628FE269B9465CAULL,
   0x1E5D01603F9C51ECULL, 0x4DE44006A15049B7ULL, 0xBF6C70E5F776CBB1ULL,
   0x411218F2EF552BEDULL, 0xCB0C0708705A36A3ULL, 0xE74D14754F986044ULL,
   0xCD56D9430EA8280EULL, 0xC12591D7535F5065ULL, 0xC83223F1720AEF96ULL,
   0xC3A0396F7363A51FULL };

}
/*
* Tiger
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Tiger Mixing Function
*/
inline void mix(MemoryRegion<u64bit>& X)
   {
   X[0] -= X[7] ^ 0xA5A5A5A5A5A5A5A5ULL;
   X[1] ^= X[0];
   X[2] += X[1];
   X[3] -= X[2] ^ ((~X[1]) << 19);
   X[4] ^= X[3];
   X[5] += X[4];
   X[6] -= X[5] ^ ((~X[4]) >> 23);
   X[7] ^= X[6];

   X[0] += X[7];
   X[1] -= X[0] ^ ((~X[7]) << 19);
   X[2] ^= X[1];
   X[3] += X[2];
   X[4] -= X[3] ^ ((~X[2]) >> 23);
   X[5] ^= X[4];
   X[6] += X[5];
   X[7] -= X[6] ^ 0x0123456789ABCDEFULL;
   }

}

/*
* Tiger Compression Function
*/
void Tiger::compress_n(const byte input[], size_t blocks)
   {
   u64bit A = digest[0], B = digest[1], C = digest[2];

   for(size_t i = 0; i != blocks; ++i)
      {
      load_le(&X[0], input, X.size());

      pass(A, B, C, X, 5); mix(X);
      pass(C, A, B, X, 7); mix(X);
      pass(B, C, A, X, 9);

      for(size_t j = 3; j != passes; ++j)
         {
         mix(X);
         pass(A, B, C, X, 9);
         u64bit T = A; A = C; C = B; B = T;
         }

      A = (digest[0] ^= A);
      B = digest[1] = B - digest[1];
      C = (digest[2] += C);

      input += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void Tiger::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); ++i)
      output[i] = get_byte(7 - (i % 8), digest[i/8]);
   }

/*
* Tiger Pass
*/
void Tiger::pass(u64bit& A, u64bit& B, u64bit& C,
                 const MemoryRegion<u64bit>& X,
                 byte mul)
   {
   C ^= X[0];
   A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^
        SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)];
   B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^
        SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)];
   B *= mul;

   A ^= X[1];
   B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^
        SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)];
   C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^
        SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)];
   C *= mul;

   B ^= X[2];
   C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^
        SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)];
   A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^
        SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)];
   A *= mul;

   C ^= X[3];
   A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^
        SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)];
   B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^
        SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)];
   B *= mul;

   A ^= X[4];
   B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^
        SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)];
   C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^
        SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)];
   C *= mul;

   B ^= X[5];
   C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^
        SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)];
   A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^
        SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)];
   A *= mul;

   C ^= X[6];
   A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^
        SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)];
   B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^
        SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)];
   B *= mul;

   A ^= X[7];
   B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^
        SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)];
   C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^
        SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)];
   C *= mul;
   }

/*
* Clear memory of sensitive data
*/
void Tiger::clear()
   {
   MDx_HashFunction::clear();
   zeroise(X);
   digest[0] = 0x0123456789ABCDEFULL;
   digest[1] = 0xFEDCBA9876543210ULL;
   digest[2] = 0xF096A5B4C3B2E187ULL;
   }

/*
* Return the name of this type
*/
std::string Tiger::name() const
   {
   return "Tiger(" + to_string(output_length()) + "," + to_string(passes) + ")";
   }

/*
* Tiger Constructor
*/
Tiger::Tiger(size_t hash_len, size_t passes) :
   MDx_HashFunction(64, false, false),
   X(8),
   digest(3),
   hash_len(hash_len),
   passes(passes)
   {
   if(output_length() != 16 && output_length() != 20 && output_length() != 24)
      throw Invalid_Argument("Tiger: Illegal hash output size: " +
                             to_string(output_length()));

   if(passes < 3)
      throw Invalid_Argument("Tiger: Invalid number of passes: "
                             + to_string(passes));
   clear();
   }

}
/*
* Diffusion Tables for Whirlpool
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u64bit Whirlpool::C0[256] = {
0x18186018C07830D8ULL, 0x23238C2305AF4626ULL, 0xC6C63FC67EF991B8ULL, 0xE8E887E8136FCDFBULL,
0x878726874CA113CBULL, 0xB8B8DAB8A9626D11ULL, 0x0101040108050209ULL, 0x4F4F214F426E9E0DULL,
0x3636D836ADEE6C9BULL, 0xA6A6A2A6590451FFULL, 0xD2D26FD2DEBDB90CULL, 0xF5F5F3F5FB06F70EULL,
0x7979F979EF80F296ULL, 0x6F6FA16F5FCEDE30ULL, 0x91917E91FCEF3F6DULL, 0x52525552AA07A4F8ULL,
0x60609D6027FDC047ULL, 0xBCBCCABC89766535ULL, 0x9B9B569BACCD2B37ULL, 0x8E8E028E048C018AULL,
0xA3A3B6A371155BD2ULL, 0x0C0C300C603C186CULL, 0x7B7BF17BFF8AF684ULL, 0x3535D435B5E16A80ULL,
0x1D1D741DE8693AF5ULL, 0xE0E0A7E05347DDB3ULL, 0xD7D77BD7F6ACB321ULL, 0xC2C22FC25EED999CULL,
0x2E2EB82E6D965C43ULL, 0x4B4B314B627A9629ULL, 0xFEFEDFFEA321E15DULL, 0x575741578216AED5ULL,
0x15155415A8412ABDULL, 0x7777C1779FB6EEE8ULL, 0x3737DC37A5EB6E92ULL, 0xE5E5B3E57B56D79EULL,
0x9F9F469F8CD92313ULL, 0xF0F0E7F0D317FD23ULL, 0x4A4A354A6A7F9420ULL, 0xDADA4FDA9E95A944ULL,
0x58587D58FA25B0A2ULL, 0xC9C903C906CA8FCFULL, 0x2929A429558D527CULL, 0x0A0A280A5022145AULL,
0xB1B1FEB1E14F7F50ULL, 0xA0A0BAA0691A5DC9ULL, 0x6B6BB16B7FDAD614ULL, 0x85852E855CAB17D9ULL,
0xBDBDCEBD8173673CULL, 0x5D5D695DD234BA8FULL, 0x1010401080502090ULL, 0xF4F4F7F4F303F507ULL,
0xCBCB0BCB16C08BDDULL, 0x3E3EF83EEDC67CD3ULL, 0x0505140528110A2DULL, 0x676781671FE6CE78ULL,
0xE4E4B7E47353D597ULL, 0x27279C2725BB4E02ULL, 0x4141194132588273ULL, 0x8B8B168B2C9D0BA7ULL,
0xA7A7A6A7510153F6ULL, 0x7D7DE97DCF94FAB2ULL, 0x95956E95DCFB3749ULL, 0xD8D847D88E9FAD56ULL,
0xFBFBCBFB8B30EB70ULL, 0xEEEE9FEE2371C1CDULL, 0x7C7CED7CC791F8BBULL, 0x6666856617E3CC71ULL,
0xDDDD53DDA68EA77BULL, 0x17175C17B84B2EAFULL, 0x4747014702468E45ULL, 0x9E9E429E84DC211AULL,
0xCACA0FCA1EC589D4ULL, 0x2D2DB42D75995A58ULL, 0xBFBFC6BF9179632EULL, 0x07071C07381B0E3FULL,
0xADAD8EAD012347ACULL, 0x5A5A755AEA2FB4B0ULL, 0x838336836CB51BEFULL, 0x3333CC3385FF66B6ULL,
0x636391633FF2C65CULL, 0x02020802100A0412ULL, 0xAAAA92AA39384993ULL, 0x7171D971AFA8E2DEULL,
0xC8C807C80ECF8DC6ULL, 0x19196419C87D32D1ULL, 0x494939497270923BULL, 0xD9D943D9869AAF5FULL,
0xF2F2EFF2C31DF931ULL, 0xE3E3ABE34B48DBA8ULL, 0x5B5B715BE22AB6B9ULL, 0x88881A8834920DBCULL,
0x9A9A529AA4C8293EULL, 0x262698262DBE4C0BULL, 0x3232C8328DFA64BFULL, 0xB0B0FAB0E94A7D59ULL,
0xE9E983E91B6ACFF2ULL, 0x0F0F3C0F78331E77ULL, 0xD5D573D5E6A6B733ULL, 0x80803A8074BA1DF4ULL,
0xBEBEC2BE997C6127ULL, 0xCDCD13CD26DE87EBULL, 0x3434D034BDE46889ULL, 0x48483D487A759032ULL,
0xFFFFDBFFAB24E354ULL, 0x7A7AF57AF78FF48DULL, 0x90907A90F4EA3D64ULL, 0x5F5F615FC23EBE9DULL,
0x202080201DA0403DULL, 0x6868BD6867D5D00FULL, 0x1A1A681AD07234CAULL, 0xAEAE82AE192C41B7ULL,
0xB4B4EAB4C95E757DULL, 0x54544D549A19A8CEULL, 0x93937693ECE53B7FULL, 0x222288220DAA442FULL,
0x64648D6407E9C863ULL, 0xF1F1E3F1DB12FF2AULL, 0x7373D173BFA2E6CCULL, 0x12124812905A2482ULL,
0x40401D403A5D807AULL, 0x0808200840281048ULL, 0xC3C32BC356E89B95ULL, 0xECEC97EC337BC5DFULL,
0xDBDB4BDB9690AB4DULL, 0xA1A1BEA1611F5FC0ULL, 0x8D8D0E8D1C830791ULL, 0x3D3DF43DF5C97AC8ULL,
0x97976697CCF1335BULL, 0x0000000000000000ULL, 0xCFCF1BCF36D483F9ULL, 0x2B2BAC2B4587566EULL,
0x7676C57697B3ECE1ULL, 0x8282328264B019E6ULL, 0xD6D67FD6FEA9B128ULL, 0x1B1B6C1BD87736C3ULL,
0xB5B5EEB5C15B7774ULL, 0xAFAF86AF112943BEULL, 0x6A6AB56A77DFD41DULL, 0x50505D50BA0DA0EAULL,
0x45450945124C8A57ULL, 0xF3F3EBF3CB18FB38ULL, 0x3030C0309DF060ADULL, 0xEFEF9BEF2B74C3C4ULL,
0x3F3FFC3FE5C37EDAULL, 0x55554955921CAAC7ULL, 0xA2A2B2A2791059DBULL, 0xEAEA8FEA0365C9E9ULL,
0x656589650FECCA6AULL, 0xBABAD2BAB9686903ULL, 0x2F2FBC2F65935E4AULL, 0xC0C027C04EE79D8EULL,
0xDEDE5FDEBE81A160ULL, 0x1C1C701CE06C38FCULL, 0xFDFDD3FDBB2EE746ULL, 0x4D4D294D52649A1FULL,
0x92927292E4E03976ULL, 0x7575C9758FBCEAFAULL, 0x06061806301E0C36ULL, 0x8A8A128A249809AEULL,
0xB2B2F2B2F940794BULL, 0xE6E6BFE66359D185ULL, 0x0E0E380E70361C7EULL, 0x1F1F7C1FF8633EE7ULL,
0x6262956237F7C455ULL, 0xD4D477D4EEA3B53AULL, 0xA8A89AA829324D81ULL, 0x96966296C4F43152ULL,
0xF9F9C3F99B3AEF62ULL, 0xC5C533C566F697A3ULL, 0x2525942535B14A10ULL, 0x59597959F220B2ABULL,
0x84842A8454AE15D0ULL, 0x7272D572B7A7E4C5ULL, 0x3939E439D5DD72ECULL, 0x4C4C2D4C5A619816ULL,
0x5E5E655ECA3BBC94ULL, 0x7878FD78E785F09FULL, 0x3838E038DDD870E5ULL, 0x8C8C0A8C14860598ULL,
0xD1D163D1C6B2BF17ULL, 0xA5A5AEA5410B57E4ULL, 0xE2E2AFE2434DD9A1ULL, 0x616199612FF8C24EULL,
0xB3B3F6B3F1457B42ULL, 0x2121842115A54234ULL, 0x9C9C4A9C94D62508ULL, 0x1E1E781EF0663CEEULL,
0x4343114322528661ULL, 0xC7C73BC776FC93B1ULL, 0xFCFCD7FCB32BE54FULL, 0x0404100420140824ULL,
0x51515951B208A2E3ULL, 0x99995E99BCC72F25ULL, 0x6D6DA96D4FC4DA22ULL, 0x0D0D340D68391A65ULL,
0xFAFACFFA8335E979ULL, 0xDFDF5BDFB684A369ULL, 0x7E7EE57ED79BFCA9ULL, 0x242490243DB44819ULL,
0x3B3BEC3BC5D776FEULL, 0xABAB96AB313D4B9AULL, 0xCECE1FCE3ED181F0ULL, 0x1111441188552299ULL,
0x8F8F068F0C890383ULL, 0x4E4E254E4A6B9C04ULL, 0xB7B7E6B7D1517366ULL, 0xEBEB8BEB0B60CBE0ULL,
0x3C3CF03CFDCC78C1ULL, 0x81813E817CBF1FFDULL, 0x94946A94D4FE3540ULL, 0xF7F7FBF7EB0CF31CULL,
0xB9B9DEB9A1676F18ULL, 0x13134C13985F268BULL, 0x2C2CB02C7D9C5851ULL, 0xD3D36BD3D6B8BB05ULL,
0xE7E7BBE76B5CD38CULL, 0x6E6EA56E57CBDC39ULL, 0xC4C437C46EF395AAULL, 0x03030C03180F061BULL,
0x565645568A13ACDCULL, 0x44440D441A49885EULL, 0x7F7FE17FDF9EFEA0ULL, 0xA9A99EA921374F88ULL,
0x2A2AA82A4D825467ULL, 0xBBBBD6BBB16D6B0AULL, 0xC1C123C146E29F87ULL, 0x53535153A202A6F1ULL,
0xDCDC57DCAE8BA572ULL, 0x0B0B2C0B58271653ULL, 0x9D9D4E9D9CD32701ULL, 0x6C6CAD6C47C1D82BULL,
0x3131C43195F562A4ULL, 0x7474CD7487B9E8F3ULL, 0xF6F6FFF6E309F115ULL, 0x464605460A438C4CULL,
0xACAC8AAC092645A5ULL, 0x89891E893C970FB5ULL, 0x14145014A04428B4ULL, 0xE1E1A3E15B42DFBAULL,
0x16165816B04E2CA6ULL, 0x3A3AE83ACDD274F7ULL, 0x6969B9696FD0D206ULL, 0x09092409482D1241ULL,
0x7070DD70A7ADE0D7ULL, 0xB6B6E2B6D954716FULL, 0xD0D067D0CEB7BD1EULL, 0xEDED93ED3B7EC7D6ULL,
0xCCCC17CC2EDB85E2ULL, 0x424215422A578468ULL, 0x98985A98B4C22D2CULL, 0xA4A4AAA4490E55EDULL,
0x2828A0285D885075ULL, 0x5C5C6D5CDA31B886ULL, 0xF8F8C7F8933FED6BULL, 0x8686228644A411C2ULL };

const u64bit Whirlpool::C1[256] = {
0xD818186018C07830ULL, 0x2623238C2305AF46ULL, 0xB8C6C63FC67EF991ULL, 0xFBE8E887E8136FCDULL,
0xCB878726874CA113ULL, 0x11B8B8DAB8A9626DULL, 0x0901010401080502ULL, 0x0D4F4F214F426E9EULL,
0x9B3636D836ADEE6CULL, 0xFFA6A6A2A6590451ULL, 0x0CD2D26FD2DEBDB9ULL, 0x0EF5F5F3F5FB06F7ULL,
0x967979F979EF80F2ULL, 0x306F6FA16F5FCEDEULL, 0x6D91917E91FCEF3FULL, 0xF852525552AA07A4ULL,
0x4760609D6027FDC0ULL, 0x35BCBCCABC897665ULL, 0x379B9B569BACCD2BULL, 0x8A8E8E028E048C01ULL,
0xD2A3A3B6A371155BULL, 0x6C0C0C300C603C18ULL, 0x847B7BF17BFF8AF6ULL, 0x803535D435B5E16AULL,
0xF51D1D741DE8693AULL, 0xB3E0E0A7E05347DDULL, 0x21D7D77BD7F6ACB3ULL, 0x9CC2C22FC25EED99ULL,
0x432E2EB82E6D965CULL, 0x294B4B314B627A96ULL, 0x5DFEFEDFFEA321E1ULL, 0xD5575741578216AEULL,
0xBD15155415A8412AULL, 0xE87777C1779FB6EEULL, 0x923737DC37A5EB6EULL, 0x9EE5E5B3E57B56D7ULL,
0x139F9F469F8CD923ULL, 0x23F0F0E7F0D317FDULL, 0x204A4A354A6A7F94ULL, 0x44DADA4FDA9E95A9ULL,
0xA258587D58FA25B0ULL, 0xCFC9C903C906CA8FULL, 0x7C2929A429558D52ULL, 0x5A0A0A280A502214ULL,
0x50B1B1FEB1E14F7FULL, 0xC9A0A0BAA0691A5DULL, 0x146B6BB16B7FDAD6ULL, 0xD985852E855CAB17ULL,
0x3CBDBDCEBD817367ULL, 0x8F5D5D695DD234BAULL, 0x9010104010805020ULL, 0x07F4F4F7F4F303F5ULL,
0xDDCBCB0BCB16C08BULL, 0xD33E3EF83EEDC67CULL, 0x2D0505140528110AULL, 0x78676781671FE6CEULL,
0x97E4E4B7E47353D5ULL, 0x0227279C2725BB4EULL, 0x7341411941325882ULL, 0xA78B8B168B2C9D0BULL,
0xF6A7A7A6A7510153ULL, 0xB27D7DE97DCF94FAULL, 0x4995956E95DCFB37ULL, 0x56D8D847D88E9FADULL,
0x70FBFBCBFB8B30EBULL, 0xCDEEEE9FEE2371C1ULL, 0xBB7C7CED7CC791F8ULL, 0x716666856617E3CCULL,
0x7BDDDD53DDA68EA7ULL, 0xAF17175C17B84B2EULL, 0x454747014702468EULL, 0x1A9E9E429E84DC21ULL,
0xD4CACA0FCA1EC589ULL, 0x582D2DB42D75995AULL, 0x2EBFBFC6BF917963ULL, 0x3F07071C07381B0EULL,
0xACADAD8EAD012347ULL, 0xB05A5A755AEA2FB4ULL, 0xEF838336836CB51BULL, 0xB63333CC3385FF66ULL,
0x5C636391633FF2C6ULL, 0x1202020802100A04ULL, 0x93AAAA92AA393849ULL, 0xDE7171D971AFA8E2ULL,
0xC6C8C807C80ECF8DULL, 0xD119196419C87D32ULL, 0x3B49493949727092ULL, 0x5FD9D943D9869AAFULL,
0x31F2F2EFF2C31DF9ULL, 0xA8E3E3ABE34B48DBULL, 0xB95B5B715BE22AB6ULL, 0xBC88881A8834920DULL,
0x3E9A9A529AA4C829ULL, 0x0B262698262DBE4CULL, 0xBF3232C8328DFA64ULL, 0x59B0B0FAB0E94A7DULL,
0xF2E9E983E91B6ACFULL, 0x770F0F3C0F78331EULL, 0x33D5D573D5E6A6B7ULL, 0xF480803A8074BA1DULL,
0x27BEBEC2BE997C61ULL, 0xEBCDCD13CD26DE87ULL, 0x893434D034BDE468ULL, 0x3248483D487A7590ULL,
0x54FFFFDBFFAB24E3ULL, 0x8D7A7AF57AF78FF4ULL, 0x6490907A90F4EA3DULL, 0x9D5F5F615FC23EBEULL,
0x3D202080201DA040ULL, 0x0F6868BD6867D5D0ULL, 0xCA1A1A681AD07234ULL, 0xB7AEAE82AE192C41ULL,
0x7DB4B4EAB4C95E75ULL, 0xCE54544D549A19A8ULL, 0x7F93937693ECE53BULL, 0x2F222288220DAA44ULL,
0x6364648D6407E9C8ULL, 0x2AF1F1E3F1DB12FFULL, 0xCC7373D173BFA2E6ULL, 0x8212124812905A24ULL,
0x7A40401D403A5D80ULL, 0x4808082008402810ULL, 0x95C3C32BC356E89BULL, 0xDFECEC97EC337BC5ULL,
0x4DDBDB4BDB9690ABULL, 0xC0A1A1BEA1611F5FULL, 0x918D8D0E8D1C8307ULL, 0xC83D3DF43DF5C97AULL,
0x5B97976697CCF133ULL, 0x0000000000000000ULL, 0xF9CFCF1BCF36D483ULL, 0x6E2B2BAC2B458756ULL,
0xE17676C57697B3ECULL, 0xE68282328264B019ULL, 0x28D6D67FD6FEA9B1ULL, 0xC31B1B6C1BD87736ULL,
0x74B5B5EEB5C15B77ULL, 0xBEAFAF86AF112943ULL, 0x1D6A6AB56A77DFD4ULL, 0xEA50505D50BA0DA0ULL,
0x5745450945124C8AULL, 0x38F3F3EBF3CB18FBULL, 0xAD3030C0309DF060ULL, 0xC4EFEF9BEF2B74C3ULL,
0xDA3F3FFC3FE5C37EULL, 0xC755554955921CAAULL, 0xDBA2A2B2A2791059ULL, 0xE9EAEA8FEA0365C9ULL,
0x6A656589650FECCAULL, 0x03BABAD2BAB96869ULL, 0x4A2F2FBC2F65935EULL, 0x8EC0C027C04EE79DULL,
0x60DEDE5FDEBE81A1ULL, 0xFC1C1C701CE06C38ULL, 0x46FDFDD3FDBB2EE7ULL, 0x1F4D4D294D52649AULL,
0x7692927292E4E039ULL, 0xFA7575C9758FBCEAULL, 0x3606061806301E0CULL, 0xAE8A8A128A249809ULL,
0x4BB2B2F2B2F94079ULL, 0x85E6E6BFE66359D1ULL, 0x7E0E0E380E70361CULL, 0xE71F1F7C1FF8633EULL,
0x556262956237F7C4ULL, 0x3AD4D477D4EEA3B5ULL, 0x81A8A89AA829324DULL, 0x5296966296C4F431ULL,
0x62F9F9C3F99B3AEFULL, 0xA3C5C533C566F697ULL, 0x102525942535B14AULL, 0xAB59597959F220B2ULL,
0xD084842A8454AE15ULL, 0xC57272D572B7A7E4ULL, 0xEC3939E439D5DD72ULL, 0x164C4C2D4C5A6198ULL,
0x945E5E655ECA3BBCULL, 0x9F7878FD78E785F0ULL, 0xE53838E038DDD870ULL, 0x988C8C0A8C148605ULL,
0x17D1D163D1C6B2BFULL, 0xE4A5A5AEA5410B57ULL, 0xA1E2E2AFE2434DD9ULL, 0x4E616199612FF8C2ULL,
0x42B3B3F6B3F1457BULL, 0x342121842115A542ULL, 0x089C9C4A9C94D625ULL, 0xEE1E1E781EF0663CULL,
0x6143431143225286ULL, 0xB1C7C73BC776FC93ULL, 0x4FFCFCD7FCB32BE5ULL, 0x2404041004201408ULL,
0xE351515951B208A2ULL, 0x2599995E99BCC72FULL, 0x226D6DA96D4FC4DAULL, 0x650D0D340D68391AULL,
0x79FAFACFFA8335E9ULL, 0x69DFDF5BDFB684A3ULL, 0xA97E7EE57ED79BFCULL, 0x19242490243DB448ULL,
0xFE3B3BEC3BC5D776ULL, 0x9AABAB96AB313D4BULL, 0xF0CECE1FCE3ED181ULL, 0x9911114411885522ULL,
0x838F8F068F0C8903ULL, 0x044E4E254E4A6B9CULL, 0x66B7B7E6B7D15173ULL, 0xE0EBEB8BEB0B60CBULL,
0xC13C3CF03CFDCC78ULL, 0xFD81813E817CBF1FULL, 0x4094946A94D4FE35ULL, 0x1CF7F7FBF7EB0CF3ULL,
0x18B9B9DEB9A1676FULL, 0x8B13134C13985F26ULL, 0x512C2CB02C7D9C58ULL, 0x05D3D36BD3D6B8BBULL,
0x8CE7E7BBE76B5CD3ULL, 0x396E6EA56E57CBDCULL, 0xAAC4C437C46EF395ULL, 0x1B03030C03180F06ULL,
0xDC565645568A13ACULL, 0x5E44440D441A4988ULL, 0xA07F7FE17FDF9EFEULL, 0x88A9A99EA921374FULL,
0x672A2AA82A4D8254ULL, 0x0ABBBBD6BBB16D6BULL, 0x87C1C123C146E29FULL, 0xF153535153A202A6ULL,
0x72DCDC57DCAE8BA5ULL, 0x530B0B2C0B582716ULL, 0x019D9D4E9D9CD327ULL, 0x2B6C6CAD6C47C1D8ULL,
0xA43131C43195F562ULL, 0xF37474CD7487B9E8ULL, 0x15F6F6FFF6E309F1ULL, 0x4C464605460A438CULL,
0xA5ACAC8AAC092645ULL, 0xB589891E893C970FULL, 0xB414145014A04428ULL, 0xBAE1E1A3E15B42DFULL,
0xA616165816B04E2CULL, 0xF73A3AE83ACDD274ULL, 0x066969B9696FD0D2ULL, 0x4109092409482D12ULL,
0xD77070DD70A7ADE0ULL, 0x6FB6B6E2B6D95471ULL, 0x1ED0D067D0CEB7BDULL, 0xD6EDED93ED3B7EC7ULL,
0xE2CCCC17CC2EDB85ULL, 0x68424215422A5784ULL, 0x2C98985A98B4C22DULL, 0xEDA4A4AAA4490E55ULL,
0x752828A0285D8850ULL, 0x865C5C6D5CDA31B8ULL, 0x6BF8F8C7F8933FEDULL, 0xC28686228644A411ULL };

const u64bit Whirlpool::C2[256] = {
0x30D818186018C078ULL, 0x462623238C2305AFULL, 0x91B8C6C63FC67EF9ULL, 0xCDFBE8E887E8136FULL,
0x13CB878726874CA1ULL, 0x6D11B8B8DAB8A962ULL, 0x0209010104010805ULL, 0x9E0D4F4F214F426EULL,
0x6C9B3636D836ADEEULL, 0x51FFA6A6A2A65904ULL, 0xB90CD2D26FD2DEBDULL, 0xF70EF5F5F3F5FB06ULL,
0xF2967979F979EF80ULL, 0xDE306F6FA16F5FCEULL, 0x3F6D91917E91FCEFULL, 0xA4F852525552AA07ULL,
0xC04760609D6027FDULL, 0x6535BCBCCABC8976ULL, 0x2B379B9B569BACCDULL, 0x018A8E8E028E048CULL,
0x5BD2A3A3B6A37115ULL, 0x186C0C0C300C603CULL, 0xF6847B7BF17BFF8AULL, 0x6A803535D435B5E1ULL,
0x3AF51D1D741DE869ULL, 0xDDB3E0E0A7E05347ULL, 0xB321D7D77BD7F6ACULL, 0x999CC2C22FC25EEDULL,
0x5C432E2EB82E6D96ULL, 0x96294B4B314B627AULL, 0xE15DFEFEDFFEA321ULL, 0xAED5575741578216ULL,
0x2ABD15155415A841ULL, 0xEEE87777C1779FB6ULL, 0x6E923737DC37A5EBULL, 0xD79EE5E5B3E57B56ULL,
0x23139F9F469F8CD9ULL, 0xFD23F0F0E7F0D317ULL, 0x94204A4A354A6A7FULL, 0xA944DADA4FDA9E95ULL,
0xB0A258587D58FA25ULL, 0x8FCFC9C903C906CAULL, 0x527C2929A429558DULL, 0x145A0A0A280A5022ULL,
0x7F50B1B1FEB1E14FULL, 0x5DC9A0A0BAA0691AULL, 0xD6146B6BB16B7FDAULL, 0x17D985852E855CABULL,
0x673CBDBDCEBD8173ULL, 0xBA8F5D5D695DD234ULL, 0x2090101040108050ULL, 0xF507F4F4F7F4F303ULL,
0x8BDDCBCB0BCB16C0ULL, 0x7CD33E3EF83EEDC6ULL, 0x0A2D050514052811ULL, 0xCE78676781671FE6ULL,
0xD597E4E4B7E47353ULL, 0x4E0227279C2725BBULL, 0x8273414119413258ULL, 0x0BA78B8B168B2C9DULL,
0x53F6A7A7A6A75101ULL, 0xFAB27D7DE97DCF94ULL, 0x374995956E95DCFBULL, 0xAD56D8D847D88E9FULL,
0xEB70FBFBCBFB8B30ULL, 0xC1CDEEEE9FEE2371ULL, 0xF8BB7C7CED7CC791ULL, 0xCC716666856617E3ULL,
0xA77BDDDD53DDA68EULL, 0x2EAF17175C17B84BULL, 0x8E45474701470246ULL, 0x211A9E9E429E84DCULL,
0x89D4CACA0FCA1EC5ULL, 0x5A582D2DB42D7599ULL, 0x632EBFBFC6BF9179ULL, 0x0E3F07071C07381BULL,
0x47ACADAD8EAD0123ULL, 0xB4B05A5A755AEA2FULL, 0x1BEF838336836CB5ULL, 0x66B63333CC3385FFULL,
0xC65C636391633FF2ULL, 0x041202020802100AULL, 0x4993AAAA92AA3938ULL, 0xE2DE7171D971AFA8ULL,
0x8DC6C8C807C80ECFULL, 0x32D119196419C87DULL, 0x923B494939497270ULL, 0xAF5FD9D943D9869AULL,
0xF931F2F2EFF2C31DULL, 0xDBA8E3E3ABE34B48ULL, 0xB6B95B5B715BE22AULL, 0x0DBC88881A883492ULL,
0x293E9A9A529AA4C8ULL, 0x4C0B262698262DBEULL, 0x64BF3232C8328DFAULL, 0x7D59B0B0FAB0E94AULL,
0xCFF2E9E983E91B6AULL, 0x1E770F0F3C0F7833ULL, 0xB733D5D573D5E6A6ULL, 0x1DF480803A8074BAULL,
0x6127BEBEC2BE997CULL, 0x87EBCDCD13CD26DEULL, 0x68893434D034BDE4ULL, 0x903248483D487A75ULL,
0xE354FFFFDBFFAB24ULL, 0xF48D7A7AF57AF78FULL, 0x3D6490907A90F4EAULL, 0xBE9D5F5F615FC23EULL,
0x403D202080201DA0ULL, 0xD00F6868BD6867D5ULL, 0x34CA1A1A681AD072ULL, 0x41B7AEAE82AE192CULL,
0x757DB4B4EAB4C95EULL, 0xA8CE54544D549A19ULL, 0x3B7F93937693ECE5ULL, 0x442F222288220DAAULL,
0xC86364648D6407E9ULL, 0xFF2AF1F1E3F1DB12ULL, 0xE6CC7373D173BFA2ULL, 0x248212124812905AULL,
0x807A40401D403A5DULL, 0x1048080820084028ULL, 0x9B95C3C32BC356E8ULL, 0xC5DFECEC97EC337BULL,
0xAB4DDBDB4BDB9690ULL, 0x5FC0A1A1BEA1611FULL, 0x07918D8D0E8D1C83ULL, 0x7AC83D3DF43DF5C9ULL,
0x335B97976697CCF1ULL, 0x0000000000000000ULL, 0x83F9CFCF1BCF36D4ULL, 0x566E2B2BAC2B4587ULL,
0xECE17676C57697B3ULL, 0x19E68282328264B0ULL, 0xB128D6D67FD6FEA9ULL, 0x36C31B1B6C1BD877ULL,
0x7774B5B5EEB5C15BULL, 0x43BEAFAF86AF1129ULL, 0xD41D6A6AB56A77DFULL, 0xA0EA50505D50BA0DULL,
0x8A5745450945124CULL, 0xFB38F3F3EBF3CB18ULL, 0x60AD3030C0309DF0ULL, 0xC3C4EFEF9BEF2B74ULL,
0x7EDA3F3FFC3FE5C3ULL, 0xAAC755554955921CULL, 0x59DBA2A2B2A27910ULL, 0xC9E9EAEA8FEA0365ULL,
0xCA6A656589650FECULL, 0x6903BABAD2BAB968ULL, 0x5E4A2F2FBC2F6593ULL, 0x9D8EC0C027C04EE7ULL,
0xA160DEDE5FDEBE81ULL, 0x38FC1C1C701CE06CULL, 0xE746FDFDD3FDBB2EULL, 0x9A1F4D4D294D5264ULL,
0x397692927292E4E0ULL, 0xEAFA7575C9758FBCULL, 0x0C3606061806301EULL, 0x09AE8A8A128A2498ULL,
0x794BB2B2F2B2F940ULL, 0xD185E6E6BFE66359ULL, 0x1C7E0E0E380E7036ULL, 0x3EE71F1F7C1FF863ULL,
0xC4556262956237F7ULL, 0xB53AD4D477D4EEA3ULL, 0x4D81A8A89AA82932ULL, 0x315296966296C4F4ULL,
0xEF62F9F9C3F99B3AULL, 0x97A3C5C533C566F6ULL, 0x4A102525942535B1ULL, 0xB2AB59597959F220ULL,
0x15D084842A8454AEULL, 0xE4C57272D572B7A7ULL, 0x72EC3939E439D5DDULL, 0x98164C4C2D4C5A61ULL,
0xBC945E5E655ECA3BULL, 0xF09F7878FD78E785ULL, 0x70E53838E038DDD8ULL, 0x05988C8C0A8C1486ULL,
0xBF17D1D163D1C6B2ULL, 0x57E4A5A5AEA5410BULL, 0xD9A1E2E2AFE2434DULL, 0xC24E616199612FF8ULL,
0x7B42B3B3F6B3F145ULL, 0x42342121842115A5ULL, 0x25089C9C4A9C94D6ULL, 0x3CEE1E1E781EF066ULL,
0x8661434311432252ULL, 0x93B1C7C73BC776FCULL, 0xE54FFCFCD7FCB32BULL, 0x0824040410042014ULL,
0xA2E351515951B208ULL, 0x2F2599995E99BCC7ULL, 0xDA226D6DA96D4FC4ULL, 0x1A650D0D340D6839ULL,
0xE979FAFACFFA8335ULL, 0xA369DFDF5BDFB684ULL, 0xFCA97E7EE57ED79BULL, 0x4819242490243DB4ULL,
0x76FE3B3BEC3BC5D7ULL, 0x4B9AABAB96AB313DULL, 0x81F0CECE1FCE3ED1ULL, 0x2299111144118855ULL,
0x03838F8F068F0C89ULL, 0x9C044E4E254E4A6BULL, 0x7366B7B7E6B7D151ULL, 0xCBE0EBEB8BEB0B60ULL,
0x78C13C3CF03CFDCCULL, 0x1FFD81813E817CBFULL, 0x354094946A94D4FEULL, 0xF31CF7F7FBF7EB0CULL,
0x6F18B9B9DEB9A167ULL, 0x268B13134C13985FULL, 0x58512C2CB02C7D9CULL, 0xBB05D3D36BD3D6B8ULL,
0xD38CE7E7BBE76B5CULL, 0xDC396E6EA56E57CBULL, 0x95AAC4C437C46EF3ULL, 0x061B03030C03180FULL,
0xACDC565645568A13ULL, 0x885E44440D441A49ULL, 0xFEA07F7FE17FDF9EULL, 0x4F88A9A99EA92137ULL,
0x54672A2AA82A4D82ULL, 0x6B0ABBBBD6BBB16DULL, 0x9F87C1C123C146E2ULL, 0xA6F153535153A202ULL,
0xA572DCDC57DCAE8BULL, 0x16530B0B2C0B5827ULL, 0x27019D9D4E9D9CD3ULL, 0xD82B6C6CAD6C47C1ULL,
0x62A43131C43195F5ULL, 0xE8F37474CD7487B9ULL, 0xF115F6F6FFF6E309ULL, 0x8C4C464605460A43ULL,
0x45A5ACAC8AAC0926ULL, 0x0FB589891E893C97ULL, 0x28B414145014A044ULL, 0xDFBAE1E1A3E15B42ULL,
0x2CA616165816B04EULL, 0x74F73A3AE83ACDD2ULL, 0xD2066969B9696FD0ULL, 0x124109092409482DULL,
0xE0D77070DD70A7ADULL, 0x716FB6B6E2B6D954ULL, 0xBD1ED0D067D0CEB7ULL, 0xC7D6EDED93ED3B7EULL,
0x85E2CCCC17CC2EDBULL, 0x8468424215422A57ULL, 0x2D2C98985A98B4C2ULL, 0x55EDA4A4AAA4490EULL,
0x50752828A0285D88ULL, 0xB8865C5C6D5CDA31ULL, 0xED6BF8F8C7F8933FULL, 0x11C28686228644A4ULL };

const u64bit Whirlpool::C3[256] = {
0x7830D818186018C0ULL, 0xAF462623238C2305ULL, 0xF991B8C6C63FC67EULL, 0x6FCDFBE8E887E813ULL,
0xA113CB878726874CULL, 0x626D11B8B8DAB8A9ULL, 0x0502090101040108ULL, 0x6E9E0D4F4F214F42ULL,
0xEE6C9B3636D836ADULL, 0x0451FFA6A6A2A659ULL, 0xBDB90CD2D26FD2DEULL, 0x06F70EF5F5F3F5FBULL,
0x80F2967979F979EFULL, 0xCEDE306F6FA16F5FULL, 0xEF3F6D91917E91FCULL, 0x07A4F852525552AAULL,
0xFDC04760609D6027ULL, 0x766535BCBCCABC89ULL, 0xCD2B379B9B569BACULL, 0x8C018A8E8E028E04ULL,
0x155BD2A3A3B6A371ULL, 0x3C186C0C0C300C60ULL, 0x8AF6847B7BF17BFFULL, 0xE16A803535D435B5ULL,
0x693AF51D1D741DE8ULL, 0x47DDB3E0E0A7E053ULL, 0xACB321D7D77BD7F6ULL, 0xED999CC2C22FC25EULL,
0x965C432E2EB82E6DULL, 0x7A96294B4B314B62ULL, 0x21E15DFEFEDFFEA3ULL, 0x16AED55757415782ULL,
0x412ABD15155415A8ULL, 0xB6EEE87777C1779FULL, 0xEB6E923737DC37A5ULL, 0x56D79EE5E5B3E57BULL,
0xD923139F9F469F8CULL, 0x17FD23F0F0E7F0D3ULL, 0x7F94204A4A354A6AULL, 0x95A944DADA4FDA9EULL,
0x25B0A258587D58FAULL, 0xCA8FCFC9C903C906ULL, 0x8D527C2929A42955ULL, 0x22145A0A0A280A50ULL,
0x4F7F50B1B1FEB1E1ULL, 0x1A5DC9A0A0BAA069ULL, 0xDAD6146B6BB16B7FULL, 0xAB17D985852E855CULL,
0x73673CBDBDCEBD81ULL, 0x34BA8F5D5D695DD2ULL, 0x5020901010401080ULL, 0x03F507F4F4F7F4F3ULL,
0xC08BDDCBCB0BCB16ULL, 0xC67CD33E3EF83EEDULL, 0x110A2D0505140528ULL, 0xE6CE78676781671FULL,
0x53D597E4E4B7E473ULL, 0xBB4E0227279C2725ULL, 0x5882734141194132ULL, 0x9D0BA78B8B168B2CULL,
0x0153F6A7A7A6A751ULL, 0x94FAB27D7DE97DCFULL, 0xFB374995956E95DCULL, 0x9FAD56D8D847D88EULL,
0x30EB70FBFBCBFB8BULL, 0x71C1CDEEEE9FEE23ULL, 0x91F8BB7C7CED7CC7ULL, 0xE3CC716666856617ULL,
0x8EA77BDDDD53DDA6ULL, 0x4B2EAF17175C17B8ULL, 0x468E454747014702ULL, 0xDC211A9E9E429E84ULL,
0xC589D4CACA0FCA1EULL, 0x995A582D2DB42D75ULL, 0x79632EBFBFC6BF91ULL, 0x1B0E3F07071C0738ULL,
0x2347ACADAD8EAD01ULL, 0x2FB4B05A5A755AEAULL, 0xB51BEF838336836CULL, 0xFF66B63333CC3385ULL,
0xF2C65C636391633FULL, 0x0A04120202080210ULL, 0x384993AAAA92AA39ULL, 0xA8E2DE7171D971AFULL,
0xCF8DC6C8C807C80EULL, 0x7D32D119196419C8ULL, 0x70923B4949394972ULL, 0x9AAF5FD9D943D986ULL,
0x1DF931F2F2EFF2C3ULL, 0x48DBA8E3E3ABE34BULL, 0x2AB6B95B5B715BE2ULL, 0x920DBC88881A8834ULL,
0xC8293E9A9A529AA4ULL, 0xBE4C0B262698262DULL, 0xFA64BF3232C8328DULL, 0x4A7D59B0B0FAB0E9ULL,
0x6ACFF2E9E983E91BULL, 0x331E770F0F3C0F78ULL, 0xA6B733D5D573D5E6ULL, 0xBA1DF480803A8074ULL,
0x7C6127BEBEC2BE99ULL, 0xDE87EBCDCD13CD26ULL, 0xE468893434D034BDULL, 0x75903248483D487AULL,
0x24E354FFFFDBFFABULL, 0x8FF48D7A7AF57AF7ULL, 0xEA3D6490907A90F4ULL, 0x3EBE9D5F5F615FC2ULL,
0xA0403D202080201DULL, 0xD5D00F6868BD6867ULL, 0x7234CA1A1A681AD0ULL, 0x2C41B7AEAE82AE19ULL,
0x5E757DB4B4EAB4C9ULL, 0x19A8CE54544D549AULL, 0xE53B7F93937693ECULL, 0xAA442F222288220DULL,
0xE9C86364648D6407ULL, 0x12FF2AF1F1E3F1DBULL, 0xA2E6CC7373D173BFULL, 0x5A24821212481290ULL,
0x5D807A40401D403AULL, 0x2810480808200840ULL, 0xE89B95C3C32BC356ULL, 0x7BC5DFECEC97EC33ULL,
0x90AB4DDBDB4BDB96ULL, 0x1F5FC0A1A1BEA161ULL, 0x8307918D8D0E8D1CULL, 0xC97AC83D3DF43DF5ULL,
0xF1335B97976697CCULL, 0x0000000000000000ULL, 0xD483F9CFCF1BCF36ULL, 0x87566E2B2BAC2B45ULL,
0xB3ECE17676C57697ULL, 0xB019E68282328264ULL, 0xA9B128D6D67FD6FEULL, 0x7736C31B1B6C1BD8ULL,
0x5B7774B5B5EEB5C1ULL, 0x2943BEAFAF86AF11ULL, 0xDFD41D6A6AB56A77ULL, 0x0DA0EA50505D50BAULL,
0x4C8A574545094512ULL, 0x18FB38F3F3EBF3CBULL, 0xF060AD3030C0309DULL, 0x74C3C4EFEF9BEF2BULL,
0xC37EDA3F3FFC3FE5ULL, 0x1CAAC75555495592ULL, 0x1059DBA2A2B2A279ULL, 0x65C9E9EAEA8FEA03ULL,
0xECCA6A656589650FULL, 0x686903BABAD2BAB9ULL, 0x935E4A2F2FBC2F65ULL, 0xE79D8EC0C027C04EULL,
0x81A160DEDE5FDEBEULL, 0x6C38FC1C1C701CE0ULL, 0x2EE746FDFDD3FDBBULL, 0x649A1F4D4D294D52ULL,
0xE0397692927292E4ULL, 0xBCEAFA7575C9758FULL, 0x1E0C360606180630ULL, 0x9809AE8A8A128A24ULL,
0x40794BB2B2F2B2F9ULL, 0x59D185E6E6BFE663ULL, 0x361C7E0E0E380E70ULL, 0x633EE71F1F7C1FF8ULL,
0xF7C4556262956237ULL, 0xA3B53AD4D477D4EEULL, 0x324D81A8A89AA829ULL, 0xF4315296966296C4ULL,
0x3AEF62F9F9C3F99BULL, 0xF697A3C5C533C566ULL, 0xB14A102525942535ULL, 0x20B2AB59597959F2ULL,
0xAE15D084842A8454ULL, 0xA7E4C57272D572B7ULL, 0xDD72EC3939E439D5ULL, 0x6198164C4C2D4C5AULL,
0x3BBC945E5E655ECAULL, 0x85F09F7878FD78E7ULL, 0xD870E53838E038DDULL, 0x8605988C8C0A8C14ULL,
0xB2BF17D1D163D1C6ULL, 0x0B57E4A5A5AEA541ULL, 0x4DD9A1E2E2AFE243ULL, 0xF8C24E616199612FULL,
0x457B42B3B3F6B3F1ULL, 0xA542342121842115ULL, 0xD625089C9C4A9C94ULL, 0x663CEE1E1E781EF0ULL,
0x5286614343114322ULL, 0xFC93B1C7C73BC776ULL, 0x2BE54FFCFCD7FCB3ULL, 0x1408240404100420ULL,
0x08A2E351515951B2ULL, 0xC72F2599995E99BCULL, 0xC4DA226D6DA96D4FULL, 0x391A650D0D340D68ULL,
0x35E979FAFACFFA83ULL, 0x84A369DFDF5BDFB6ULL, 0x9BFCA97E7EE57ED7ULL, 0xB44819242490243DULL,
0xD776FE3B3BEC3BC5ULL, 0x3D4B9AABAB96AB31ULL, 0xD181F0CECE1FCE3EULL, 0x5522991111441188ULL,
0x8903838F8F068F0CULL, 0x6B9C044E4E254E4AULL, 0x517366B7B7E6B7D1ULL, 0x60CBE0EBEB8BEB0BULL,
0xCC78C13C3CF03CFDULL, 0xBF1FFD81813E817CULL, 0xFE354094946A94D4ULL, 0x0CF31CF7F7FBF7EBULL,
0x676F18B9B9DEB9A1ULL, 0x5F268B13134C1398ULL, 0x9C58512C2CB02C7DULL, 0xB8BB05D3D36BD3D6ULL,
0x5CD38CE7E7BBE76BULL, 0xCBDC396E6EA56E57ULL, 0xF395AAC4C437C46EULL, 0x0F061B03030C0318ULL,
0x13ACDC565645568AULL, 0x49885E44440D441AULL, 0x9EFEA07F7FE17FDFULL, 0x374F88A9A99EA921ULL,
0x8254672A2AA82A4DULL, 0x6D6B0ABBBBD6BBB1ULL, 0xE29F87C1C123C146ULL, 0x02A6F153535153A2ULL,
0x8BA572DCDC57DCAEULL, 0x2716530B0B2C0B58ULL, 0xD327019D9D4E9D9CULL, 0xC1D82B6C6CAD6C47ULL,
0xF562A43131C43195ULL, 0xB9E8F37474CD7487ULL, 0x09F115F6F6FFF6E3ULL, 0x438C4C464605460AULL,
0x2645A5ACAC8AAC09ULL, 0x970FB589891E893CULL, 0x4428B414145014A0ULL, 0x42DFBAE1E1A3E15BULL,
0x4E2CA616165816B0ULL, 0xD274F73A3AE83ACDULL, 0xD0D2066969B9696FULL, 0x2D12410909240948ULL,
0xADE0D77070DD70A7ULL, 0x54716FB6B6E2B6D9ULL, 0xB7BD1ED0D067D0CEULL, 0x7EC7D6EDED93ED3BULL,
0xDB85E2CCCC17CC2EULL, 0x578468424215422AULL, 0xC22D2C98985A98B4ULL, 0x0E55EDA4A4AAA449ULL,
0x8850752828A0285DULL, 0x31B8865C5C6D5CDAULL, 0x3FED6BF8F8C7F893ULL, 0xA411C28686228644ULL };

const u64bit Whirlpool::C4[256] = {
0xC07830D818186018ULL, 0x05AF462623238C23ULL, 0x7EF991B8C6C63FC6ULL, 0x136FCDFBE8E887E8ULL,
0x4CA113CB87872687ULL, 0xA9626D11B8B8DAB8ULL, 0x0805020901010401ULL, 0x426E9E0D4F4F214FULL,
0xADEE6C9B3636D836ULL, 0x590451FFA6A6A2A6ULL, 0xDEBDB90CD2D26FD2ULL, 0xFB06F70EF5F5F3F5ULL,
0xEF80F2967979F979ULL, 0x5FCEDE306F6FA16FULL, 0xFCEF3F6D91917E91ULL, 0xAA07A4F852525552ULL,
0x27FDC04760609D60ULL, 0x89766535BCBCCABCULL, 0xACCD2B379B9B569BULL, 0x048C018A8E8E028EULL,
0x71155BD2A3A3B6A3ULL, 0x603C186C0C0C300CULL, 0xFF8AF6847B7BF17BULL, 0xB5E16A803535D435ULL,
0xE8693AF51D1D741DULL, 0x5347DDB3E0E0A7E0ULL, 0xF6ACB321D7D77BD7ULL, 0x5EED999CC2C22FC2ULL,
0x6D965C432E2EB82EULL, 0x627A96294B4B314BULL, 0xA321E15DFEFEDFFEULL, 0x8216AED557574157ULL,
0xA8412ABD15155415ULL, 0x9FB6EEE87777C177ULL, 0xA5EB6E923737DC37ULL, 0x7B56D79EE5E5B3E5ULL,
0x8CD923139F9F469FULL, 0xD317FD23F0F0E7F0ULL, 0x6A7F94204A4A354AULL, 0x9E95A944DADA4FDAULL,
0xFA25B0A258587D58ULL, 0x06CA8FCFC9C903C9ULL, 0x558D527C2929A429ULL, 0x5022145A0A0A280AULL,
0xE14F7F50B1B1FEB1ULL, 0x691A5DC9A0A0BAA0ULL, 0x7FDAD6146B6BB16BULL, 0x5CAB17D985852E85ULL,
0x8173673CBDBDCEBDULL, 0xD234BA8F5D5D695DULL, 0x8050209010104010ULL, 0xF303F507F4F4F7F4ULL,
0x16C08BDDCBCB0BCBULL, 0xEDC67CD33E3EF83EULL, 0x28110A2D05051405ULL, 0x1FE6CE7867678167ULL,
0x7353D597E4E4B7E4ULL, 0x25BB4E0227279C27ULL, 0x3258827341411941ULL, 0x2C9D0BA78B8B168BULL,
0x510153F6A7A7A6A7ULL, 0xCF94FAB27D7DE97DULL, 0xDCFB374995956E95ULL, 0x8E9FAD56D8D847D8ULL,
0x8B30EB70FBFBCBFBULL, 0x2371C1CDEEEE9FEEULL, 0xC791F8BB7C7CED7CULL, 0x17E3CC7166668566ULL,
0xA68EA77BDDDD53DDULL, 0xB84B2EAF17175C17ULL, 0x02468E4547470147ULL, 0x84DC211A9E9E429EULL,
0x1EC589D4CACA0FCAULL, 0x75995A582D2DB42DULL, 0x9179632EBFBFC6BFULL, 0x381B0E3F07071C07ULL,
0x012347ACADAD8EADULL, 0xEA2FB4B05A5A755AULL, 0x6CB51BEF83833683ULL, 0x85FF66B63333CC33ULL,
0x3FF2C65C63639163ULL, 0x100A041202020802ULL, 0x39384993AAAA92AAULL, 0xAFA8E2DE7171D971ULL,
0x0ECF8DC6C8C807C8ULL, 0xC87D32D119196419ULL, 0x7270923B49493949ULL, 0x869AAF5FD9D943D9ULL,
0xC31DF931F2F2EFF2ULL, 0x4B48DBA8E3E3ABE3ULL, 0xE22AB6B95B5B715BULL, 0x34920DBC88881A88ULL,
0xA4C8293E9A9A529AULL, 0x2DBE4C0B26269826ULL, 0x8DFA64BF3232C832ULL, 0xE94A7D59B0B0FAB0ULL,
0x1B6ACFF2E9E983E9ULL, 0x78331E770F0F3C0FULL, 0xE6A6B733D5D573D5ULL, 0x74BA1DF480803A80ULL,
0x997C6127BEBEC2BEULL, 0x26DE87EBCDCD13CDULL, 0xBDE468893434D034ULL, 0x7A75903248483D48ULL,
0xAB24E354FFFFDBFFULL, 0xF78FF48D7A7AF57AULL, 0xF4EA3D6490907A90ULL, 0xC23EBE9D5F5F615FULL,
0x1DA0403D20208020ULL, 0x67D5D00F6868BD68ULL, 0xD07234CA1A1A681AULL, 0x192C41B7AEAE82AEULL,
0xC95E757DB4B4EAB4ULL, 0x9A19A8CE54544D54ULL, 0xECE53B7F93937693ULL, 0x0DAA442F22228822ULL,
0x07E9C86364648D64ULL, 0xDB12FF2AF1F1E3F1ULL, 0xBFA2E6CC7373D173ULL, 0x905A248212124812ULL,
0x3A5D807A40401D40ULL, 0x4028104808082008ULL, 0x56E89B95C3C32BC3ULL, 0x337BC5DFECEC97ECULL,
0x9690AB4DDBDB4BDBULL, 0x611F5FC0A1A1BEA1ULL, 0x1C8307918D8D0E8DULL, 0xF5C97AC83D3DF43DULL,
0xCCF1335B97976697ULL, 0x0000000000000000ULL, 0x36D483F9CFCF1BCFULL, 0x4587566E2B2BAC2BULL,
0x97B3ECE17676C576ULL, 0x64B019E682823282ULL, 0xFEA9B128D6D67FD6ULL, 0xD87736C31B1B6C1BULL,
0xC15B7774B5B5EEB5ULL, 0x112943BEAFAF86AFULL, 0x77DFD41D6A6AB56AULL, 0xBA0DA0EA50505D50ULL,
0x124C8A5745450945ULL, 0xCB18FB38F3F3EBF3ULL, 0x9DF060AD3030C030ULL, 0x2B74C3C4EFEF9BEFULL,
0xE5C37EDA3F3FFC3FULL, 0x921CAAC755554955ULL, 0x791059DBA2A2B2A2ULL, 0x0365C9E9EAEA8FEAULL,
0x0FECCA6A65658965ULL, 0xB9686903BABAD2BAULL, 0x65935E4A2F2FBC2FULL, 0x4EE79D8EC0C027C0ULL,
0xBE81A160DEDE5FDEULL, 0xE06C38FC1C1C701CULL, 0xBB2EE746FDFDD3FDULL, 0x52649A1F4D4D294DULL,
0xE4E0397692927292ULL, 0x8FBCEAFA7575C975ULL, 0x301E0C3606061806ULL, 0x249809AE8A8A128AULL,
0xF940794BB2B2F2B2ULL, 0x6359D185E6E6BFE6ULL, 0x70361C7E0E0E380EULL, 0xF8633EE71F1F7C1FULL,
0x37F7C45562629562ULL, 0xEEA3B53AD4D477D4ULL, 0x29324D81A8A89AA8ULL, 0xC4F4315296966296ULL,
0x9B3AEF62F9F9C3F9ULL, 0x66F697A3C5C533C5ULL, 0x35B14A1025259425ULL, 0xF220B2AB59597959ULL,
0x54AE15D084842A84ULL, 0xB7A7E4C57272D572ULL, 0xD5DD72EC3939E439ULL, 0x5A6198164C4C2D4CULL,
0xCA3BBC945E5E655EULL, 0xE785F09F7878FD78ULL, 0xDDD870E53838E038ULL, 0x148605988C8C0A8CULL,
0xC6B2BF17D1D163D1ULL, 0x410B57E4A5A5AEA5ULL, 0x434DD9A1E2E2AFE2ULL, 0x2FF8C24E61619961ULL,
0xF1457B42B3B3F6B3ULL, 0x15A5423421218421ULL, 0x94D625089C9C4A9CULL, 0xF0663CEE1E1E781EULL,
0x2252866143431143ULL, 0x76FC93B1C7C73BC7ULL, 0xB32BE54FFCFCD7FCULL, 0x2014082404041004ULL,
0xB208A2E351515951ULL, 0xBCC72F2599995E99ULL, 0x4FC4DA226D6DA96DULL, 0x68391A650D0D340DULL,
0x8335E979FAFACFFAULL, 0xB684A369DFDF5BDFULL, 0xD79BFCA97E7EE57EULL, 0x3DB4481924249024ULL,
0xC5D776FE3B3BEC3BULL, 0x313D4B9AABAB96ABULL, 0x3ED181F0CECE1FCEULL, 0x8855229911114411ULL,
0x0C8903838F8F068FULL, 0x4A6B9C044E4E254EULL, 0xD1517366B7B7E6B7ULL, 0x0B60CBE0EBEB8BEBULL,
0xFDCC78C13C3CF03CULL, 0x7CBF1FFD81813E81ULL, 0xD4FE354094946A94ULL, 0xEB0CF31CF7F7FBF7ULL,
0xA1676F18B9B9DEB9ULL, 0x985F268B13134C13ULL, 0x7D9C58512C2CB02CULL, 0xD6B8BB05D3D36BD3ULL,
0x6B5CD38CE7E7BBE7ULL, 0x57CBDC396E6EA56EULL, 0x6EF395AAC4C437C4ULL, 0x180F061B03030C03ULL,
0x8A13ACDC56564556ULL, 0x1A49885E44440D44ULL, 0xDF9EFEA07F7FE17FULL, 0x21374F88A9A99EA9ULL,
0x4D8254672A2AA82AULL, 0xB16D6B0ABBBBD6BBULL, 0x46E29F87C1C123C1ULL, 0xA202A6F153535153ULL,
0xAE8BA572DCDC57DCULL, 0x582716530B0B2C0BULL, 0x9CD327019D9D4E9DULL, 0x47C1D82B6C6CAD6CULL,
0x95F562A43131C431ULL, 0x87B9E8F37474CD74ULL, 0xE309F115F6F6FFF6ULL, 0x0A438C4C46460546ULL,
0x092645A5ACAC8AACULL, 0x3C970FB589891E89ULL, 0xA04428B414145014ULL, 0x5B42DFBAE1E1A3E1ULL,
0xB04E2CA616165816ULL, 0xCDD274F73A3AE83AULL, 0x6FD0D2066969B969ULL, 0x482D124109092409ULL,
0xA7ADE0D77070DD70ULL, 0xD954716FB6B6E2B6ULL, 0xCEB7BD1ED0D067D0ULL, 0x3B7EC7D6EDED93EDULL,
0x2EDB85E2CCCC17CCULL, 0x2A57846842421542ULL, 0xB4C22D2C98985A98ULL, 0x490E55EDA4A4AAA4ULL,
0x5D8850752828A028ULL, 0xDA31B8865C5C6D5CULL, 0x933FED6BF8F8C7F8ULL, 0x44A411C286862286ULL };

const u64bit Whirlpool::C5[256] = {
0x18C07830D8181860ULL, 0x2305AF462623238CULL, 0xC67EF991B8C6C63FULL, 0xE8136FCDFBE8E887ULL,
0x874CA113CB878726ULL, 0xB8A9626D11B8B8DAULL, 0x0108050209010104ULL, 0x4F426E9E0D4F4F21ULL,
0x36ADEE6C9B3636D8ULL, 0xA6590451FFA6A6A2ULL, 0xD2DEBDB90CD2D26FULL, 0xF5FB06F70EF5F5F3ULL,
0x79EF80F2967979F9ULL, 0x6F5FCEDE306F6FA1ULL, 0x91FCEF3F6D91917EULL, 0x52AA07A4F8525255ULL,
0x6027FDC04760609DULL, 0xBC89766535BCBCCAULL, 0x9BACCD2B379B9B56ULL, 0x8E048C018A8E8E02ULL,
0xA371155BD2A3A3B6ULL, 0x0C603C186C0C0C30ULL, 0x7BFF8AF6847B7BF1ULL, 0x35B5E16A803535D4ULL,
0x1DE8693AF51D1D74ULL, 0xE05347DDB3E0E0A7ULL, 0xD7F6ACB321D7D77BULL, 0xC25EED999CC2C22FULL,
0x2E6D965C432E2EB8ULL, 0x4B627A96294B4B31ULL, 0xFEA321E15DFEFEDFULL, 0x578216AED5575741ULL,
0x15A8412ABD151554ULL, 0x779FB6EEE87777C1ULL, 0x37A5EB6E923737DCULL, 0xE57B56D79EE5E5B3ULL,
0x9F8CD923139F9F46ULL, 0xF0D317FD23F0F0E7ULL, 0x4A6A7F94204A4A35ULL, 0xDA9E95A944DADA4FULL,
0x58FA25B0A258587DULL, 0xC906CA8FCFC9C903ULL, 0x29558D527C2929A4ULL, 0x0A5022145A0A0A28ULL,
0xB1E14F7F50B1B1FEULL, 0xA0691A5DC9A0A0BAULL, 0x6B7FDAD6146B6BB1ULL, 0x855CAB17D985852EULL,
0xBD8173673CBDBDCEULL, 0x5DD234BA8F5D5D69ULL, 0x1080502090101040ULL, 0xF4F303F507F4F4F7ULL,
0xCB16C08BDDCBCB0BULL, 0x3EEDC67CD33E3EF8ULL, 0x0528110A2D050514ULL, 0x671FE6CE78676781ULL,
0xE47353D597E4E4B7ULL, 0x2725BB4E0227279CULL, 0x4132588273414119ULL, 0x8B2C9D0BA78B8B16ULL,
0xA7510153F6A7A7A6ULL, 0x7DCF94FAB27D7DE9ULL, 0x95DCFB374995956EULL, 0xD88E9FAD56D8D847ULL,
0xFB8B30EB70FBFBCBULL, 0xEE2371C1CDEEEE9FULL, 0x7CC791F8BB7C7CEDULL, 0x6617E3CC71666685ULL,
0xDDA68EA77BDDDD53ULL, 0x17B84B2EAF17175CULL, 0x4702468E45474701ULL, 0x9E84DC211A9E9E42ULL,
0xCA1EC589D4CACA0FULL, 0x2D75995A582D2DB4ULL, 0xBF9179632EBFBFC6ULL, 0x07381B0E3F07071CULL,
0xAD012347ACADAD8EULL, 0x5AEA2FB4B05A5A75ULL, 0x836CB51BEF838336ULL, 0x3385FF66B63333CCULL,
0x633FF2C65C636391ULL, 0x02100A0412020208ULL, 0xAA39384993AAAA92ULL, 0x71AFA8E2DE7171D9ULL,
0xC80ECF8DC6C8C807ULL, 0x19C87D32D1191964ULL, 0x497270923B494939ULL, 0xD9869AAF5FD9D943ULL,
0xF2C31DF931F2F2EFULL, 0xE34B48DBA8E3E3ABULL, 0x5BE22AB6B95B5B71ULL, 0x8834920DBC88881AULL,
0x9AA4C8293E9A9A52ULL, 0x262DBE4C0B262698ULL, 0x328DFA64BF3232C8ULL, 0xB0E94A7D59B0B0FAULL,
0xE91B6ACFF2E9E983ULL, 0x0F78331E770F0F3CULL, 0xD5E6A6B733D5D573ULL, 0x8074BA1DF480803AULL,
0xBE997C6127BEBEC2ULL, 0xCD26DE87EBCDCD13ULL, 0x34BDE468893434D0ULL, 0x487A75903248483DULL,
0xFFAB24E354FFFFDBULL, 0x7AF78FF48D7A7AF5ULL, 0x90F4EA3D6490907AULL, 0x5FC23EBE9D5F5F61ULL,
0x201DA0403D202080ULL, 0x6867D5D00F6868BDULL, 0x1AD07234CA1A1A68ULL, 0xAE192C41B7AEAE82ULL,
0xB4C95E757DB4B4EAULL, 0x549A19A8CE54544DULL, 0x93ECE53B7F939376ULL, 0x220DAA442F222288ULL,
0x6407E9C86364648DULL, 0xF1DB12FF2AF1F1E3ULL, 0x73BFA2E6CC7373D1ULL, 0x12905A2482121248ULL,
0x403A5D807A40401DULL, 0x0840281048080820ULL, 0xC356E89B95C3C32BULL, 0xEC337BC5DFECEC97ULL,
0xDB9690AB4DDBDB4BULL, 0xA1611F5FC0A1A1BEULL, 0x8D1C8307918D8D0EULL, 0x3DF5C97AC83D3DF4ULL,
0x97CCF1335B979766ULL, 0x0000000000000000ULL, 0xCF36D483F9CFCF1BULL, 0x2B4587566E2B2BACULL,
0x7697B3ECE17676C5ULL, 0x8264B019E6828232ULL, 0xD6FEA9B128D6D67FULL, 0x1BD87736C31B1B6CULL,
0xB5C15B7774B5B5EEULL, 0xAF112943BEAFAF86ULL, 0x6A77DFD41D6A6AB5ULL, 0x50BA0DA0EA50505DULL,
0x45124C8A57454509ULL, 0xF3CB18FB38F3F3EBULL, 0x309DF060AD3030C0ULL, 0xEF2B74C3C4EFEF9BULL,
0x3FE5C37EDA3F3FFCULL, 0x55921CAAC7555549ULL, 0xA2791059DBA2A2B2ULL, 0xEA0365C9E9EAEA8FULL,
0x650FECCA6A656589ULL, 0xBAB9686903BABAD2ULL, 0x2F65935E4A2F2FBCULL, 0xC04EE79D8EC0C027ULL,
0xDEBE81A160DEDE5FULL, 0x1CE06C38FC1C1C70ULL, 0xFDBB2EE746FDFDD3ULL, 0x4D52649A1F4D4D29ULL,
0x92E4E03976929272ULL, 0x758FBCEAFA7575C9ULL, 0x06301E0C36060618ULL, 0x8A249809AE8A8A12ULL,
0xB2F940794BB2B2F2ULL, 0xE66359D185E6E6BFULL, 0x0E70361C7E0E0E38ULL, 0x1FF8633EE71F1F7CULL,
0x6237F7C455626295ULL, 0xD4EEA3B53AD4D477ULL, 0xA829324D81A8A89AULL, 0x96C4F43152969662ULL,
0xF99B3AEF62F9F9C3ULL, 0xC566F697A3C5C533ULL, 0x2535B14A10252594ULL, 0x59F220B2AB595979ULL,
0x8454AE15D084842AULL, 0x72B7A7E4C57272D5ULL, 0x39D5DD72EC3939E4ULL, 0x4C5A6198164C4C2DULL,
0x5ECA3BBC945E5E65ULL, 0x78E785F09F7878FDULL, 0x38DDD870E53838E0ULL, 0x8C148605988C8C0AULL,
0xD1C6B2BF17D1D163ULL, 0xA5410B57E4A5A5AEULL, 0xE2434DD9A1E2E2AFULL, 0x612FF8C24E616199ULL,
0xB3F1457B42B3B3F6ULL, 0x2115A54234212184ULL, 0x9C94D625089C9C4AULL, 0x1EF0663CEE1E1E78ULL,
0x4322528661434311ULL, 0xC776FC93B1C7C73BULL, 0xFCB32BE54FFCFCD7ULL, 0x0420140824040410ULL,
0x51B208A2E3515159ULL, 0x99BCC72F2599995EULL, 0x6D4FC4DA226D6DA9ULL, 0x0D68391A650D0D34ULL,
0xFA8335E979FAFACFULL, 0xDFB684A369DFDF5BULL, 0x7ED79BFCA97E7EE5ULL, 0x243DB44819242490ULL,
0x3BC5D776FE3B3BECULL, 0xAB313D4B9AABAB96ULL, 0xCE3ED181F0CECE1FULL, 0x1188552299111144ULL,
0x8F0C8903838F8F06ULL, 0x4E4A6B9C044E4E25ULL, 0xB7D1517366B7B7E6ULL, 0xEB0B60CBE0EBEB8BULL,
0x3CFDCC78C13C3CF0ULL, 0x817CBF1FFD81813EULL, 0x94D4FE354094946AULL, 0xF7EB0CF31CF7F7FBULL,
0xB9A1676F18B9B9DEULL, 0x13985F268B13134CULL, 0x2C7D9C58512C2CB0ULL, 0xD3D6B8BB05D3D36BULL,
0xE76B5CD38CE7E7BBULL, 0x6E57CBDC396E6EA5ULL, 0xC46EF395AAC4C437ULL, 0x03180F061B03030CULL,
0x568A13ACDC565645ULL, 0x441A49885E44440DULL, 0x7FDF9EFEA07F7FE1ULL, 0xA921374F88A9A99EULL,
0x2A4D8254672A2AA8ULL, 0xBBB16D6B0ABBBBD6ULL, 0xC146E29F87C1C123ULL, 0x53A202A6F1535351ULL,
0xDCAE8BA572DCDC57ULL, 0x0B582716530B0B2CULL, 0x9D9CD327019D9D4EULL, 0x6C47C1D82B6C6CADULL,
0x3195F562A43131C4ULL, 0x7487B9E8F37474CDULL, 0xF6E309F115F6F6FFULL, 0x460A438C4C464605ULL,
0xAC092645A5ACAC8AULL, 0x893C970FB589891EULL, 0x14A04428B4141450ULL, 0xE15B42DFBAE1E1A3ULL,
0x16B04E2CA6161658ULL, 0x3ACDD274F73A3AE8ULL, 0x696FD0D2066969B9ULL, 0x09482D1241090924ULL,
0x70A7ADE0D77070DDULL, 0xB6D954716FB6B6E2ULL, 0xD0CEB7BD1ED0D067ULL, 0xED3B7EC7D6EDED93ULL,
0xCC2EDB85E2CCCC17ULL, 0x422A578468424215ULL, 0x98B4C22D2C98985AULL, 0xA4490E55EDA4A4AAULL,
0x285D8850752828A0ULL, 0x5CDA31B8865C5C6DULL, 0xF8933FED6BF8F8C7ULL, 0x8644A411C2868622ULL };

const u64bit Whirlpool::C6[256] = {
0x6018C07830D81818ULL, 0x8C2305AF46262323ULL, 0x3FC67EF991B8C6C6ULL, 0x87E8136FCDFBE8E8ULL,
0x26874CA113CB8787ULL, 0xDAB8A9626D11B8B8ULL, 0x0401080502090101ULL, 0x214F426E9E0D4F4FULL,
0xD836ADEE6C9B3636ULL, 0xA2A6590451FFA6A6ULL, 0x6FD2DEBDB90CD2D2ULL, 0xF3F5FB06F70EF5F5ULL,
0xF979EF80F2967979ULL, 0xA16F5FCEDE306F6FULL, 0x7E91FCEF3F6D9191ULL, 0x5552AA07A4F85252ULL,
0x9D6027FDC0476060ULL, 0xCABC89766535BCBCULL, 0x569BACCD2B379B9BULL, 0x028E048C018A8E8EULL,
0xB6A371155BD2A3A3ULL, 0x300C603C186C0C0CULL, 0xF17BFF8AF6847B7BULL, 0xD435B5E16A803535ULL,
0x741DE8693AF51D1DULL, 0xA7E05347DDB3E0E0ULL, 0x7BD7F6ACB321D7D7ULL, 0x2FC25EED999CC2C2ULL,
0xB82E6D965C432E2EULL, 0x314B627A96294B4BULL, 0xDFFEA321E15DFEFEULL, 0x41578216AED55757ULL,
0x5415A8412ABD1515ULL, 0xC1779FB6EEE87777ULL, 0xDC37A5EB6E923737ULL, 0xB3E57B56D79EE5E5ULL,
0x469F8CD923139F9FULL, 0xE7F0D317FD23F0F0ULL, 0x354A6A7F94204A4AULL, 0x4FDA9E95A944DADAULL,
0x7D58FA25B0A25858ULL, 0x03C906CA8FCFC9C9ULL, 0xA429558D527C2929ULL, 0x280A5022145A0A0AULL,
0xFEB1E14F7F50B1B1ULL, 0xBAA0691A5DC9A0A0ULL, 0xB16B7FDAD6146B6BULL, 0x2E855CAB17D98585ULL,
0xCEBD8173673CBDBDULL, 0x695DD234BA8F5D5DULL, 0x4010805020901010ULL, 0xF7F4F303F507F4F4ULL,
0x0BCB16C08BDDCBCBULL, 0xF83EEDC67CD33E3EULL, 0x140528110A2D0505ULL, 0x81671FE6CE786767ULL,
0xB7E47353D597E4E4ULL, 0x9C2725BB4E022727ULL, 0x1941325882734141ULL, 0x168B2C9D0BA78B8BULL,
0xA6A7510153F6A7A7ULL, 0xE97DCF94FAB27D7DULL, 0x6E95DCFB37499595ULL, 0x47D88E9FAD56D8D8ULL,
0xCBFB8B30EB70FBFBULL, 0x9FEE2371C1CDEEEEULL, 0xED7CC791F8BB7C7CULL, 0x856617E3CC716666ULL,
0x53DDA68EA77BDDDDULL, 0x5C17B84B2EAF1717ULL, 0x014702468E454747ULL, 0x429E84DC211A9E9EULL,
0x0FCA1EC589D4CACAULL, 0xB42D75995A582D2DULL, 0xC6BF9179632EBFBFULL, 0x1C07381B0E3F0707ULL,
0x8EAD012347ACADADULL, 0x755AEA2FB4B05A5AULL, 0x36836CB51BEF8383ULL, 0xCC3385FF66B63333ULL,
0x91633FF2C65C6363ULL, 0x0802100A04120202ULL, 0x92AA39384993AAAAULL, 0xD971AFA8E2DE7171ULL,
0x07C80ECF8DC6C8C8ULL, 0x6419C87D32D11919ULL, 0x39497270923B4949ULL, 0x43D9869AAF5FD9D9ULL,
0xEFF2C31DF931F2F2ULL, 0xABE34B48DBA8E3E3ULL, 0x715BE22AB6B95B5BULL, 0x1A8834920DBC8888ULL,
0x529AA4C8293E9A9AULL, 0x98262DBE4C0B2626ULL, 0xC8328DFA64BF3232ULL, 0xFAB0E94A7D59B0B0ULL,
0x83E91B6ACFF2E9E9ULL, 0x3C0F78331E770F0FULL, 0x73D5E6A6B733D5D5ULL, 0x3A8074BA1DF48080ULL,
0xC2BE997C6127BEBEULL, 0x13CD26DE87EBCDCDULL, 0xD034BDE468893434ULL, 0x3D487A7590324848ULL,
0xDBFFAB24E354FFFFULL, 0xF57AF78FF48D7A7AULL, 0x7A90F4EA3D649090ULL, 0x615FC23EBE9D5F5FULL,
0x80201DA0403D2020ULL, 0xBD6867D5D00F6868ULL, 0x681AD07234CA1A1AULL, 0x82AE192C41B7AEAEULL,
0xEAB4C95E757DB4B4ULL, 0x4D549A19A8CE5454ULL, 0x7693ECE53B7F9393ULL, 0x88220DAA442F2222ULL,
0x8D6407E9C8636464ULL, 0xE3F1DB12FF2AF1F1ULL, 0xD173BFA2E6CC7373ULL, 0x4812905A24821212ULL,
0x1D403A5D807A4040ULL, 0x2008402810480808ULL, 0x2BC356E89B95C3C3ULL, 0x97EC337BC5DFECECULL,
0x4BDB9690AB4DDBDBULL, 0xBEA1611F5FC0A1A1ULL, 0x0E8D1C8307918D8DULL, 0xF43DF5C97AC83D3DULL,
0x6697CCF1335B9797ULL, 0x0000000000000000ULL, 0x1BCF36D483F9CFCFULL, 0xAC2B4587566E2B2BULL,
0xC57697B3ECE17676ULL, 0x328264B019E68282ULL, 0x7FD6FEA9B128D6D6ULL, 0x6C1BD87736C31B1BULL,
0xEEB5C15B7774B5B5ULL, 0x86AF112943BEAFAFULL, 0xB56A77DFD41D6A6AULL, 0x5D50BA0DA0EA5050ULL,
0x0945124C8A574545ULL, 0xEBF3CB18FB38F3F3ULL, 0xC0309DF060AD3030ULL, 0x9BEF2B74C3C4EFEFULL,
0xFC3FE5C37EDA3F3FULL, 0x4955921CAAC75555ULL, 0xB2A2791059DBA2A2ULL, 0x8FEA0365C9E9EAEAULL,
0x89650FECCA6A6565ULL, 0xD2BAB9686903BABAULL, 0xBC2F65935E4A2F2FULL, 0x27C04EE79D8EC0C0ULL,
0x5FDEBE81A160DEDEULL, 0x701CE06C38FC1C1CULL, 0xD3FDBB2EE746FDFDULL, 0x294D52649A1F4D4DULL,
0x7292E4E039769292ULL, 0xC9758FBCEAFA7575ULL, 0x1806301E0C360606ULL, 0x128A249809AE8A8AULL,
0xF2B2F940794BB2B2ULL, 0xBFE66359D185E6E6ULL, 0x380E70361C7E0E0EULL, 0x7C1FF8633EE71F1FULL,
0x956237F7C4556262ULL, 0x77D4EEA3B53AD4D4ULL, 0x9AA829324D81A8A8ULL, 0x6296C4F431529696ULL,
0xC3F99B3AEF62F9F9ULL, 0x33C566F697A3C5C5ULL, 0x942535B14A102525ULL, 0x7959F220B2AB5959ULL,
0x2A8454AE15D08484ULL, 0xD572B7A7E4C57272ULL, 0xE439D5DD72EC3939ULL, 0x2D4C5A6198164C4CULL,
0x655ECA3BBC945E5EULL, 0xFD78E785F09F7878ULL, 0xE038DDD870E53838ULL, 0x0A8C148605988C8CULL,
0x63D1C6B2BF17D1D1ULL, 0xAEA5410B57E4A5A5ULL, 0xAFE2434DD9A1E2E2ULL, 0x99612FF8C24E6161ULL,
0xF6B3F1457B42B3B3ULL, 0x842115A542342121ULL, 0x4A9C94D625089C9CULL, 0x781EF0663CEE1E1EULL,
0x1143225286614343ULL, 0x3BC776FC93B1C7C7ULL, 0xD7FCB32BE54FFCFCULL, 0x1004201408240404ULL,
0x5951B208A2E35151ULL, 0x5E99BCC72F259999ULL, 0xA96D4FC4DA226D6DULL, 0x340D68391A650D0DULL,
0xCFFA8335E979FAFAULL, 0x5BDFB684A369DFDFULL, 0xE57ED79BFCA97E7EULL, 0x90243DB448192424ULL,
0xEC3BC5D776FE3B3BULL, 0x96AB313D4B9AABABULL, 0x1FCE3ED181F0CECEULL, 0x4411885522991111ULL,
0x068F0C8903838F8FULL, 0x254E4A6B9C044E4EULL, 0xE6B7D1517366B7B7ULL, 0x8BEB0B60CBE0EBEBULL,
0xF03CFDCC78C13C3CULL, 0x3E817CBF1FFD8181ULL, 0x6A94D4FE35409494ULL, 0xFBF7EB0CF31CF7F7ULL,
0xDEB9A1676F18B9B9ULL, 0x4C13985F268B1313ULL, 0xB02C7D9C58512C2CULL, 0x6BD3D6B8BB05D3D3ULL,
0xBBE76B5CD38CE7E7ULL, 0xA56E57CBDC396E6EULL, 0x37C46EF395AAC4C4ULL, 0x0C03180F061B0303ULL,
0x45568A13ACDC5656ULL, 0x0D441A49885E4444ULL, 0xE17FDF9EFEA07F7FULL, 0x9EA921374F88A9A9ULL,
0xA82A4D8254672A2AULL, 0xD6BBB16D6B0ABBBBULL, 0x23C146E29F87C1C1ULL, 0x5153A202A6F15353ULL,
0x57DCAE8BA572DCDCULL, 0x2C0B582716530B0BULL, 0x4E9D9CD327019D9DULL, 0xAD6C47C1D82B6C6CULL,
0xC43195F562A43131ULL, 0xCD7487B9E8F37474ULL, 0xFFF6E309F115F6F6ULL, 0x05460A438C4C4646ULL,
0x8AAC092645A5ACACULL, 0x1E893C970FB58989ULL, 0x5014A04428B41414ULL, 0xA3E15B42DFBAE1E1ULL,
0x5816B04E2CA61616ULL, 0xE83ACDD274F73A3AULL, 0xB9696FD0D2066969ULL, 0x2409482D12410909ULL,
0xDD70A7ADE0D77070ULL, 0xE2B6D954716FB6B6ULL, 0x67D0CEB7BD1ED0D0ULL, 0x93ED3B7EC7D6EDEDULL,
0x17CC2EDB85E2CCCCULL, 0x15422A5784684242ULL, 0x5A98B4C22D2C9898ULL, 0xAAA4490E55EDA4A4ULL,
0xA0285D8850752828ULL, 0x6D5CDA31B8865C5CULL, 0xC7F8933FED6BF8F8ULL, 0x228644A411C28686ULL };

const u64bit Whirlpool::C7[256] = {
0x186018C07830D818ULL, 0x238C2305AF462623ULL, 0xC63FC67EF991B8C6ULL, 0xE887E8136FCDFBE8ULL,
0x8726874CA113CB87ULL, 0xB8DAB8A9626D11B8ULL, 0x0104010805020901ULL, 0x4F214F426E9E0D4FULL,
0x36D836ADEE6C9B36ULL, 0xA6A2A6590451FFA6ULL, 0xD26FD2DEBDB90CD2ULL, 0xF5F3F5FB06F70EF5ULL,
0x79F979EF80F29679ULL, 0x6FA16F5FCEDE306FULL, 0x917E91FCEF3F6D91ULL, 0x525552AA07A4F852ULL,
0x609D6027FDC04760ULL, 0xBCCABC89766535BCULL, 0x9B569BACCD2B379BULL, 0x8E028E048C018A8EULL,
0xA3B6A371155BD2A3ULL, 0x0C300C603C186C0CULL, 0x7BF17BFF8AF6847BULL, 0x35D435B5E16A8035ULL,
0x1D741DE8693AF51DULL, 0xE0A7E05347DDB3E0ULL, 0xD77BD7F6ACB321D7ULL, 0xC22FC25EED999CC2ULL,
0x2EB82E6D965C432EULL, 0x4B314B627A96294BULL, 0xFEDFFEA321E15DFEULL, 0x5741578216AED557ULL,
0x155415A8412ABD15ULL, 0x77C1779FB6EEE877ULL, 0x37DC37A5EB6E9237ULL, 0xE5B3E57B56D79EE5ULL,
0x9F469F8CD923139FULL, 0xF0E7F0D317FD23F0ULL, 0x4A354A6A7F94204AULL, 0xDA4FDA9E95A944DAULL,
0x587D58FA25B0A258ULL, 0xC903C906CA8FCFC9ULL, 0x29A429558D527C29ULL, 0x0A280A5022145A0AULL,
0xB1FEB1E14F7F50B1ULL, 0xA0BAA0691A5DC9A0ULL, 0x6BB16B7FDAD6146BULL, 0x852E855CAB17D985ULL,
0xBDCEBD8173673CBDULL, 0x5D695DD234BA8F5DULL, 0x1040108050209010ULL, 0xF4F7F4F303F507F4ULL,
0xCB0BCB16C08BDDCBULL, 0x3EF83EEDC67CD33EULL, 0x05140528110A2D05ULL, 0x6781671FE6CE7867ULL,
0xE4B7E47353D597E4ULL, 0x279C2725BB4E0227ULL, 0x4119413258827341ULL, 0x8B168B2C9D0BA78BULL,
0xA7A6A7510153F6A7ULL, 0x7DE97DCF94FAB27DULL, 0x956E95DCFB374995ULL, 0xD847D88E9FAD56D8ULL,
0xFBCBFB8B30EB70FBULL, 0xEE9FEE2371C1CDEEULL, 0x7CED7CC791F8BB7CULL, 0x66856617E3CC7166ULL,
0xDD53DDA68EA77BDDULL, 0x175C17B84B2EAF17ULL, 0x47014702468E4547ULL, 0x9E429E84DC211A9EULL,
0xCA0FCA1EC589D4CAULL, 0x2DB42D75995A582DULL, 0xBFC6BF9179632EBFULL, 0x071C07381B0E3F07ULL,
0xAD8EAD012347ACADULL, 0x5A755AEA2FB4B05AULL, 0x8336836CB51BEF83ULL, 0x33CC3385FF66B633ULL,
0x6391633FF2C65C63ULL, 0x020802100A041202ULL, 0xAA92AA39384993AAULL, 0x71D971AFA8E2DE71ULL,
0xC807C80ECF8DC6C8ULL, 0x196419C87D32D119ULL, 0x4939497270923B49ULL, 0xD943D9869AAF5FD9ULL,
0xF2EFF2C31DF931F2ULL, 0xE3ABE34B48DBA8E3ULL, 0x5B715BE22AB6B95BULL, 0x881A8834920DBC88ULL,
0x9A529AA4C8293E9AULL, 0x2698262DBE4C0B26ULL, 0x32C8328DFA64BF32ULL, 0xB0FAB0E94A7D59B0ULL,
0xE983E91B6ACFF2E9ULL, 0x0F3C0F78331E770FULL, 0xD573D5E6A6B733D5ULL, 0x803A8074BA1DF480ULL,
0xBEC2BE997C6127BEULL, 0xCD13CD26DE87EBCDULL, 0x34D034BDE4688934ULL, 0x483D487A75903248ULL,
0xFFDBFFAB24E354FFULL, 0x7AF57AF78FF48D7AULL, 0x907A90F4EA3D6490ULL, 0x5F615FC23EBE9D5FULL,
0x2080201DA0403D20ULL, 0x68BD6867D5D00F68ULL, 0x1A681AD07234CA1AULL, 0xAE82AE192C41B7AEULL,
0xB4EAB4C95E757DB4ULL, 0x544D549A19A8CE54ULL, 0x937693ECE53B7F93ULL, 0x2288220DAA442F22ULL,
0x648D6407E9C86364ULL, 0xF1E3F1DB12FF2AF1ULL, 0x73D173BFA2E6CC73ULL, 0x124812905A248212ULL,
0x401D403A5D807A40ULL, 0x0820084028104808ULL, 0xC32BC356E89B95C3ULL, 0xEC97EC337BC5DFECULL,
0xDB4BDB9690AB4DDBULL, 0xA1BEA1611F5FC0A1ULL, 0x8D0E8D1C8307918DULL, 0x3DF43DF5C97AC83DULL,
0x976697CCF1335B97ULL, 0x0000000000000000ULL, 0xCF1BCF36D483F9CFULL, 0x2BAC2B4587566E2BULL,
0x76C57697B3ECE176ULL, 0x82328264B019E682ULL, 0xD67FD6FEA9B128D6ULL, 0x1B6C1BD87736C31BULL,
0xB5EEB5C15B7774B5ULL, 0xAF86AF112943BEAFULL, 0x6AB56A77DFD41D6AULL, 0x505D50BA0DA0EA50ULL,
0x450945124C8A5745ULL, 0xF3EBF3CB18FB38F3ULL, 0x30C0309DF060AD30ULL, 0xEF9BEF2B74C3C4EFULL,
0x3FFC3FE5C37EDA3FULL, 0x554955921CAAC755ULL, 0xA2B2A2791059DBA2ULL, 0xEA8FEA0365C9E9EAULL,
0x6589650FECCA6A65ULL, 0xBAD2BAB9686903BAULL, 0x2FBC2F65935E4A2FULL, 0xC027C04EE79D8EC0ULL,
0xDE5FDEBE81A160DEULL, 0x1C701CE06C38FC1CULL, 0xFDD3FDBB2EE746FDULL, 0x4D294D52649A1F4DULL,
0x927292E4E0397692ULL, 0x75C9758FBCEAFA75ULL, 0x061806301E0C3606ULL, 0x8A128A249809AE8AULL,
0xB2F2B2F940794BB2ULL, 0xE6BFE66359D185E6ULL, 0x0E380E70361C7E0EULL, 0x1F7C1FF8633EE71FULL,
0x62956237F7C45562ULL, 0xD477D4EEA3B53AD4ULL, 0xA89AA829324D81A8ULL, 0x966296C4F4315296ULL,
0xF9C3F99B3AEF62F9ULL, 0xC533C566F697A3C5ULL, 0x25942535B14A1025ULL, 0x597959F220B2AB59ULL,
0x842A8454AE15D084ULL, 0x72D572B7A7E4C572ULL, 0x39E439D5DD72EC39ULL, 0x4C2D4C5A6198164CULL,
0x5E655ECA3BBC945EULL, 0x78FD78E785F09F78ULL, 0x38E038DDD870E538ULL, 0x8C0A8C148605988CULL,
0xD163D1C6B2BF17D1ULL, 0xA5AEA5410B57E4A5ULL, 0xE2AFE2434DD9A1E2ULL, 0x6199612FF8C24E61ULL,
0xB3F6B3F1457B42B3ULL, 0x21842115A5423421ULL, 0x9C4A9C94D625089CULL, 0x1E781EF0663CEE1EULL,
0x4311432252866143ULL, 0xC73BC776FC93B1C7ULL, 0xFCD7FCB32BE54FFCULL, 0x0410042014082404ULL,
0x515951B208A2E351ULL, 0x995E99BCC72F2599ULL, 0x6DA96D4FC4DA226DULL, 0x0D340D68391A650DULL,
0xFACFFA8335E979FAULL, 0xDF5BDFB684A369DFULL, 0x7EE57ED79BFCA97EULL, 0x2490243DB4481924ULL,
0x3BEC3BC5D776FE3BULL, 0xAB96AB313D4B9AABULL, 0xCE1FCE3ED181F0CEULL, 0x1144118855229911ULL,
0x8F068F0C8903838FULL, 0x4E254E4A6B9C044EULL, 0xB7E6B7D1517366B7ULL, 0xEB8BEB0B60CBE0EBULL,
0x3CF03CFDCC78C13CULL, 0x813E817CBF1FFD81ULL, 0x946A94D4FE354094ULL, 0xF7FBF7EB0CF31CF7ULL,
0xB9DEB9A1676F18B9ULL, 0x134C13985F268B13ULL, 0x2CB02C7D9C58512CULL, 0xD36BD3D6B8BB05D3ULL,
0xE7BBE76B5CD38CE7ULL, 0x6EA56E57CBDC396EULL, 0xC437C46EF395AAC4ULL, 0x030C03180F061B03ULL,
0x5645568A13ACDC56ULL, 0x440D441A49885E44ULL, 0x7FE17FDF9EFEA07FULL, 0xA99EA921374F88A9ULL,
0x2AA82A4D8254672AULL, 0xBBD6BBB16D6B0ABBULL, 0xC123C146E29F87C1ULL, 0x535153A202A6F153ULL,
0xDC57DCAE8BA572DCULL, 0x0B2C0B582716530BULL, 0x9D4E9D9CD327019DULL, 0x6CAD6C47C1D82B6CULL,
0x31C43195F562A431ULL, 0x74CD7487B9E8F374ULL, 0xF6FFF6E309F115F6ULL, 0x4605460A438C4C46ULL,
0xAC8AAC092645A5ACULL, 0x891E893C970FB589ULL, 0x145014A04428B414ULL, 0xE1A3E15B42DFBAE1ULL,
0x165816B04E2CA616ULL, 0x3AE83ACDD274F73AULL, 0x69B9696FD0D20669ULL, 0x092409482D124109ULL,
0x70DD70A7ADE0D770ULL, 0xB6E2B6D954716FB6ULL, 0xD067D0CEB7BD1ED0ULL, 0xED93ED3B7EC7D6EDULL,
0xCC17CC2EDB85E2CCULL, 0x4215422A57846842ULL, 0x985A98B4C22D2C98ULL, 0xA4AAA4490E55EDA4ULL,
0x28A0285D88507528ULL, 0x5C6D5CDA31B8865CULL, 0xF8C7F8933FED6BF8ULL, 0x86228644A411C286ULL };

}
/*
* Whirlpool
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Whirlpool Compression Function
*/
void Whirlpool::compress_n(const byte in[], size_t blocks)
   {
   static const u64bit RC[10] = {
      0x1823C6E887B8014FULL, 0x36A6D2F5796F9152ULL,
      0x60BC9B8EA30C7B35ULL, 0x1DE0D7C22E4BFE57ULL,
      0x157737E59FF04ADAULL, 0x58C9290AB1A06B85ULL,
      0xBD5D10F4CB3E0567ULL, 0xE427418BA77D95D8ULL,
      0xFBEE7C66DD17479EULL, 0xCA2DBF07AD5A8333ULL
   };

   for(size_t i = 0; i != blocks; ++i)
      {
      load_be(&M[0], in, M.size());

      u64bit K0, K1, K2, K3, K4, K5, K6, K7;
      K0 = digest[0]; K1 = digest[1]; K2 = digest[2]; K3 = digest[3];
      K4 = digest[4]; K5 = digest[5]; K6 = digest[6]; K7 = digest[7];

      u64bit B0, B1, B2, B3, B4, B5, B6, B7;
      B0 = K0 ^ M[0]; B1 = K1 ^ M[1]; B2 = K2 ^ M[2]; B3 = K3 ^ M[3];
      B4 = K4 ^ M[4]; B5 = K5 ^ M[5]; B6 = K6 ^ M[6]; B7 = K7 ^ M[7];

      for(size_t j = 0; j != 10; ++j)
         {
         u64bit T0, T1, T2, T3, T4, T5, T6, T7;
         T0 = C0[get_byte(0, K0)] ^ C1[get_byte(1, K7)] ^
              C2[get_byte(2, K6)] ^ C3[get_byte(3, K5)] ^
              C4[get_byte(4, K4)] ^ C5[get_byte(5, K3)] ^
              C6[get_byte(6, K2)] ^ C7[get_byte(7, K1)] ^ RC[j];
         T1 = C0[get_byte(0, K1)] ^ C1[get_byte(1, K0)] ^
              C2[get_byte(2, K7)] ^ C3[get_byte(3, K6)] ^
              C4[get_byte(4, K5)] ^ C5[get_byte(5, K4)] ^
              C6[get_byte(6, K3)] ^ C7[get_byte(7, K2)];
         T2 = C0[get_byte(0, K2)] ^ C1[get_byte(1, K1)] ^
              C2[get_byte(2, K0)] ^ C3[get_byte(3, K7)] ^
              C4[get_byte(4, K6)] ^ C5[get_byte(5, K5)] ^
              C6[get_byte(6, K4)] ^ C7[get_byte(7, K3)];
         T3 = C0[get_byte(0, K3)] ^ C1[get_byte(1, K2)] ^
              C2[get_byte(2, K1)] ^ C3[get_byte(3, K0)] ^
              C4[get_byte(4, K7)] ^ C5[get_byte(5, K6)] ^
              C6[get_byte(6, K5)] ^ C7[get_byte(7, K4)];
         T4 = C0[get_byte(0, K4)] ^ C1[get_byte(1, K3)] ^
              C2[get_byte(2, K2)] ^ C3[get_byte(3, K1)] ^
              C4[get_byte(4, K0)] ^ C5[get_byte(5, K7)] ^
              C6[get_byte(6, K6)] ^ C7[get_byte(7, K5)];
         T5 = C0[get_byte(0, K5)] ^ C1[get_byte(1, K4)] ^
              C2[get_byte(2, K3)] ^ C3[get_byte(3, K2)] ^
              C4[get_byte(4, K1)] ^ C5[get_byte(5, K0)] ^
              C6[get_byte(6, K7)] ^ C7[get_byte(7, K6)];
         T6 = C0[get_byte(0, K6)] ^ C1[get_byte(1, K5)] ^
              C2[get_byte(2, K4)] ^ C3[get_byte(3, K3)] ^
              C4[get_byte(4, K2)] ^ C5[get_byte(5, K1)] ^
              C6[get_byte(6, K0)] ^ C7[get_byte(7, K7)];
         T7 = C0[get_byte(0, K7)] ^ C1[get_byte(1, K6)] ^
              C2[get_byte(2, K5)] ^ C3[get_byte(3, K4)] ^
              C4[get_byte(4, K3)] ^ C5[get_byte(5, K2)] ^
              C6[get_byte(6, K1)] ^ C7[get_byte(7, K0)];

         K0 = T0; K1 = T1; K2 = T2; K3 = T3;
         K4 = T4; K5 = T5; K6 = T6; K7 = T7;

         T0 = C0[get_byte(0, B0)] ^ C1[get_byte(1, B7)] ^
              C2[get_byte(2, B6)] ^ C3[get_byte(3, B5)] ^
              C4[get_byte(4, B4)] ^ C5[get_byte(5, B3)] ^
              C6[get_byte(6, B2)] ^ C7[get_byte(7, B1)] ^ K0;
         T1 = C0[get_byte(0, B1)] ^ C1[get_byte(1, B0)] ^
              C2[get_byte(2, B7)] ^ C3[get_byte(3, B6)] ^
              C4[get_byte(4, B5)] ^ C5[get_byte(5, B4)] ^
              C6[get_byte(6, B3)] ^ C7[get_byte(7, B2)] ^ K1;
         T2 = C0[get_byte(0, B2)] ^ C1[get_byte(1, B1)] ^
              C2[get_byte(2, B0)] ^ C3[get_byte(3, B7)] ^
              C4[get_byte(4, B6)] ^ C5[get_byte(5, B5)] ^
              C6[get_byte(6, B4)] ^ C7[get_byte(7, B3)] ^ K2;
         T3 = C0[get_byte(0, B3)] ^ C1[get_byte(1, B2)] ^
              C2[get_byte(2, B1)] ^ C3[get_byte(3, B0)] ^
              C4[get_byte(4, B7)] ^ C5[get_byte(5, B6)] ^
              C6[get_byte(6, B5)] ^ C7[get_byte(7, B4)] ^ K3;
         T4 = C0[get_byte(0, B4)] ^ C1[get_byte(1, B3)] ^
              C2[get_byte(2, B2)] ^ C3[get_byte(3, B1)] ^
              C4[get_byte(4, B0)] ^ C5[get_byte(5, B7)] ^
              C6[get_byte(6, B6)] ^ C7[get_byte(7, B5)] ^ K4;
         T5 = C0[get_byte(0, B5)] ^ C1[get_byte(1, B4)] ^
              C2[get_byte(2, B3)] ^ C3[get_byte(3, B2)] ^
              C4[get_byte(4, B1)] ^ C5[get_byte(5, B0)] ^
              C6[get_byte(6, B7)] ^ C7[get_byte(7, B6)] ^ K5;
         T6 = C0[get_byte(0, B6)] ^ C1[get_byte(1, B5)] ^
              C2[get_byte(2, B4)] ^ C3[get_byte(3, B3)] ^
              C4[get_byte(4, B2)] ^ C5[get_byte(5, B1)] ^
              C6[get_byte(6, B0)] ^ C7[get_byte(7, B7)] ^ K6;
         T7 = C0[get_byte(0, B7)] ^ C1[get_byte(1, B6)] ^
              C2[get_byte(2, B5)] ^ C3[get_byte(3, B4)] ^
              C4[get_byte(4, B3)] ^ C5[get_byte(5, B2)] ^
              C6[get_byte(6, B1)] ^ C7[get_byte(7, B0)] ^ K7;

         B0 = T0; B1 = T1; B2 = T2; B3 = T3;
         B4 = T4; B5 = T5; B6 = T6; B7 = T7;
         }

      digest[0] ^= B0 ^ M[0];
      digest[1] ^= B1 ^ M[1];
      digest[2] ^= B2 ^ M[2];
      digest[3] ^= B3 ^ M[3];
      digest[4] ^= B4 ^ M[4];
      digest[5] ^= B5 ^ M[5];
      digest[6] ^= B6 ^ M[6];
      digest[7] ^= B7 ^ M[7];

      in += hash_block_size();
      }
   }

/*
* Copy out the digest
*/
void Whirlpool::copy_out(byte output[])
   {
   for(size_t i = 0; i != output_length(); i += 8)
      store_be(digest[i/8], output + i);
   }

/*
* Clear memory of sensitive data
*/
void Whirlpool::clear()
   {
   MDx_HashFunction::clear();
   zeroise(M);
   zeroise(digest);
   }

}
/*
* KDF Base Class
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Derive a key
*/
SecureVector<byte> KDF::derive_key(size_t key_len,
                                   const MemoryRegion<byte>& secret,
                                   const std::string& salt) const
   {
   return derive_key(key_len, &secret[0], secret.size(),
                     reinterpret_cast<const byte*>(salt.data()),
                     salt.length());
   }

/*
* Derive a key
*/
SecureVector<byte> KDF::derive_key(size_t key_len,
                                   const MemoryRegion<byte>& secret,
                                   const byte salt[], size_t salt_len) const
   {
   return derive_key(key_len, &secret[0], secret.size(),
                     salt, salt_len);
   }

/*
* Derive a key
*/
SecureVector<byte> KDF::derive_key(size_t key_len,
                                   const MemoryRegion<byte>& secret,
                                   const MemoryRegion<byte>& salt) const
   {
   return derive_key(key_len, &secret[0], secret.size(),
                     &salt[0], salt.size());
   }

/*
* Derive a key
*/
SecureVector<byte> KDF::derive_key(size_t key_len,
                                   const byte secret[], size_t secret_len,
                                   const std::string& salt) const
   {
   return derive_key(key_len, secret, secret_len,
                     reinterpret_cast<const byte*>(salt.data()),
                     salt.length());
   }

/*
* Derive a key
*/
SecureVector<byte> KDF::derive_key(size_t key_len,
                                   const byte secret[], size_t secret_len,
                                   const byte salt[], size_t salt_len) const
   {
   return derive(key_len, secret, secret_len, salt, salt_len);
   }

}
/*
* KDF1
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* KDF1 Key Derivation Mechanism
*/
SecureVector<byte> KDF1::derive(size_t,
                                const byte secret[], size_t secret_len,
                                const byte P[], size_t P_len) const
   {
   hash->update(secret, secret_len);
   hash->update(P, P_len);
   return hash->final();
   }

}
/*
* KDF2
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* KDF2 Key Derivation Mechanism
*/
SecureVector<byte> KDF2::derive(size_t out_len,
                                const byte secret[], size_t secret_len,
                                const byte P[], size_t P_len) const
   {
   SecureVector<byte> output;
   u32bit counter = 1;

   while(out_len && counter)
      {
      hash->update(secret, secret_len);
      hash->update_be(counter);
      hash->update(P, P_len);

      SecureVector<byte> hash_result = hash->final();

      size_t added = std::min(hash_result.size(), out_len);
      output += std::make_pair(&hash_result[0], added);
      out_len -= added;

      ++counter;
      }

   return output;
   }

}
/*
* MGF1
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

/*
* MGF1 Mask Generation Function
*/
void MGF1::mask(const byte in[], size_t in_len, byte out[],
                size_t out_len) const
   {
   u32bit counter = 0;

   while(out_len)
      {
      hash->update(in, in_len);
      hash->update_be(counter);
      SecureVector<byte> buffer = hash->final();

      size_t xored = std::min<size_t>(buffer.size(), out_len);
      xor_buf(out, &buffer[0], xored);
      out += xored;
      out_len -= xored;

      ++counter;
      }
   }

/*
* MGF1 Constructor
*/
MGF1::MGF1(HashFunction* h) : hash(h)
   {
   if(!hash)
      throw Invalid_Argument("MGF1 given null hash object");
   }

/*
* MGF1 Destructor
*/
MGF1::~MGF1()
   {
   delete hash;
   }

}
/*
* SSLv3 PRF
* (C) 2004-2006 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace {

/*
* Return the next inner hash
*/
OctetString next_hash(size_t where, size_t want,
                      HashFunction& md5, HashFunction& sha1,
                      const byte secret[], size_t secret_len,
                      const byte seed[], size_t seed_len)
   {
   BOTAN_ASSERT(want <= md5.output_length(), "Desired output too large");

   const byte ASCII_A_CHAR = 0x41;

   for(size_t j = 0; j != where + 1; j++)
     sha1.update(static_cast<byte>(ASCII_A_CHAR + where));
   sha1.update(secret, secret_len);
   sha1.update(seed, seed_len);
   SecureVector<byte> sha1_hash = sha1.final();

   md5.update(secret, secret_len);
   md5.update(sha1_hash);
   SecureVector<byte> md5_hash = md5.final();

   return OctetString(&md5_hash[0], want);
   }

}

/*
* SSL3 PRF
*/
SecureVector<byte> SSL3_PRF::derive(size_t key_len,
                                    const byte secret[], size_t secret_len,
                                    const byte seed[], size_t seed_len) const
   {
   if(key_len > 416)
      throw Invalid_Argument("SSL3_PRF: Requested key length is too large");

   MD5 md5;
   SHA_160 sha1;

   OctetString output;

   int counter = 0;
   while(key_len)
      {
      const size_t produce = std::min<size_t>(key_len, md5.output_length());

      output = output + next_hash(counter++, produce, md5, sha1,
                                  secret, secret_len, seed, seed_len);

      key_len -= produce;
      }

   return output.bits_of();
   }

}
/*
* TLS v1.0 and v1.2 PRFs
* (C) 2004-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* TLS PRF P_hash function
*/
void P_hash(MemoryRegion<byte>& output,
            MessageAuthenticationCode* mac,
            const byte secret[], size_t secret_len,
            const byte seed[], size_t seed_len)
   {
   mac->set_key(secret, secret_len);

   SecureVector<byte> A(seed, seed_len);

   size_t offset = 0;

   while(offset != output.size())
      {
      const size_t this_block_len =
         std::min<size_t>(mac->output_length(), output.size() - offset);

      A = mac->process(A);

      mac->update(A);
      mac->update(seed, seed_len);
      SecureVector<byte> block = mac->final();

      xor_buf(&output[offset], &block[0], this_block_len);
      offset += this_block_len;
      }
   }

}

/*
* TLS PRF Constructor and Destructor
*/
TLS_PRF::TLS_PRF()
   {
   hmac_md5 = new HMAC(new MD5);
   hmac_sha1 = new HMAC(new SHA_160);
   }

TLS_PRF::~TLS_PRF()
   {
   delete hmac_md5;
   delete hmac_sha1;
   }

/*
* TLS PRF
*/
SecureVector<byte> TLS_PRF::derive(size_t key_len,
                                   const byte secret[], size_t secret_len,
                                   const byte seed[], size_t seed_len) const
   {
   SecureVector<byte> output(key_len);

   size_t S1_len = (secret_len + 1) / 2,
          S2_len = (secret_len + 1) / 2;
   const byte* S1 = secret;
   const byte* S2 = secret + (secret_len - S2_len);

   P_hash(output, hmac_md5,  S1, S1_len, seed, seed_len);
   P_hash(output, hmac_sha1, S2, S2_len, seed, seed_len);

   return output;
   }

/*
* TLS v1.2 PRF Constructor and Destructor
*/
TLS_12_PRF::TLS_12_PRF(MessageAuthenticationCode* mac) : hmac(mac)
   {
   }

TLS_12_PRF::~TLS_12_PRF()
   {
   delete hmac;
   }

SecureVector<byte> TLS_12_PRF::derive(size_t key_len,
                                      const byte secret[], size_t secret_len,
                                      const byte seed[], size_t seed_len) const
   {
   SecureVector<byte> output(key_len);

   P_hash(output, hmac, secret, secret_len, seed, seed_len);

   return output;
   }

}
/*
* X9.42 PRF
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

namespace {

/*
* Encode an integer as an OCTET STRING
*/
MemoryVector<byte> encode_x942_int(u32bit n)
   {
   byte n_buf[4] = { 0 };
   store_be(n, n_buf);
   return DER_Encoder().encode(n_buf, 4, OCTET_STRING).get_contents();
   }

}

/*
* X9.42 PRF
*/
SecureVector<byte> X942_PRF::derive(size_t key_len,
                                    const byte secret[], size_t secret_len,
                                    const byte salt[], size_t salt_len) const
   {
   SHA_160 hash;
   const OID kek_algo(key_wrap_oid);

   SecureVector<byte> key;
   u32bit counter = 1;

   while(key.size() != key_len && counter)
      {
      hash.update(secret, secret_len);

      hash.update(
         DER_Encoder().start_cons(SEQUENCE)

            .start_cons(SEQUENCE)
               .encode(kek_algo)
               .raw_bytes(encode_x942_int(counter))
            .end_cons()

            .encode_if(salt_len != 0,
               DER_Encoder()
                  .start_explicit(0)
                     .encode(salt, salt_len, OCTET_STRING)
                  .end_explicit()
               )

            .start_explicit(2)
               .raw_bytes(encode_x942_int(static_cast<u32bit>(8 * key_len)))
            .end_explicit()

         .end_cons().get_contents()
         );

      SecureVector<byte> digest = hash.final();
      const size_t needed = std::min(digest.size(), key_len - key.size());
      key += std::make_pair(&digest[0], needed);

      ++counter;
      }

   return key;
   }

/*
* X9.42 Constructor
*/
X942_PRF::X942_PRF(const std::string& oid)
   {
   if(OIDS::have_oid(oid))
      key_wrap_oid = OIDS::lookup(oid).as_string();
   else
      key_wrap_oid = oid;
   }

}
/*
* PBKDF/EMSA/EME/KDF/MGF Retrieval
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_MGF1)
#endif

#if defined(BOTAN_HAS_EMSA1)
#endif

#if defined(BOTAN_HAS_EMSA1_BSI)
#endif

#if defined(BOTAN_HAS_EMSA2)
#endif

#if defined(BOTAN_HAS_EMSA3)
#endif

#if defined(BOTAN_HAS_EMSA4)
#endif

#if defined(BOTAN_HAS_EMSA_RAW)
#endif

#if defined(BOTAN_HAS_EME1)
#endif

#if defined(BOTAN_HAS_EME_PKCS1v15)
#endif

#if defined(BOTAN_HAS_KDF1)
#endif

#if defined(BOTAN_HAS_KDF2)
#endif

#if defined(BOTAN_HAS_X942_PRF)
#endif

#if defined(BOTAN_HAS_SSL_V3_PRF)
#endif

#if defined(BOTAN_HAS_TLS_V10_PRF)
#endif

namespace Botan {

/*
* Get a PBKDF algorithm by name
*/
PBKDF* get_pbkdf(const std::string& algo_spec)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(PBKDF* pbkdf = af.make_pbkdf(algo_spec))
      return pbkdf;

   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Get an EMSA by name
*/
EMSA* get_emsa(const std::string& algo_spec)
   {
   SCAN_Name request(algo_spec);

   Algorithm_Factory& af = global_state().algorithm_factory();

#if defined(BOTAN_HAS_EMSA_RAW)
   if(request.algo_name() == "Raw" && request.arg_count() == 0)
      return new EMSA_Raw;
#endif

#if defined(BOTAN_HAS_EMSA1)
   if(request.algo_name() == "EMSA1" && request.arg_count() == 1)
      return new EMSA1(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_EMSA1_BSI)
   if(request.algo_name() == "EMSA1_BSI" && request.arg_count() == 1)
      return new EMSA1_BSI(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_EMSA2)
   if(request.algo_name() == "EMSA2" && request.arg_count() == 1)
      return new EMSA2(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_EMSA3)
   if(request.algo_name() == "EMSA3" && request.arg_count() == 1)
      {
      if(request.arg(0) == "Raw")
         return new EMSA3_Raw;
      return new EMSA3(af.make_hash_function(request.arg(0)));
      }
#endif

#if defined(BOTAN_HAS_EMSA4)
   if(request.algo_name() == "EMSA4" && request.arg_count_between(1, 3))
      {
      // 3 args: Hash, MGF, salt size (MGF is hardcoded MGF1 in Botan)
      if(request.arg_count() == 1)
         return new EMSA4(af.make_hash_function(request.arg(0)));

      if(request.arg_count() == 2 && request.arg(1) != "MGF1")
         return new EMSA4(af.make_hash_function(request.arg(0)));

      if(request.arg_count() == 3)
         return new EMSA4(af.make_hash_function(request.arg(0)),
                          request.arg_as_integer(2, 0));
      }
#endif

   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Get an EME by name
*/
EME* get_eme(const std::string& algo_spec)
   {
   SCAN_Name request(algo_spec);

   Algorithm_Factory& af = global_state().algorithm_factory();

   if(request.algo_name() == "Raw")
      return 0; // No padding

#if defined(BOTAN_HAS_EME_PKCS1v15)
   if(request.algo_name() == "PKCS1v15" && request.arg_count() == 0)
      return new EME_PKCS1v15;
#endif

#if defined(BOTAN_HAS_EME1)
   if(request.algo_name() == "EME1" && request.arg_count_between(1, 2))
      {
      if(request.arg_count() == 1 ||
         (request.arg_count() == 2 && request.arg(1) == "MGF1"))
         {
         return new EME1(af.make_hash_function(request.arg(0)));
         }
      }
#endif

   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Get an KDF by name
*/
KDF* get_kdf(const std::string& algo_spec)
   {
   SCAN_Name request(algo_spec);

   Algorithm_Factory& af = global_state().algorithm_factory();

   if(request.algo_name() == "Raw")
      return 0; // No KDF

#if defined(BOTAN_HAS_KDF1)
   if(request.algo_name() == "KDF1" && request.arg_count() == 1)
      return new KDF1(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_KDF2)
   if(request.algo_name() == "KDF2" && request.arg_count() == 1)
      return new KDF2(af.make_hash_function(request.arg(0)));
#endif

#if defined(BOTAN_HAS_X942_PRF)
   if(request.algo_name() == "X9.42-PRF" && request.arg_count() == 1)
      return new X942_PRF(request.arg(0)); // OID
#endif

#if defined(BOTAN_HAS_TLS_V10_PRF)
   if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0)
      return new TLS_PRF;
#endif

#if defined(BOTAN_HAS_SSL_V3_PRF)
   if(request.algo_name() == "SSL3-PRF" && request.arg_count() == 0)
      return new SSL3_PRF;
#endif

   throw Algorithm_Not_Found(algo_spec);
   }

}
/*
* Global PRNG
* (C) 2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_RANDPOOL)
#endif

#if defined(BOTAN_HAS_HMAC_RNG)
#endif

#if defined(BOTAN_HAS_X931_RNG)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_FTW)
#endif

namespace Botan {

namespace {

/**
* Add any known entropy sources to this RNG
*/
void add_entropy_sources(RandomNumberGenerator* rng)
   {
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
   rng->add_entropy_source(new High_Resolution_Timestamp);
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
   rng->add_entropy_source(new Intel_Rdrand);
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
   rng->add_entropy_source(
      new Device_EntropySource(
         split_on("/dev/random:/dev/srandom:/dev/urandom", ':')
         )
      );
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
   rng->add_entropy_source(
      new EGD_EntropySource(split_on("/var/run/egd-pool:/dev/egd-pool", ':'))
      );
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
   rng->add_entropy_source(new Win32_CAPI_EntropySource);
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_FTW)
   rng->add_entropy_source(new FTW_EntropySource("/proc"));
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
   rng->add_entropy_source(new Win32_EntropySource);
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
   rng->add_entropy_source(new BeOS_EntropySource);
#endif

#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX)
   rng->add_entropy_source(
      new Unix_EntropySource(split_on("/bin:/sbin:/usr/bin:/usr/sbin", ':'))
      );
#endif
   }

class Serialized_PRNG : public RandomNumberGenerator
   {
   public:
      void randomize(byte out[], size_t len)
         {
         Mutex_Holder lock(mutex);
         rng->randomize(out, len);
         }

      bool is_seeded() const
         {
         Mutex_Holder lock(mutex);
         return rng->is_seeded();
         }

      void clear()
         {
         Mutex_Holder lock(mutex);
         rng->clear();
         }

      std::string name() const
         {
         Mutex_Holder lock(mutex);
         return rng->name();
         }

      void reseed(size_t poll_bits)
         {
         Mutex_Holder lock(mutex);
         rng->reseed(poll_bits);
         }

      void add_entropy_source(EntropySource* es)
         {
         Mutex_Holder lock(mutex);
         rng->add_entropy_source(es);
         }

      void add_entropy(const byte in[], size_t len)
         {
         Mutex_Holder lock(mutex);
         rng->add_entropy(in, len);
         }

      // We do not own the mutex; Library_State does
      Serialized_PRNG(RandomNumberGenerator* r, Mutex* m) :
         mutex(m), rng(r) {}

      ~Serialized_PRNG() { delete rng; }
   private:
      Mutex* mutex;
      RandomNumberGenerator* rng;
   };

}

RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af,
                                                      Mutex* mutex)
   {
   RandomNumberGenerator* rng = 0;

#if defined(BOTAN_HAS_HMAC_RNG)

   rng = new HMAC_RNG(af.make_mac("HMAC(SHA-512)"),
                      af.make_mac("HMAC(SHA-256)"));

#elif defined(BOTAN_HAS_RANDPOOL)

   rng = new Randpool(af.make_block_cipher("AES-256"),
                      af.make_mac("HMAC(SHA-256)"));

#endif

   if(!rng)
      throw Internal_Error("No usable RNG found enabled in build");

   /* If X9.31 is available, use it to wrap the other RNG as a failsafe */
#if defined(BOTAN_HAS_X931_RNG)

   rng = new ANSI_X931_RNG(af.make_block_cipher("AES-256"), rng);

#endif

   add_entropy_sources(rng);

   rng->reseed(256);

   return new Serialized_PRNG(rng, mutex);
   }

}
/*
* Global State Management
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* @todo There should probably be a lock to avoid racy manipulation
* of the state among different threads
*/

namespace Global_State_Management {

/*
* Botan's global state
*/
namespace {

Library_State* global_lib_state = 0;

}

/*
* Access the global state object
*/
Library_State& global_state()
   {
   /* Lazy initialization. Botan still needs to be deinitialized later
      on or memory might leak.
   */
   if(!global_lib_state)
      {
      global_lib_state = new Library_State;
      global_lib_state->initialize(true);
      }

   return (*global_lib_state);
   }

/*
* Set a new global state object
*/
void set_global_state(Library_State* new_state)
   {
   delete swap_global_state(new_state);
   }

/*
* Set a new global state object unless one already existed
*/
bool set_global_state_unless_set(Library_State* new_state)
   {
   if(global_lib_state)
      {
      delete new_state;
      return false;
      }
   else
      {
      delete swap_global_state(new_state);
      return true;
      }
   }

/*
* Swap two global state objects
*/
Library_State* swap_global_state(Library_State* new_state)
   {
   Library_State* old_state = global_lib_state;
   global_lib_state = new_state;
   return old_state;
   }

/*
* Query if library is initialized
*/
bool global_state_exists()
   {
   return (global_lib_state != 0);
   }

}

}
/*
* Default Initialization Function
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Library Initialization
*/
void LibraryInitializer::initialize(const std::string& arg_string)
   {
   bool thread_safe = false;

   const std::vector<std::string> arg_list = split_on(arg_string, ' ');
   for(size_t i = 0; i != arg_list.size(); ++i)
      {
      if(arg_list[i].size() == 0)
         continue;

      std::string name, value;

      if(arg_list[i].find('=') == std::string::npos)
         {
         name = arg_list[i];
         value = "true";
         }
      else
         {
         std::vector<std::string> name_and_value = split_on(arg_list[i], '=');
         name = name_and_value[0];
         value = name_and_value[1];
         }

      bool is_on =
         (value == "1" || value == "true" || value == "yes" || value == "on");

      if(name == "thread_safe")
         thread_safe = is_on;
      }

   try
      {
      /*
      This two stage initialization process is because Library_State's
      constructor will implicitly refer to global state through the
      allocators and so forth, so global_state() has to be a valid
      reference before initialize() can be called. Yeah, gross.
      */
      Global_State_Management::set_global_state(new Library_State);

      global_state().initialize(thread_safe);
      }
   catch(...)
      {
      deinitialize();
      throw;
      }
   }

/*
* Library Shutdown
*/
void LibraryInitializer::deinitialize()
   {
   Global_State_Management::set_global_state(0);
   }

}
/*
* Library Internal/Global State
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

#if defined(BOTAN_HAS_SELFTESTS)
#endif

#if defined(BOTAN_HAS_MUTEX_PTHREAD)
#elif defined(BOTAN_HAS_MUTEX_WIN32)
#endif

#if defined(BOTAN_HAS_ALLOC_MMAP)
#endif

#if defined(BOTAN_HAS_ENGINE_ASSEMBLER)
#endif

#if defined(BOTAN_HAS_ENGINE_AES_ISA)
#endif

#if defined(BOTAN_HAS_ENGINE_SIMD)
#endif

#if defined(BOTAN_HAS_ENGINE_GNU_MP)
#endif

#if defined(BOTAN_HAS_ENGINE_OPENSSL)
#endif

namespace Botan {

/*
* Get a new mutex object
*/
Mutex* Library_State::get_mutex() const
   {
   return mutex_factory->make();
   }

/*
* Get an allocator by its name
*/
Allocator* Library_State::get_allocator(const std::string& type) const
   {
   Mutex_Holder lock(allocator_lock);

   if(type != "")
      return search_map<std::string, Allocator*>(alloc_factory, type, 0);

   if(!cached_default_allocator)
      {
      cached_default_allocator =
         search_map<std::string, Allocator*>(alloc_factory,
                                             default_allocator_name, 0);
      }

   return cached_default_allocator;
   }

/*
* Create a new name to object mapping
*/
void Library_State::add_allocator(Allocator* allocator)
   {
   Mutex_Holder lock(allocator_lock);

   allocator->init();

   allocators.push_back(allocator);
   alloc_factory[allocator->type()] = allocator;
   }

/*
* Set the default allocator type
*/
void Library_State::set_default_allocator(const std::string& type)
   {
   Mutex_Holder lock(allocator_lock);

   if(type == "")
      return;

   default_allocator_name = type;
   cached_default_allocator = 0;
   }

/*
* Get a configuration value
*/
std::string Library_State::get(const std::string& section,
                               const std::string& key) const
   {
   Mutex_Holder lock(config_lock);

   return search_map<std::string, std::string>(config,
                                               section + "/" + key, "");
   }

/*
* See if a particular option has been set
*/
bool Library_State::is_set(const std::string& section,
                           const std::string& key) const
   {
   Mutex_Holder lock(config_lock);

   return config.count(section + "/" + key) != 0;
   }

/*
* Set a configuration value
*/
void Library_State::set(const std::string& section, const std::string& key,
                        const std::string& value, bool overwrite)
   {
   Mutex_Holder lock(config_lock);

   std::string full_key = section + "/" + key;

   std::map<std::string, std::string>::const_iterator i =
      config.find(full_key);

   if(overwrite || i == config.end() || i->second == "")
      config[full_key] = value;
   }

/*
* Add an alias
*/
void Library_State::add_alias(const std::string& key, const std::string& value)
   {
   set("alias", key, value);
   }

/*
* Dereference an alias to a fixed name
*/
std::string Library_State::deref_alias(const std::string& key) const
   {
   std::string result = key;
   while(is_set("alias", result))
      result = get("alias", result);
   return result;
   }

/*
* Return a reference to the Algorithm_Factory
*/
Algorithm_Factory& Library_State::algorithm_factory() const
   {
   if(!m_algorithm_factory)
      throw Invalid_State("Uninitialized in Library_State::algorithm_factory");
   return *m_algorithm_factory;
   }

/*
* Return a reference to the global PRNG
*/
RandomNumberGenerator& Library_State::global_rng()
   {
   Mutex_Holder lock(global_rng_lock);

   if(!global_rng_ptr)
      global_rng_ptr = make_global_rng(algorithm_factory(),
                                       global_rng_lock);

   return *global_rng_ptr;
   }

/*
* Load a set of modules
*/
void Library_State::initialize(bool thread_safe)
   {
   CPUID::initialize();

   if(mutex_factory)
      throw Invalid_State("Library_State has already been initialized");

   if(!thread_safe)
      {
      mutex_factory = new Noop_Mutex_Factory;
      }
   else
      {
#if defined(BOTAN_HAS_MUTEX_PTHREAD)
      mutex_factory = new Pthread_Mutex_Factory;
#elif defined(BOTAN_HAS_MUTEX_WIN32)
      mutex_factory = new Win32_Mutex_Factory;
#else
      throw Invalid_State("Could not find a thread-safe mutex object to use");
#endif
      }

   allocator_lock = get_mutex();
   config_lock = get_mutex();
   global_rng_lock = get_mutex();

   default_allocator_name = has_mlock() ? "locking" : "malloc";

   add_allocator(new Malloc_Allocator);
   add_allocator(new Locking_Allocator(get_mutex()));

#if defined(BOTAN_HAS_ALLOC_MMAP)
   add_allocator(new MemoryMapping_Allocator(get_mutex()));
#endif

   load_default_config();

   m_algorithm_factory = new Algorithm_Factory(*mutex_factory);

#if defined(BOTAN_HAS_ENGINE_GNU_MP)
   algorithm_factory().add_engine(new GMP_Engine);
#endif

#if defined(BOTAN_HAS_ENGINE_OPENSSL)
   algorithm_factory().add_engine(new OpenSSL_Engine);
#endif

#if defined(BOTAN_HAS_ENGINE_AES_ISA)
   algorithm_factory().add_engine(new AES_ISA_Engine);
#endif

#if defined(BOTAN_HAS_ENGINE_SIMD)
   algorithm_factory().add_engine(new SIMD_Engine);
#endif

#if defined(BOTAN_HAS_ENGINE_ASSEMBLER)
   algorithm_factory().add_engine(new Assembler_Engine);
#endif

   algorithm_factory().add_engine(new Core_Engine);

#if defined(BOTAN_HAS_SELFTESTS)
   confirm_startup_self_tests(algorithm_factory());
#endif
   }

/*
* Library_State Constructor
*/
Library_State::Library_State()
   {
   mutex_factory = 0;
   allocator_lock = config_lock = 0;
   cached_default_allocator = 0;
   m_algorithm_factory = 0;

   global_rng_lock = 0;
   global_rng_ptr = 0;
   }

/*
* Library_State Destructor
*/
Library_State::~Library_State()
   {
   delete m_algorithm_factory;
   delete global_rng_ptr;

   cached_default_allocator = 0;

   for(size_t i = 0; i != allocators.size(); ++i)
      {
      allocators[i]->destroy();
      delete allocators[i];
      }

   delete global_rng_lock;
   delete allocator_lock;
   delete mutex_factory;
   delete config_lock;
   }

}
/*
* Algorithm Retrieval
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Query if an algorithm exists
*/
bool have_algorithm(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(af.prototype_block_cipher(name))
      return true;
   if(af.prototype_stream_cipher(name))
      return true;
   if(af.prototype_hash_function(name))
      return true;
   if(af.prototype_mac(name))
      return true;
   return false;
   }

/*
* Query the block size of a cipher or hash
*/
size_t block_size_of(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(const BlockCipher* cipher = af.prototype_block_cipher(name))
      return cipher->block_size();

   if(const HashFunction* hash = af.prototype_hash_function(name))
      return hash->hash_block_size();

   throw Algorithm_Not_Found(name);
   }

/*
* Query the output_length() of a hash or MAC
*/
size_t output_length_of(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(const HashFunction* hash = af.prototype_hash_function(name))
      return hash->output_length();

   if(const MessageAuthenticationCode* mac = af.prototype_mac(name))
      return mac->output_length();

   throw Algorithm_Not_Found(name);
   }

/*
* Query the minimum allowed key length of an algorithm implementation
*/
size_t min_keylength_of(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(const BlockCipher* bc = af.prototype_block_cipher(name))
      return bc->key_spec().minimum_keylength();

   if(const StreamCipher* sc = af.prototype_stream_cipher(name))
      return sc->key_spec().minimum_keylength();

   if(const MessageAuthenticationCode* mac = af.prototype_mac(name))
      return mac->key_spec().minimum_keylength();

   throw Algorithm_Not_Found(name);
   }

/*
* Query the maximum allowed keylength of an algorithm implementation
*/
size_t max_keylength_of(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(const BlockCipher* bc = af.prototype_block_cipher(name))
      return bc->key_spec().maximum_keylength();

   if(const StreamCipher* sc = af.prototype_stream_cipher(name))
      return sc->key_spec().maximum_keylength();

   if(const MessageAuthenticationCode* mac = af.prototype_mac(name))
      return mac->key_spec().maximum_keylength();

   throw Algorithm_Not_Found(name);
   }

/*
* Query the number of byte a valid key must be a multiple of
*/
size_t keylength_multiple_of(const std::string& name)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   if(const BlockCipher* bc = af.prototype_block_cipher(name))
      return bc->key_spec().keylength_multiple();

   if(const StreamCipher* sc = af.prototype_stream_cipher(name))
      return sc->key_spec().keylength_multiple();

   if(const MessageAuthenticationCode* mac = af.prototype_mac(name))
      return mac->key_spec().keylength_multiple();

   throw Algorithm_Not_Found(name);
   }

/*
* Get a cipher object
*/
Keyed_Filter* get_cipher(const std::string& algo_spec,
                         Cipher_Dir direction)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   Algorithm_Factory::Engine_Iterator i(af);

   while(Engine* engine = i.next())
      {
      if(Keyed_Filter* algo = engine->get_cipher(algo_spec, direction, af))
         return algo;
      }

   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Get a cipher object
*/
Keyed_Filter* get_cipher(const std::string& algo_spec,
                         const SymmetricKey& key,
                         const InitializationVector& iv,
                         Cipher_Dir direction)
   {
   Keyed_Filter* cipher = get_cipher(algo_spec, direction);
   cipher->set_key(key);

   if(iv.length())
      cipher->set_iv(iv);

   return cipher;
   }

/*
* Get a cipher object
*/
Keyed_Filter* get_cipher(const std::string& algo_spec,
                         const SymmetricKey& key,
                         Cipher_Dir direction)
   {
   return get_cipher(algo_spec,
                     key, InitializationVector(), direction);
   }

}
/*
* OID Registry
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace OIDS {

/*
* Register an OID to string mapping
*/
void add_oid(const OID& oid, const std::string& name)
   {
   const std::string oid_str = oid.as_string();

   if(!global_state().is_set("oid2str", oid_str))
      global_state().set("oid2str", oid_str, name);
   if(!global_state().is_set("str2oid", name))
      global_state().set("str2oid", name, oid_str);
   }

/*
* Do an OID to string lookup
*/
std::string lookup(const OID& oid)
   {
   std::string name = global_state().get("oid2str", oid.as_string());
   if(name == "")
      return oid.as_string();
   return name;
   }

/*
* Do a string to OID lookup
*/
OID lookup(const std::string& name)
   {
   std::string value = global_state().get("str2oid", name);
   if(value != "")
      return OID(value);

   try
      {
      return OID(name);
      }
   catch(...)
      {
      throw Lookup_Error("No object identifier found for " + name);
      }
   }

/*
* Check to see if an OID exists in the table
*/
bool have_oid(const std::string& name)
   {
   return global_state().is_set("str2oid", name);
   }

/*
* Check to see if an OID exists in the table
*/
bool name_of(const OID& oid, const std::string& name)
   {
   return (oid == lookup(name));
   }

}

}
/*
* Default Policy
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* OID loading helper function
*/
void add_oid(Library_State& config,
             const std::string& oid_str,
             const std::string& name)
   {
   if(!config.is_set("oid2str", oid_str))
      config.set("oid2str", oid_str, name);
   if(!config.is_set("str2oid", name))
      config.set("str2oid", name, oid_str);
   }

/*
* Load all of the default OIDs
*/
void set_default_oids(Library_State& config)
   {
   /* Public key types */
   add_oid(config, "1.2.840.113549.1.1.1", "RSA");
   add_oid(config, "2.5.8.1.1", "RSA"); // RSA alternate
   add_oid(config, "1.2.840.10040.4.1", "DSA");
   add_oid(config, "1.2.840.10046.2.1", "DH");
   add_oid(config, "1.3.6.1.4.1.3029.1.2.1", "ElGamal");
   add_oid(config, "1.3.6.1.4.1.25258.1.1", "RW");
   add_oid(config, "1.3.6.1.4.1.25258.1.2", "NR");

   // X9.62 ecPublicKey, valid for ECDSA and ECDH (RFC 3279 sec 2.3.5)
   add_oid(config, "1.2.840.10045.2.1", "ECDSA");

   /*
   * This is an OID defined for ECDH keys though rarely used for such.
   * In this configuration it is accepted on decoding, but not used for
   * encoding. You can enable it for encoding by calling
   *    global_state().set("str2oid", "ECDH", "1.3.132.1.12")
   * from your application code.
   */
   config.set("oid2str", "1.3.132.1.12", "ECDH");

   add_oid(config, "1.2.643.2.2.19", "GOST-34.10"); // RFC 4491

   /* Ciphers */
   add_oid(config, "1.3.14.3.2.7", "DES/CBC");
   add_oid(config, "1.2.840.113549.3.7", "TripleDES/CBC");
   add_oid(config, "1.2.840.113549.3.2", "RC2/CBC");
   add_oid(config, "1.2.840.113533.7.66.10", "CAST-128/CBC");
   add_oid(config, "2.16.840.1.101.3.4.1.2", "AES-128/CBC");
   add_oid(config, "2.16.840.1.101.3.4.1.22", "AES-192/CBC");
   add_oid(config, "2.16.840.1.101.3.4.1.42", "AES-256/CBC");
   add_oid(config, "1.2.410.200004.1.4", "SEED/CBC"); // RFC 4010
   add_oid(config, "1.3.6.1.4.1.25258.3.1", "Serpent/CBC");

   /* Hash Functions */
   add_oid(config, "1.2.840.113549.2.5", "MD5");
   add_oid(config, "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)");

   add_oid(config, "1.3.14.3.2.26", "SHA-160");
   add_oid(config, "2.16.840.1.101.3.4.2.4", "SHA-224");
   add_oid(config, "2.16.840.1.101.3.4.2.1", "SHA-256");
   add_oid(config, "2.16.840.1.101.3.4.2.2", "SHA-384");
   add_oid(config, "2.16.840.1.101.3.4.2.3", "SHA-512");

   /* MACs */
   add_oid(config, "1.2.840.113549.2.7", "HMAC(SHA-1)");
   add_oid(config, "1.2.840.113549.2.8", "HMAC(SHA-224)");
   add_oid(config, "1.2.840.113549.2.9", "HMAC(SHA-256)");
   add_oid(config, "1.2.840.113549.2.10", "HMAC(SHA-384)");
   add_oid(config, "1.2.840.113549.2.11", "HMAC(SHA-512)");

   /* Key Wrap */
   add_oid(config, "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES");
   add_oid(config, "1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2");
   add_oid(config, "1.2.840.113533.7.66.15", "KeyWrap.CAST-128");
   add_oid(config, "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128");
   add_oid(config, "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192");
   add_oid(config, "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256");

   /* Compression */
   add_oid(config, "1.2.840.113549.1.9.16.3.8", "Compression.Zlib");

   /* Public key signature schemes */
   add_oid(config, "1.2.840.113549.1.1.1", "RSA/EME-PKCS1-v1_5");
   add_oid(config, "1.2.840.113549.1.1.2", "RSA/EMSA3(MD2)");
   add_oid(config, "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)");
   add_oid(config, "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)");
   add_oid(config, "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)");
   add_oid(config, "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)");
   add_oid(config, "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)");
   add_oid(config, "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)");

   add_oid(config, "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)");
   add_oid(config, "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)");
   add_oid(config, "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)");

   add_oid(config, "0.4.0.127.0.7.1.1.4.1.1", "ECDSA/EMSA1_BSI(SHA-160)");
   add_oid(config, "0.4.0.127.0.7.1.1.4.1.2", "ECDSA/EMSA1_BSI(SHA-224)");
   add_oid(config, "0.4.0.127.0.7.1.1.4.1.3", "ECDSA/EMSA1_BSI(SHA-256)");
   add_oid(config, "0.4.0.127.0.7.1.1.4.1.4", "ECDSA/EMSA1_BSI(SHA-384)");
   add_oid(config, "0.4.0.127.0.7.1.1.4.1.5", "ECDSA/EMSA1_BSI(SHA-512)");
   add_oid(config, "0.4.0.127.0.7.1.1.4.1.6", "ECDSA/EMSA1_BSI(RIPEMD-160)");

   add_oid(config, "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)");
   add_oid(config, "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)");
   add_oid(config, "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)");
   add_oid(config, "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)");
   add_oid(config, "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)");

   add_oid(config, "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)");

   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.1", "RW/EMSA2(RIPEMD-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.2", "RW/EMSA2(SHA-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.3", "RW/EMSA2(SHA-224)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.4", "RW/EMSA2(SHA-256)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.5", "RW/EMSA2(SHA-384)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.1.6", "RW/EMSA2(SHA-512)");

   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.1", "RW/EMSA4(RIPEMD-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.2", "RW/EMSA4(SHA-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.3", "RW/EMSA4(SHA-224)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.4", "RW/EMSA4(SHA-256)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.5", "RW/EMSA4(SHA-384)");
   add_oid(config, "1.3.6.1.4.1.25258.2.1.2.6", "RW/EMSA4(SHA-512)");

   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.1", "NR/EMSA2(RIPEMD-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.2", "NR/EMSA2(SHA-160)");
   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.3", "NR/EMSA2(SHA-224)");
   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.4", "NR/EMSA2(SHA-256)");
   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.5", "NR/EMSA2(SHA-384)");
   add_oid(config, "1.3.6.1.4.1.25258.2.2.1.6", "NR/EMSA2(SHA-512)");

   add_oid(config, "2.5.4.3",  "X520.CommonName");
   add_oid(config, "2.5.4.4",  "X520.Surname");
   add_oid(config, "2.5.4.5",  "X520.SerialNumber");
   add_oid(config, "2.5.4.6",  "X520.Country");
   add_oid(config, "2.5.4.7",  "X520.Locality");
   add_oid(config, "2.5.4.8",  "X520.State");
   add_oid(config, "2.5.4.10", "X520.Organization");
   add_oid(config, "2.5.4.11", "X520.OrganizationalUnit");
   add_oid(config, "2.5.4.12", "X520.Title");
   add_oid(config, "2.5.4.42", "X520.GivenName");
   add_oid(config, "2.5.4.43", "X520.Initials");
   add_oid(config, "2.5.4.44", "X520.GenerationalQualifier");
   add_oid(config, "2.5.4.46", "X520.DNQualifier");
   add_oid(config, "2.5.4.65", "X520.Pseudonym");

   add_oid(config, "1.2.840.113549.1.5.12", "PKCS5.PBKDF2");
   add_oid(config, "1.2.840.113549.1.5.1",  "PBE-PKCS5v15(MD2,DES/CBC)");
   add_oid(config, "1.2.840.113549.1.5.4",  "PBE-PKCS5v15(MD2,RC2/CBC)");
   add_oid(config, "1.2.840.113549.1.5.3",  "PBE-PKCS5v15(MD5,DES/CBC)");
   add_oid(config, "1.2.840.113549.1.5.6",  "PBE-PKCS5v15(MD5,RC2/CBC)");
   add_oid(config, "1.2.840.113549.1.5.10", "PBE-PKCS5v15(SHA-160,DES/CBC)");
   add_oid(config, "1.2.840.113549.1.5.11", "PBE-PKCS5v15(SHA-160,RC2/CBC)");
   add_oid(config, "1.2.840.113549.1.5.13", "PBE-PKCS5v20");

   add_oid(config, "1.2.840.113549.1.9.1", "PKCS9.EmailAddress");
   add_oid(config, "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName");
   add_oid(config, "1.2.840.113549.1.9.3", "PKCS9.ContentType");
   add_oid(config, "1.2.840.113549.1.9.4", "PKCS9.MessageDigest");
   add_oid(config, "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword");
   add_oid(config, "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest");

   add_oid(config, "1.2.840.113549.1.7.1",      "CMS.DataContent");
   add_oid(config, "1.2.840.113549.1.7.2",      "CMS.SignedData");
   add_oid(config, "1.2.840.113549.1.7.3",      "CMS.EnvelopedData");
   add_oid(config, "1.2.840.113549.1.7.5",      "CMS.DigestedData");
   add_oid(config, "1.2.840.113549.1.7.6",      "CMS.EncryptedData");
   add_oid(config, "1.2.840.113549.1.9.16.1.2", "CMS.AuthenticatedData");
   add_oid(config, "1.2.840.113549.1.9.16.1.9", "CMS.CompressedData");

   add_oid(config, "2.5.29.14", "X509v3.SubjectKeyIdentifier");
   add_oid(config, "2.5.29.15", "X509v3.KeyUsage");
   add_oid(config, "2.5.29.17", "X509v3.SubjectAlternativeName");
   add_oid(config, "2.5.29.18", "X509v3.IssuerAlternativeName");
   add_oid(config, "2.5.29.19", "X509v3.BasicConstraints");
   add_oid(config, "2.5.29.20", "X509v3.CRLNumber");
   add_oid(config, "2.5.29.21", "X509v3.ReasonCode");
   add_oid(config, "2.5.29.23", "X509v3.HoldInstructionCode");
   add_oid(config, "2.5.29.24", "X509v3.InvalidityDate");
   add_oid(config, "2.5.29.32", "X509v3.CertificatePolicies");
   add_oid(config, "2.5.29.35", "X509v3.AuthorityKeyIdentifier");
   add_oid(config, "2.5.29.36", "X509v3.PolicyConstraints");
   add_oid(config, "2.5.29.37", "X509v3.ExtendedKeyUsage");

   add_oid(config, "2.5.29.32.0", "X509v3.AnyPolicy");

   add_oid(config, "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth");
   add_oid(config, "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth");
   add_oid(config, "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning");
   add_oid(config, "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection");
   add_oid(config, "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem");
   add_oid(config, "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel");
   add_oid(config, "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser");
   add_oid(config, "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping");
   add_oid(config, "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning");

   add_oid(config, "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr");

   /* ECC domain parameters */

   add_oid(config, "1.3.132.0.6",  "secp112r1");
   add_oid(config, "1.3.132.0.7",  "secp112r2");
   add_oid(config, "1.3.132.0.8",  "secp160r1");
   add_oid(config, "1.3.132.0.9",  "secp160k1");
   add_oid(config, "1.3.132.0.10", "secp256k1");
   add_oid(config, "1.3.132.0.28", "secp128r1");
   add_oid(config, "1.3.132.0.29", "secp128r2");
   add_oid(config, "1.3.132.0.30", "secp160r2");
   add_oid(config, "1.3.132.0.31", "secp192k1");
   add_oid(config, "1.3.132.0.32", "secp224k1");
   add_oid(config, "1.3.132.0.33", "secp224r1");
   add_oid(config, "1.3.132.0.34", "secp384r1");
   add_oid(config, "1.3.132.0.35", "secp521r1");

   add_oid(config, "1.2.840.10045.3.1.1", "secp192r1");
   add_oid(config, "1.2.840.10045.3.1.2", "x962_p192v2");
   add_oid(config, "1.2.840.10045.3.1.3", "x962_p192v3");
   add_oid(config, "1.2.840.10045.3.1.4", "x962_p239v1");
   add_oid(config, "1.2.840.10045.3.1.5", "x962_p239v2");
   add_oid(config, "1.2.840.10045.3.1.6", "x962_p239v3");
   add_oid(config, "1.2.840.10045.3.1.7", "secp256r1");

   add_oid(config, "1.3.36.3.3.2.8.1.1.1",  "brainpool160r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.3",  "brainpool192r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.5",  "brainpool224r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.7",  "brainpool256r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.9",  "brainpool320r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.11", "brainpool384r1");
   add_oid(config, "1.3.36.3.3.2.8.1.1.13", "brainpool512r1");

   add_oid(config, "1.2.643.2.2.35.1", "gost_256A");
   add_oid(config, "1.2.643.2.2.36.0", "gost_256A");

   /* CVC */
   add_oid(config, "0.4.0.127.0.7.3.1.2.1",
           "CertificateHolderAuthorizationTemplate");
   }

/*
* Set the default algorithm aliases
*/
void set_default_aliases(Library_State& config)
   {
   config.add_alias("OpenPGP.Cipher.1",  "IDEA");
   config.add_alias("OpenPGP.Cipher.2",  "TripleDES");
   config.add_alias("OpenPGP.Cipher.3",  "CAST-128");
   config.add_alias("OpenPGP.Cipher.4",  "Blowfish");
   config.add_alias("OpenPGP.Cipher.5",  "SAFER-SK(13)");
   config.add_alias("OpenPGP.Cipher.7",  "AES-128");
   config.add_alias("OpenPGP.Cipher.8",  "AES-192");
   config.add_alias("OpenPGP.Cipher.9",  "AES-256");
   config.add_alias("OpenPGP.Cipher.10", "Twofish");

   config.add_alias("OpenPGP.Digest.1", "MD5");
   config.add_alias("OpenPGP.Digest.2", "SHA-1");
   config.add_alias("OpenPGP.Digest.3", "RIPEMD-160");
   config.add_alias("OpenPGP.Digest.5", "MD2");
   config.add_alias("OpenPGP.Digest.6", "Tiger(24,3)");
   config.add_alias("OpenPGP.Digest.8", "SHA-256");

   config.add_alias("TLS.Digest.0",     "Parallel(MD5,SHA-160)");

   config.add_alias("EME-PKCS1-v1_5",  "PKCS1v15");
   config.add_alias("OAEP-MGF1",       "EME1");
   config.add_alias("EME-OAEP",        "EME1");
   config.add_alias("X9.31",           "EMSA2");
   config.add_alias("EMSA-PKCS1-v1_5", "EMSA3");
   config.add_alias("PSS-MGF1",        "EMSA4");
   config.add_alias("EMSA-PSS",        "EMSA4");

   config.add_alias("3DES",     "TripleDES");
   config.add_alias("DES-EDE",  "TripleDES");
   config.add_alias("CAST5",    "CAST-128");
   config.add_alias("SHA1",     "SHA-160");
   config.add_alias("SHA-1",    "SHA-160");
   config.add_alias("MARK-4",   "ARC4(256)");
   config.add_alias("OMAC",     "CMAC");
   config.add_alias("GOST",     "GOST-28147-89");
   }

/*
* Set the built-in discrete log groups
*/
void set_default_dl_groups(Library_State& config)
   {
   config.set("dl", "modp/ietf/768",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIHIAmEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFK"
         "CHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjo2IP//"
         "////////AgECAmB//////////+SH7VEQtGEaYmMxRcBuDmiUgScERTPmOgEF31Md"
         "ic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Catrao4SLyQtq7MS8/Y3omIXTT"
         "HRsQf/////////8="
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/ietf/1024",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIBCgKBgQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si"
         "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r"
         "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezmU4H//////////wIBAgKBgH//"
         "////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXfUx2JzZEopQQ8xxoCbvfK"
         "jNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYhdNMb9rWF/65begNb9vcc"
         "Nf2tRM/S10+SCL4lj/MklDMo9nMpwP//////////"
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/1024",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIBCgKBgQDurwq5rbON1pwz+Ar6j8XoYHJhh3X/PAueojFMnCVldtZ033SW6oHT"
         "ODtIE9aSxuDg1djiULmL5I5JXB1gidrRXcfXtGFU1rbOjvStabFdSYJVmyl7zxiF"
         "xSn1ZmYOV+xo7bw8BXJswC/Uy/SXbqqa/VE4/oN2Q1ufxh0vwOsG4wIBAgKBgHdX"
         "hVzW2cbrThn8BX1H4vQwOTDDuv+eBc9RGKZOErK7azpvukt1QOmcHaQJ60ljcHBq"
         "7HEoXMXyRySuDrBE7Wiu4+vaMKprW2dHela02K6kwSrNlL3njELilPqzMwcr9jR2"
         "3h4CuTZgF+pl+ku3VU1+qJx/Qbshrc/jDpfgdYNx"
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/ietf/1536",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIBigKBwQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si"
         "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r"
         "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezkWz3CAHy4oWO/BZjaSDYcVdOa"
         "aRY/qP0kz1+DZV0j3KOtlhxi81YghVK7ntUpB3CWlm1nDDVOSryYBPF0bAjKI3Mn"
         "//////////8CAQICgcB//////////+SH7VEQtGEaYmMxRcBuDmiUgScERTPmOgEF"
         "31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Catrao4SLyQtq7MS8/Y3om"
         "IXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQzKPZyLZ7hAD5cULHfgsxt"
         "JBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qUg7hLSzazhhqnJV5MAni6"
         "NgRlEbmT//////////8="
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/1536",
         "-----BEGIN DH PARAMETERS-----"
         "MIHHAoHBAJ3vPK+5OSd6sfEqhheke7vbpR30maxMgL7uqWFLGcxNX09fVW4ny95R"
         "xqlL5GB6KRVYkDug0PhDgLZVu5oi6NzfAop87Gfw0IE0sci5eYkUm2CeC+O6tj1H"
         "VIOB28Wx/HZOP0tT3Z2hFYv9PiucjPVu3wGVOTSWJ9sv1T0kt8SGZXcuQ31sf4zk"
         "QnNK98y3roN8Jkrjqb64f4ov6bi1KS5aAh//XpFHnoznoowkQsbzFRgPk0maI03P"
         "duP+0TX5uwIBAg=="
         "-----END DH PARAMETERS-----");

   config.set("dl", "modp/ietf/2048",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIICDAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAgKCAQB//////////+SH7VEQtGEa"
         "YmMxRcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4ob"
         "p/Catrao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/z"
         "JJQzKPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqld"
         "z2qUg7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH"
         "2uKu+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVZVNH//////////"
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/2048",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIICDAKCAQEArGvbQTJKmpvxZt5eE4lYL69ytmUZh+4H/DGSlD21YFCjcynLtKCZ"
         "7YGT4HV3Z6E91SMSq0sDMQ3Nf0ip2gT9UOgIOWntt2ewz2CVF5oWOrNmGgX71fqq"
         "6CkYqZYvC5O4Vfl5k+yXXuqoDXQK2/T/dHNZ0EHVwz6nHSgeRGsUdzvKl7Q6I/uA"
         "Fna9IHpDbGSB8dK5B4cXRhpbnTLmiPh3SFRFI7UksNV9Xqd6J3XS7PoDLPvb9S+z"
         "eGFgJ5AE5Xrmr4dOcwPOUymczAQce8MI2CpWmPOo0MOCca41+Onb+7aUtcgD2J96"
         "5DXeI21SX1R1m2XjcvzWjvIPpxEfnkr/cwIBAgKCAQBWNe2gmSVNTfizby8JxKwX"
         "17lbMozD9wP+GMlKHtqwKFG5lOXaUEz2wMnwOruz0J7qkYlVpYGYhua/pFTtAn6o"
         "dAQctPbbs9hnsEqLzQsdWbMNAv3q/VV0FIxUyxeFydwq/LzJ9kuvdVQGugVt+n+6"
         "OazoIOrhn1OOlA8iNYo7neVL2h0R/cALO16QPSG2MkD46VyDw4ujDS3OmXNEfDuk"
         "KiKR2pJYar6vU70Tuul2fQGWfe36l9m8MLATyAJyvXNXw6c5gecplM5mAg494YRs"
         "FStMedRoYcE41xr8dO3920pa5AHsT71yGu8RtqkvqjrNsvG5fmtHeQfTiI/PJX+5"
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/ietf/3072",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIDDAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS"
         "yv//////////AgECAoIBgH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6"
         "AQXfUx2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9j"
         "eiYhdNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+C"
         "zG0kGw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwC"
         "eLo2BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuM"
         "HMqkvnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeF"
         "RXU4q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQy"
         "bDsBOZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohH"
         "JcFokFSdaWV//////////w=="
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/3072",
         "-----BEGIN DH PARAMETERS-----"
         "MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS"
         "yv//////////AgEF"
         "-----END DH PARAMETERS-----");

   config.set("dl", "modp/ietf/4096",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIEDAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQICggIA"
         "f//////////kh+1RELRhGmJjMUXAbg5olIEnBEUz5joBBd9THYnNkSilBDzHGgJu"
         "98qM2eadIY2YFYU2+S+KG6fwmra2qOEi8kLauzEvP2N6JiF00xv2tYX/rlt6A1v2"
         "9xw1/a1Ez9LXT5IIviWP8ySUMyj2ci2e4QA+XFCx34LMbSQbDirpzTSLH9R+kmev"
         "wbKuke5R1ssOMXmrEEKpXc9qlIO4S0s2s4YapyVeTAJ4ujYEZQwQvhlILyMXG2cd"
         "8c87lgwHQwHNk8HRdgPRR9rirvg3pilk7xXl+0qsC4wcyqS+dUq1corpEwxMfQKI"
         "CrlHLUVVYhbWmYuGgig9GdQqkNXvjl0ydn3Cgixt94VFdTirroMGPtnLh8LTcPJj"
         "1frXRm2EmeuPRkpwJRKwzudx6RMNaXc1+Jf9A2zFBDJsOwE5n2Q1MikPlYwLvZAG"
         "XfCLq70wrrY7hMRgXWyjcQRxJ9A6ctWYoe2t/nB+iEclwWiQVJCEAI05HglTw/Nr"
         "xDjNCF7dLZNM4ZOMNXpxHg1KNBpbCoXtEsH05RVqJnRt3eFtgm9HfJdHfgoP32VT"
         "FD4so6c14C7M2Usn0Ehh0RGd0MMorfP2j7CUuGdxa9fcDe67ELgkDmgDSJPq2C1U"
         "ydp1TEbH7uDDf9vuSFNgR6b6GuSaAxjM//////////8="
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/4096",
         "-----BEGIN DH PARAMETERS-----"
         "MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQU="
         "-----END DH PARAMETERS-----");

   config.set("dl", "modp/ietf/6144",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIGDAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG"
         "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU"
         "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId"
         "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha"
         "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/"
         "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA"
         "JP//////////AoIDAH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXf"
         "Ux2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYh"
         "dNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+CzG0k"
         "Gw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwCeLo2"
         "BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuMHMqk"
         "vnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeFRXU4"
         "q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQybDsB"
         "OZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohHJcFo"
         "kFSQhACNOR4JU8Pza8Q4zQhe3S2TTOGTjDV6cR4NSjQaWwqF7RLB9OUVaiZ0bd3h"
         "bYJvR3yXR34KD99lUxQ+LKOnNeAuzNlLJ9BIYdERndDDKK3z9o+wlLhncWvX3A3u"
         "uxC4JA5oA0iT6tgtVMnadUxGx+7gw3/b7khTYEem+hrkmgFCSRth/VppPjgTYOpu"
         "WTATI29kuo87Ht0b3vx/ygNWzymHcu2cF6CYANdYNSn2yBPsGIvLk9hDLUSMbR9t"
         "9efNinaiZzZdZ2pdje2/iiPzZhKlmZAoqJXr16E33HoAm8ZpX6zB5QDjJcl2eBl1"
         "Cui5DoH6QWvnNzp/e2qvOBejTAZBWtQgGMgFjk8s8+S/32P0eZHUvT8bZkRfB46i"
         "2/+sLWKl6gPZFaCqVWZHtr9fpHDsCmYvaQfAG/BTy4r3eU3xlANQ6sXb4u07eqhV"
         "HsUP3/h1jOZY0Ynqrm0rZPYXeUsZHD/0a7ceAjQCH0ezH6Qwdwlflq2Fujprc0p8"
         "jzbmIBJ//////////wIBAg=="
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/6144",
         "-----BEGIN DH PARAMETERS-----"
         "MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG"
         "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU"
         "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId"
         "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha"
         "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/"
         "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA"
         "JP//////////AgEF"
         "-----END DH PARAMETERS-----");

   config.set("dl", "modp/ietf/8192",
         "-----BEGIN X942 DH PARAMETERS-----"
         "MIIIDAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG"
         "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU"
         "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId"
         "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha"
         "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/"
         "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R"
         "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk"
         "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw"
         "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4"
         "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i"
         "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU"
         "38gfVuiAuW5xYMmA3Zjt09///////////wKCBAB//////////+SH7VEQtGEaYmMx"
         "RcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Ca"
         "trao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQz"
         "KPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qU"
         "g7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH2uKu"
         "+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVViFtaZi4aCKD0Z1CqQ"
         "1e+OXTJ2fcKCLG33hUV1OKuugwY+2cuHwtNw8mPV+tdGbYSZ649GSnAlErDO53Hp"
         "Ew1pdzX4l/0DbMUEMmw7ATmfZDUyKQ+VjAu9kAZd8IurvTCutjuExGBdbKNxBHEn"
         "0Dpy1Zih7a3+cH6IRyXBaJBUkIQAjTkeCVPD82vEOM0IXt0tk0zhk4w1enEeDUo0"
         "GlsKhe0SwfTlFWomdG3d4W2Cb0d8l0d+Cg/fZVMUPiyjpzXgLszZSyfQSGHREZ3Q"
         "wyit8/aPsJS4Z3Fr19wN7rsQuCQOaANIk+rYLVTJ2nVMRsfu4MN/2+5IU2BHpvoa"
         "5JoBQkkbYf1aaT44E2DqblkwEyNvZLqPOx7dG978f8oDVs8ph3LtnBegmADXWDUp"
         "9sgT7BiLy5PYQy1EjG0fbfXnzYp2omc2XWdqXY3tv4oj82YSpZmQKKiV69ehN9x6"
         "AJvGaV+sweUA4yXJdngZdQrouQ6B+kFr5zc6f3tqrzgXo0wGQVrUIBjIBY5PLPPk"
         "v99j9HmR1L0/G2ZEXweOotv/rC1ipeoD2RWgqlVmR7a/X6Rw7ApmL2kHwBvwU8uK"
         "93lN8ZQDUOrF2+LtO3qoVR7FD9/4dYzmWNGJ6q5tK2T2F3lLGRw/9Gu3HgI0Ah9H"
         "sx+kMHcJX5athbo6a3NKfI823wisulHJN4l/cvIcO75bVJlvxmxfYmg53JjdHeQZ"
         "W0bO6YA6D9PfxX4j9pK7e0m10hIzHVWxzi1yerQaEdo6FfjkvBHHi2XxzrKW8f7c"
         "X35CRWyRERcCUgG+A4n1q9QNEfhjmjn+MjZ1GDWl5eRDF8HC7v1Opb/RYEP0PLQZ"
         "gfat7p0DFZ562dE8UzaVCfwfonwW75iHcDpVtRsiy/RM0BKu4LJ5jmKEI0KO/NWk"
         "DK72v1DY6ohev3Omuf15teGPZ9E0GsgjenXDz8kgBKHFpA42a8RNABdq9xwV5IyG"
         "034BNyPKrHIjqzv01U8YKHE7K0pv5A+rdEBctziwZMBuzHbp7///////////AgEC"
         "-----END X942 DH PARAMETERS-----");

   config.set("dl", "modp/srp/8192",
         "-----BEGIN DH PARAMETERS-----"
         "MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb"
         "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft"
         "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT"
         "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh"
         "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq"
         "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM"
         "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq"
         "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI"
         "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O"
         "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI"
         "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG"
         "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU"
         "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId"
         "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha"
         "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/"
         "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R"
         "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk"
         "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw"
         "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4"
         "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i"
         "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU"
         "38gfVuiAuW5xYMmA3Zjt09///////////wIBEw=="
         "-----END DH PARAMETERS-----");

   config.set("dl", "dsa/jce/512",
         "-----BEGIN DSA PARAMETERS-----"
         "MIGdAkEA/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQT"
         "xeEu0ImbzRMqzVDZkVG9xD7nN1kuFwIVAJYu3cw2nLqOuyYO5rahJtk0bjjFAkEA"
         "3gtU76vylwh+5iPVylWIxkgo70/eT/uuHs0gBndrBbEbgeo83pvDlkwWh8UyW/Q9"
         "fM76DQqGvl3/3dDRFD3NdQ=="
         "-----END DSA PARAMETERS-----");

   config.set("dl", "dsa/jce/768",
         "-----BEGIN DSA PARAMETERS-----"
         "MIHdAmEA6eZCWZ01XzfJf/01ZxILjiXJzUPpJ7OpZw++xdiQFBki0sOzrSSACTeZ"
         "hp0ehGqrSfqwrSbSzmoiIZ1HC859d31KIfvpwnC1f2BwAvPO+Dk2lM9F7jaIwRqM"
         "VqsSej2vAhUAnNvYTJ8awvOND4D0KrlS5zOL9RECYQDe7p717RUWzn5pXmcrjO5F"
         "5s17NuDmOF+JS6hhY/bz5sbU6KgRRtQBfe/dccvZD6Akdlm4i3zByJT0gmn9Txqs"
         "CjBTjf9rP8ds+xMcnnlltYhYqwpDtVczWRKoqlR/lWg="
         "-----END DSA PARAMETERS-----");

   config.set("dl", "dsa/jce/1024",
         "-----BEGIN DSA PARAMETERS-----"
         "MIIBHgKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9"
         "jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX"
         "58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8V"
         "IwvMspK5gqLrhAvwWBz1AoGARpYDUS4wJ4zTlHWV2yLuyYJqYyKtyXNE9B10DDJX"
         "JMj577qn1NgD/4xgnc0QDrxb38+tfGpCX66nhuogUOvpg1HqH9of3yTWlHqmuaoj"
         "dmlTgC9NfUqOy6BtGXaKJJH/sW0O+cQ6mbX3FnL/bwoktETQc20E04oaEyLa9s3Y"
         "jJ0="
         "-----END DSA PARAMETERS-----");

   config.set("dl", "dsa/botan/2048",
         "-----BEGIN DSA PARAMETERS-----"
         "MIICLAKCAQEAkcSKT9+898Aq6V59oSYSK13Shk9Vm4fo50oobVL1m9HeaN/WRdDg"
         "DGDAgAMYkZgDdO61lKUyv9Z7mgnqxLhmOgeRDmjzlGX7cEDSXfE5MuusQ0elMOy6"
         "YchU+biA08DDZgCAWHxFVm2t4mvVo5S+CTtMDyS1r/747GxbPlf7iQJam8FnaZMh"
         "MeFtPJTvyrGNDfBhIDzFPmEDvHLVWUv9QMplOA9EqahR3LB1SV/AM6ilgHGhvXj+"
         "BS9mVVZI60txnSr+i0iA+NrW8VgYuhePiSdMhwvpuW6wjEbEAEDMLv4d+xsYaN0x"
         "nePDSjKmOrbrEiQgmkGWgMx5AtFyjU354QIhAIzX1FD4bwrZTu5M5GmodW0evRBY"
         "JBlD6v+ws1RYXpJNAoIBAA2fXgdhtNvRgz1qsalhoJlsXyIwP3LYTBQPZ8Qx2Uq1"
         "cVvqgaDJjTnOS8941rnryJXTT+idlAkdWEhhXvFfXobxHZb2yWniA936WDVkIKSc"
         "tES1lbkBqTPP4HZ7WU8YoHt/kd7NukRriJkPePL/kfL+fNQ/0uRtGOraH3u2YCxh"
         "f27zpLKE8v2boQo2BC3o+oeiyjZZf+yBFXoUheRAQd8CgwERy4gLvm7UlIFIhvll"
         "zcMTX1zPE4Nyi/ZbgG+WksCxDWxMCcdabKO0ATyxarLBBfa+I66pAA6rIXiYX5cs"
         "mAV+HIbkTnIYaI6krg82NtzKdFydzU5q/7Z8y8E9YTE="
         "-----END DSA PARAMETERS-----");

   config.set("dl", "dsa/botan/3072",
         "-----BEGIN DSA PARAMETERS-----"
         "MIIDLAKCAYEA5LUIgHWWY1heFCRgyi2d/xMviuTIQN2jomZoiRJP5WOLhOiim3rz"
         "+hIJvmv8S1By7Tsrc4e68/hX9HioAijvNgC3az3Pth0g00RlslBtLK+H3259wM6R"
         "vS0Wekb2rcwxxTHk+cervbkq3fNbCoBsZikqX14X6WTdCZkDczrEKKs12A6m9oW/"
         "uovkBo5UGK5eytno/wc94rY+Tn6tNciptwtb1Hz7iNNztm83kxk5sKtxvVWVgJCG"
         "2gFVM30YWg5Ps2pRmxtiArhZHmACRJzxzTpmOE9tIHOxzXO+ypO68eGmEX0COPIi"
         "rh7X/tGFqJDn9n+rj+uXU8wTSlGD3+h64llfe1wtn7tCJJ/dWVE+HTOWs+sv2GaE"
         "8oWoRI/nV6ApiBxAdguU75Gb35dAw4OJWZ7FGm6btRmo4GhJHpzgovz+PLYNZs8N"
         "+tIKjsaEBIaEphREV1vRck1zUrRKdgB3s71r04XOWwpyUMwL92jagpI4Buuc+7E4"
         "hDcxthggjHWbAiEAs+vTZOxp74zzuvZDt1c0sWM5suSeXN4bWcHp+0DuDFsCggGA"
         "K+0h7vg5ZKIwrom7px2ffDnFL8gim047x+WUTTKdoQ8BDqyee69sAJ/E6ylgcj4r"
         "Vt9GY+TDrIAOkljeL3ZJ0gZ4KJP4Ze/KSY0u7zAHTqXop6smJxKk2UovOwuaku5A"
         "D7OKPMWaXcfkNtXABLIuNQKDgbUck0B+sy1K4P1Cy0XhLQ7O6KJiOO3iCCp7FSIR"
         "PGbO+NdFxs88uUX4TS9N4W1Epx3hmCcOE/A1U8iLjTI60LlIob8hA6lJl5tu0W+1"
         "88lT2Vt8jojKZ9z1pjb7nKOdkkIV96iE7Wx+48ltjZcVQnl0t8Q1EoLhPTdz99KL"
         "RS8QiSoTx1hzKN6kgntrNpsqjcFyrcWD9R8qZZjFSD5bxGewL5HQWcQC0Y4sJoD3"
         "dqoG9JKAoscsF8xC1bbnQMXEsas8UcLtCSviotiwU65Xc9FCXtKwjwbi3VBZLfGk"
         "eMFVkc39EVZP+I/zi3IdQjkv2kcyEtz9jS2IqXagCv/m//tDCjWeZMorNRyiQSOU"
         "-----END DSA PARAMETERS-----");

   config.set("ec", "secp112r1",
         "-----BEGIN EC PARAMETERS-----"
         "MHQCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDtt8Kr9i415mgHa+"
         "rSCIBA5lnvi6BDkW7t6JEXArIgQdBAlIcjmZWl7na1X5wvCYqJzlr4ckwKI+Dg/3"
         "dQACDwDbfCq/YuNedijfrGVhxQIBAQ=="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp112r2",
         "-----BEGIN EC PARAMETERS-----"
         "MHMCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDmEnwkwF84oKqvZc"
         "DvAsBA5R3vGBXbXtdPzDTIXXCQQdBEujCrXokrThZJ3QkoZDrc1G9YguN0fe826V"
         "bpcCDjbfCq/YuNdZfKEFINBLAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp128r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGAAgEBMBwGByqGSM49AQECEQD////9////////////////MCQEEP////3/////"
         "//////////wEEOh1ecEQefQ92CSZPCzuXtMEIQQWH/dSi4mbLQwoYHylLFuGz1rI"
         "OVuv6xPALaKS3e16gwIRAP////4AAAAAdaMNG5A4oRUCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp128r2",
         "-----BEGIN EC PARAMETERS-----"
         "MH8CAQEwHAYHKoZIzj0BAQIRAP////3///////////////8wJAQQ1gMZmNGzu/6/"
         "Wcybv/mu4QQQXu78o4DQKRncLGVYu22KXQQhBHtqpdheVymD5vsyp83rwUAntpFq"
         "iU067nEG/oBfw0tEAhA/////f////74AJHIGE7WjAgEE"
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp160k1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBQAAAAA"
         "AAAAAAAAAAAAAAAAAAAAAAQUAAAAAAAAAAAAAAAAAAAAAAAAAAcEKQQ7TDgs43qh"
         "kqQBnnYwNvT13U1+u5OM+TUxj9zta8KChlMXM8PwPE/uAhUBAAAAAAAAAAAAAbj6"
         "Ft+rmsoWtrMCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp160r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGYAgEBMCAGByqGSM49AQECFQD/////////////////////f////zAsBBT/////"
         "////////////////f////AQUHJe+/FS9eotlrPifgdTUrcVl+kUEKQRKlrVojvVz"
         "KEZkaYlow4u5E8v8giOmKFUxaJR9WdzJEgQjUTd6xfsyAhUBAAAAAAAAAAAAAfTI"
         "+Seu08p1IlcCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp160r2",
         "-----BEGIN EC PARAMETERS-----"
         "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBT/////"
         "///////////////+//+scAQUtOE00/tZ64urVydJBGZNWvUDiLoEKQRS3LA0KToR"
         "fh9P8Rsw9xmdMUTObf6v/vLjMfKW4HH6DfmYLP6n1D8uAhUBAAAAAAAAAAAAADUe"
         "54aoGPOhoWsCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp192k1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGwAgEBMCQGByqGSM49AQECGQD//////////////////////////v//7jcwNAQY"
         "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
         "AAMEMQTbT/EOwFfpriawfQKAt/Q0HaXRsergbH2bLy9tnFYop4RBY9AVvoY0QIKq"
         "iNleL50CGQD///////////////4m8vwXD2lGanTe/Y0CAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp192r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY"
         "/////////////////////v/////////8BBhkIQUZ5ZyA5w+n6atyJDBJ/rje7MFG"
         "ubEEMQQYjagOsDCQ9ny/IOtDoYgA9P8K/YL/EBIHGSuV/8jaeGMQEe1rJM3Vc/l3"
         "oR55SBECGQD///////////////+Z3vg2FGvJsbTSKDECAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp224k1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHIAgEBMCgGByqGSM49AQECHQD///////////////////////////////7//+Vt"
         "MDwEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHAAAAAAAAAAAAAAAAAAA"
         "AAAAAAAAAAAAAAAAAAUEOQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ZQ62t6Rcfgif"
         "7X+6NEKCyvvW9+MZ98CwvVniykvbVW1hpQIdAQAAAAAAAAAAAAAAAAAB3OjS7GGE"
         "yvCpcXafsfcCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp224r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHIAgEBMCgGByqGSM49AQECHQD/////////////////////AAAAAAAAAAAAAAAB"
         "MDwEHP////////////////////7///////////////4EHLQFCoUMBLOr9UEyVlBE"
         "sLfXv9i6Jws5QyNV/7QEOQS3Dgy9a7S/fzITkLlKA8HTVsIRIjQygNYRXB0hvTdj"
         "iLX3I/tMIt/mzUN1oFoHR2RE1YGZhQB+NAIdAP//////////////////FqLguPA+"
         "E90pRVxcKj0CAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp256k1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHgAgEBMCwGByqGSM49AQECIQD////////////////////////////////////+"
         "///8LzBEBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQgAAAAAAAA"
         "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEQQR5vmZ++dy7rFWgYpXOhwsHApv8"
         "2y3OKNlZ8oFbFvgXmEg62ncmo8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA"
         "/////////////////////rqu3OavSKA7v9JejNA2QUECAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp256r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////"
         "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6"
         "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDydwN9"
         "gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA"
         "/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp384r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBQAIBATA8BgcqhkjOPQEBAjEA////////////////////////////////////"
         "//////7/////AAAAAAAAAAD/////MGQEMP//////////////////////////////"
         "///////////+/////wAAAAAAAAAA/////AQwszEvp+I+5+SYjgVr4/gtGRgdnG7+"
         "gUESAxQIj1ATh1rGVjmNii7RnSqFyO3T7CrvBGEEqofKIr6LBTeOscce8yCtdG4d"
         "O2KLp5uYWfdB4IJUKjhVAvJdv1UpbDpUXjhydgq3NhfeSpYmLG9dnpi/kpLcKfj0"
         "Hb0omhR86doxE7XwuMAKYLHOHX6BnXpDHXyQ6g5fAjEA////////////////////"
         "////////////x2NNgfQ3Ld9YGg2ySLCneuzsGWrMxSlzAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "secp521r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////"
         "//////////////////////////////////////////////////8wgYgEQgH/////"
         "////////////////////////////////////////////////////////////////"
         "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ"
         "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e"
         "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5"
         "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm"
         "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////"
         "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "1.3.6.1.4.1.8301.3.1.2.9.0.38",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////"
         "//////////////////////////////////////////////////8wgYgEQgH/////"
         "////////////////////////////////////////////////////////////////"
         "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ"
         "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e"
         "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5"
         "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm"
         "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////"
         "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool160r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGYAgEBMCAGByqGSM49AQECFQDpXkpfc3BZ3GDfx62Vs9gTlRViDzAsBBQ0Dnvi"
         "ooDrdOK+YbradF2X6PfDAAQUHliahZVCNBITT6otveyVyNhnXlgEKQS+1a8W6j9q"
         "T2KTjEYx61r3vbzbwxZny0d6Go7DOPlHQWacl2MW2mMhAhUA6V5KX3NwWdxg31mR"
         "1FApQJ5g/AkCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool192r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIGwAgEBMCQGByqGSM49AQECGQDDAvQdkyo2zaejRjCT0Y23j85HbeGoYpcwNAQY"
         "apEXQHax4OGcOcAx/oaFwcrgQOXGmijvBBhGmijvfCjMo9xyHQRPRJa8yn70FG+/"
         "JckEMQTAoGR+qrakh1OwM8VssPCQCi9cSFM3X9YUtpCGar1buItfSCjBSQAC5nc/"
         "ovopm48CGQDDAvQdkyo2zaejRi+enpFrW+jxAprErMECAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool224r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHIAgEBMCgGByqGSM49AQECHQDXwTSqJkNmhioYMCV10deHsJ8HV5faifV+yMD/"
         "MDwEHGil5iypzmwcKZgDpsFTC1FOGCrYsAQqWcrSn0MEHCWA9jzP5EE4hwcTsakj"
         "aeM+ITXSZtuzcjhsQAsEOQQNkCmtLH5c9DQII7KofcaMnkzjF0webv3uEsB9WKpW"
         "93LAcm8kxrieTs2sJDVLnpnKo/bTdhQCzQIdANfBNKomQ2aGKhgwJXXQ+5jRFrxL"
         "bd68o6Wnk58CAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool256r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHgAgEBMCwGByqGSM49AQECIQCp+1fboe6pvD5mCpCdg41ybjv2I9UmICggE0gd"
         "H25TdzBEBCB9Wgl1/CwwV+72dTBBev/n+4BVwSbcXGzpSktE8zC12QQgJtxcbOlK"
         "S0TzMLXZu9d8v5WEFilc9+HOa8zcGP+MB7YEQQSL0q65y35XyyxLSC/8gbevud4n"
         "4eO9I8I6RFO9ms4yYlR++DXD2sT9l/hGGhRhHcnCd0UTLe2OVFwdVMcvBGmXAiEA"
         "qftX26Huqbw+ZgqQnYONcYw5eqO1Yab3kB4OgpdIVqcCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool320r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBEAIBATA0BgcqhkjOPQEBAikA015HIDa8T7fhPHhe0gHgZfmPz6b29A3vT5K5"
         "7HiT7Cj81BKx8bMuJzBUBCg+4wtWj7qw+IPM69RtPzu4oqc1E/XredpmGQ6whf+p"
         "9JLzdal9hg60BChSCIOUnf28QtOtGYZAaIpv4T9BNJVUtJrMMdzNiEU5gW9etKyP"
         "sfGmBFEEQ71+mvtT2LhSibzEjuW/5vIBN9EKCH6254ceKhClmccQr40NOeIGERT9"
         "0FVF7BzIq0CTJH93J14HQ//tEXGC6qnHeHeqrGrH01JF0WkujuECKQDTXkcgNrxP"
         "t+E8eF7SAeBl+Y/PpbaPEqMtSC7H7oZY6YaRVVtExZMRAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool384r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBQAIBATA8BgcqhkjOPQEBAjEAjLkegqM4bSgPXW9+UOZB3xUvcQntVFa0ErHa"
         "GX+3ESOs06cpkB0acYdHABMxB+xTMGQEMHvDgsY9jBUMPHIICs4Fr6DCvqKOT7In"
         "hxORZe+6kfkPiqWBSlA61OsEqMfdIs4oJgQwBKjH3SLOKCaLObVUFvBEfC+3feEH"
         "3NKmLogOpT7rYtV8tDkCldvJlDq3hpb6UEwRBGEEHRxk8GjPRf+ipjqBt8E/a4hH"
         "o+d+8U/j23/K/gy9EOjoJuA0NtZGqu+HsuJH1K8eir4ddSD5wqRcseuOlc/VUmK3"
         "Cyn+7Fhk4ZwFT/mRKSgORkYhd5GBEUKCA0EmPFMVAjEAjLkegqM4bSgPXW9+UOZB"
         "3xUvcQntVFazHxZubKwEJafPOrava3/DEDuIMgLpBGVlAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "brainpool512r1",
         "-----BEGIN EC PARAMETERS-----"
         "MIIBogIBATBMBgcqhkjOPQEBAkEAqt2duNvpxIs/1OauM8n8B8swjbOzydIO1mOc"
         "ynAzCHF9TZsAm8ZoQq7NoSrmo4DmKIH/Ly2CxoUoqmBWWDpI8zCBhARAeDCjMYtg"
         "O4niMnFFrCNMxZTL3Y09+RYQqDRByuqYY7wt7V1aqCU6oQou8cmLmsi1fxEXpyvy"
         "x7nnwaxNd/yUygRAPfkWEKg0QcrqmGO8Le1dWqglOqEKLvHJi5rItX8RF6cr8se5"
         "58GsTXf8lMrcCD5nmEBQt1665d0oCb1jgBb3IwSBgQSBruS92C7ZZFohMi6cTGqT"
         "he2fcLXZFsG0O2Lu9NAJjv87H3ji0NSNUNFoe5O5fV98bVBHQGpeaIs1Igm8ufgi"
         "fd44XVZjMuzA6r+pz3gi/fIJ9wAkpXsaoADFW4gfgRGy3N5JSl9IXlvKS9iKJ2Ou"
         "0corL6jwVAZ4zR4POtgIkgJBAKrdnbjb6cSLP9TmrjPJ/AfLMI2zs8nSDtZjnMpw"
         "MwhwVT5cQUypJhlBhmEZf6wQRx2x04EIXdrdtYeWgpypAGkCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "x962_p192v2",
         "-----BEGIN EC PARAMETERS-----"
         "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY"
         "/////////////////////v/////////8BBjMItbfuVxrJeScDWNkpOWYDDk6ohZo"
         "2VMEMQTuorrn4Ul4QvLed2nP6cmJwHKtaW9IA0pldNEdabbsemcruCoIPfLysIR9"
         "6XCy3hUCGQD///////////////5fsack3IBBhkjY3TECAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "x962_p192v3",
         "-----BEGIN EC PARAMETERS-----"
         "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY"
         "/////////////////////v/////////8BBgiEj3COVoFyqdCPa7MyUdgp9RiJWvV"
         "aRYEMQR9KXeBAMZaHaF4NxZYjc4ri0rujiKPGJY4qQ8iY3M3M0tJ3LZqbcj5l4rK"
         "dkipQ7ACGQD///////////////96YtAxyD9ClPZA7BMCAQE="
         "-----END EC PARAMETERS-----");

   config.set("ec", "x962_p239v1",
         "-----BEGIN EC PARAMETERS-----"
         "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////"
         "/zBABB5///////////////9///////+AAAAAAAB///////wEHmsBbDvc8YlB0NZU"
         "khR1ynGp2y+yfR03eWGFwpQsCgQ9BA/6ljzcqIFszDO4ZCvt+QXD01hXPT8n+707"
         "PLmqr33r6OTpCl2ubkBUylMLoEZUs2gYziJrOfzLewLxrgIef///////////////"
         "f///nl6an12QcfvRUiaIkJ0LAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "x962_p239v2",
         "-----BEGIN EC PARAMETERS-----"
         "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////"
         "/zBABB5///////////////9///////+AAAAAAAB///////wEHmF/q2gyV2y7/tUN"
         "mfAknD/uWLlLoAOMeuhMjIMvLAQ9BDivCdmHJ3BRIMkhu16eJilqPNzy81dXoOr9"
         "h7gw51sBJeTb6g7HIG2g/AHZsIEyn7VV3m70YCN9/4vkugIef///////////////"
         "gAAAz6foWUN31BTAOCG8WCBjAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "x962_p239v3",
         "-----BEGIN EC PARAMETERS-----"
         "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////"
         "/zBABB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZUsfTL"
         "A9anUKMMJQEC1JiHF9m6FattPgQ9BGdoro4Yu5LPzwBclJqixtlIU9DmYLv4VLHJ"
         "UF/pWhYH5omPOQwGvB1VK60ibztvz+SLboGEma8Y4+1s8wIef///////////////"
         "f///l13rQbOmBXw8QyFGUmVRAgEB"
         "-----END EC PARAMETERS-----");

   config.set("ec", "gost_256A",
         "-----BEGIN EC PARAMETERS-----"
         "MIHgAgEBMCwGByqGSM49AQECIQD/////////////////////////////////////"
         "///9lzBEBCD////////////////////////////////////////9lAQgAAAAAAAA"
         "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYEQQQAAAAAAAAAAAAAAAAAAAAAAAAA"
         "AAAAAAAAAAAAAAAAAY2R5HHgmJzaJ99QWkU/K3Y1KU8t3yPjsSKsyZyenx4UAiEA"
         "/////////////////////2xhEHCZWtEARYQbCbdhuJMCAQE="
         "-----END EC PARAMETERS-----");
   }
}

/*
* Set the default policy
*/
void Library_State::load_default_config()
   {
   set_default_aliases(*this);
   set_default_oids(*this);
   set_default_dl_groups(*this);
   }

}
/*
* SCAN Name Abstraction
* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

namespace Botan {

namespace {

std::string make_arg(
   const std::vector<std::pair<size_t, std::string> >& name, size_t start)
   {
   std::string output = name[start].second;
   size_t level = name[start].first;

   size_t paren_depth = 0;

   for(size_t i = start + 1; i != name.size(); ++i)
      {
      if(name[i].first <= name[start].first)
         break;

      if(name[i].first > level)
         {
         output += '(' + name[i].second;
         ++paren_depth;
         }
      else if(name[i].first < level)
         {
         output += ")," + name[i].second;
         --paren_depth;
         }
      else
         {
         if(output[output.size() - 1] != '(')
            output += ",";
         output += name[i].second;
         }

      level = name[i].first;
      }

   for(size_t i = 0; i != paren_depth; ++i)
      output += ')';

   return output;
   }

std::pair<size_t, std::string>
deref_aliases(const std::pair<size_t, std::string>& in)
   {
   return std::make_pair(in.first,
                         global_state().deref_alias(in.second));
   }

}

SCAN_Name::SCAN_Name(std::string algo_spec)
   {
   orig_algo_spec = algo_spec;

   std::vector<std::pair<size_t, std::string> > name;
   size_t level = 0;
   std::pair<size_t, std::string> accum = std::make_pair(level, "");

   std::string decoding_error = "Bad SCAN name '" + algo_spec + "': ";

   algo_spec = global_state().deref_alias(algo_spec);

   for(size_t i = 0; i != algo_spec.size(); ++i)
      {
      char c = algo_spec[i];

      if(c == '/' || c == ',' || c == '(' || c == ')')
         {
         if(c == '(')
            ++level;
         else if(c == ')')
            {
            if(level == 0)
               throw Decoding_Error(decoding_error + "Mismatched parens");
            --level;
            }

         if(c == '/' && level > 0)
            accum.second.push_back(c);
         else
            {
            if(accum.second != "")
               name.push_back(deref_aliases(accum));
            accum = std::make_pair(level, "");
            }
         }
      else
         accum.second.push_back(c);
      }

   if(accum.second != "")
      name.push_back(deref_aliases(accum));

   if(level != 0)
      throw Decoding_Error(decoding_error + "Missing close paren");

   if(name.size() == 0)
      throw Decoding_Error(decoding_error + "Empty name");

   alg_name = name[0].second;

   bool in_modes = false;

   for(size_t i = 1; i != name.size(); ++i)
      {
      if(name[i].first == 0)
         {
         mode_info.push_back(make_arg(name, i));
         in_modes = true;
         }
      else if(name[i].first == 1 && !in_modes)
         args.push_back(make_arg(name, i));
      }
   }

std::string SCAN_Name::algo_name_and_args() const
   {
   std::string out;

   out = algo_name();

   if(arg_count())
      {
      out += '(';
      for(size_t i = 0; i != arg_count(); ++i)
         {
         out += arg(i);
         if(i != arg_count() - 1)
            out += ',';
         }
      out += ')';

      }

   return out;
   }

std::string SCAN_Name::arg(size_t i) const
   {
   if(i >= arg_count())
      throw std::range_error("SCAN_Name::argument - i out of range");
   return args[i];
   }

std::string SCAN_Name::arg(size_t i, const std::string& def_value) const
   {
   if(i >= arg_count())
      return def_value;
   return args[i];
   }

size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const
   {
   if(i >= arg_count())
      return def_value;
   return to_u32bit(args[i]);
   }

}
/*
* CBC-MAC
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Update an CBC-MAC Calculation
*/
void CBC_MAC::add_data(const byte input[], size_t length)
   {
   size_t xored = std::min(output_length() - position, length);
   xor_buf(&state[position], input, xored);
   position += xored;

   if(position < output_length())
      return;

   e->encrypt(state);
   input += xored;
   length -= xored;
   while(length >= output_length())
      {
      xor_buf(state, input, output_length());
      e->encrypt(state);
      input += output_length();
      length -= output_length();
      }

   xor_buf(state, input, length);
   position = length;
   }

/*
* Finalize an CBC-MAC Calculation
*/
void CBC_MAC::final_result(byte mac[])
   {
   if(position)
      e->encrypt(state);

   copy_mem(mac, &state[0], state.size());
   zeroise(state);
   position = 0;
   }

/*
* CBC-MAC Key Schedule
*/
void CBC_MAC::key_schedule(const byte key[], size_t length)
   {
   e->set_key(key, length);
   }

/*
* Clear memory of sensitive data
*/
void CBC_MAC::clear()
   {
   e->clear();
   zeroise(state);
   position = 0;
   }

/*
* Return the name of this type
*/
std::string CBC_MAC::name() const
   {
   return "CBC-MAC(" + e->name() + ")";
   }

/*
* Return a clone of this object
*/
MessageAuthenticationCode* CBC_MAC::clone() const
   {
   return new CBC_MAC(e->clone());
   }

/*
* CBC-MAC Constructor
*/
CBC_MAC::CBC_MAC(BlockCipher* e_in) :
   e(e_in), state(e->block_size())
   {
   position = 0;
   }

/*
* CBC-MAC Destructor
*/
CBC_MAC::~CBC_MAC()
   {
   delete e;
   }

}
/*
* CMAC
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Perform CMAC's multiplication in GF(2^n)
*/
SecureVector<byte> CMAC::poly_double(const MemoryRegion<byte>& in,
                                     byte polynomial)
   {
   const byte poly_xor = (in[0] & 0x80) ? polynomial : 0;

   SecureVector<byte> out = in;

   byte carry = 0;
   for(size_t i = out.size(); i != 0; --i)
      {
      byte temp = out[i-1];
      out[i-1] = (temp << 1) | carry;
      carry = (temp >> 7);
      }

   out[out.size()-1] ^= poly_xor;

   return out;
   }

/*
* Update an CMAC Calculation
*/
void CMAC::add_data(const byte input[], size_t length)
   {
   buffer.copy(position, input, length);
   if(position + length > output_length())
      {
      xor_buf(state, buffer, output_length());
      e->encrypt(state);
      input += (output_length() - position);
      length -= (output_length() - position);
      while(length > output_length())
         {
         xor_buf(state, input, output_length());
         e->encrypt(state);
         input += output_length();
         length -= output_length();
         }
      buffer.copy(input, length);
      position = 0;
      }
   position += length;
   }

/*
* Finalize an CMAC Calculation
*/
void CMAC::final_result(byte mac[])
   {
   xor_buf(state, buffer, position);

   if(position == output_length())
      {
      xor_buf(state, B, output_length());
      }
   else
      {
      state[position] ^= 0x80;
      xor_buf(state, P, output_length());
      }

   e->encrypt(state);

   for(size_t i = 0; i != output_length(); ++i)
      mac[i] = state[i];

   zeroise(state);
   zeroise(buffer);
   position = 0;
   }

/*
* CMAC Key Schedule
*/
void CMAC::key_schedule(const byte key[], size_t length)
   {
   clear();
   e->set_key(key, length);
   e->encrypt(B);
   B = poly_double(B, polynomial);
   P = poly_double(B, polynomial);
   }

/*
* Clear memory of sensitive data
*/
void CMAC::clear()
   {
   e->clear();
   zeroise(state);
   zeroise(buffer);
   zeroise(B);
   zeroise(P);
   position = 0;
   }

/*
* Return the name of this type
*/
std::string CMAC::name() const
   {
   return "CMAC(" + e->name() + ")";
   }

/*
* Return a clone of this object
*/
MessageAuthenticationCode* CMAC::clone() const
   {
   return new CMAC(e->clone());
   }

/*
* CMAC Constructor
*/
CMAC::CMAC(BlockCipher* e_in) : e(e_in)
   {
   if(e->block_size() == 16)
      polynomial = 0x87;
   else if(e->block_size() == 8)
      polynomial = 0x1B;
   else
      throw Invalid_Argument("CMAC cannot use the cipher " + e->name());

   state.resize(output_length());
   buffer.resize(output_length());
   B.resize(output_length());
   P.resize(output_length());
   position = 0;
   }

/*
* CMAC Destructor
*/
CMAC::~CMAC()
   {
   delete e;
   }

}
/*
* HMAC
* (C) 1999-2007 Jack Lloyd
*     2007 Yves Jerschow
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Update a HMAC Calculation
*/
void HMAC::add_data(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Finalize a HMAC Calculation
*/
void HMAC::final_result(byte mac[])
   {
   hash->final(mac);
   hash->update(o_key);
   hash->update(mac, output_length());
   hash->final(mac);
   hash->update(i_key);
   }

/*
* HMAC Key Schedule
*/
void HMAC::key_schedule(const byte key[], size_t length)
   {
   hash->clear();
   std::fill(i_key.begin(), i_key.end(), 0x36);
   std::fill(o_key.begin(), o_key.end(), 0x5C);

   if(length > hash->hash_block_size())
      {
      SecureVector<byte> hmac_key = hash->process(key, length);
      xor_buf(i_key, hmac_key, hmac_key.size());
      xor_buf(o_key, hmac_key, hmac_key.size());
      }
   else
      {
      xor_buf(i_key, key, length);
      xor_buf(o_key, key, length);
      }

   hash->update(i_key);
   }

/*
* Clear memory of sensitive data
*/
void HMAC::clear()
   {
   hash->clear();
   zeroise(i_key);
   zeroise(o_key);
   }

/*
* Return the name of this type
*/
std::string HMAC::name() const
   {
   return "HMAC(" + hash->name() + ")";
   }

/*
* Return a clone of this object
*/
MessageAuthenticationCode* HMAC::clone() const
   {
   return new HMAC(hash->clone());
   }

/*
* HMAC Constructor
*/
HMAC::HMAC(HashFunction* hash_in) : hash(hash_in)
   {
   if(hash->hash_block_size() == 0)
      throw Invalid_Argument("HMAC cannot be used with " + hash->name());

   i_key.resize(hash->hash_block_size());
   o_key.resize(hash->hash_block_size());
   }

}
/*
* Message Authentication Code base class
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Default (deterministic) MAC verification operation
*/
bool MessageAuthenticationCode::verify_mac(const byte mac[], size_t length)
   {
   SecureVector<byte> our_mac = final();

   if(our_mac.size() != length)
      return false;

   return same_mem(&our_mac[0], &mac[0], length);
   }

}
/*
* SSL3-MAC
* (C) 1999-2004 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Update a SSL3-MAC Calculation
*/
void SSL3_MAC::add_data(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Finalize a SSL3-MAC Calculation
*/
void SSL3_MAC::final_result(byte mac[])
   {
   hash->final(mac);
   hash->update(o_key);
   hash->update(mac, output_length());
   hash->final(mac);
   hash->update(i_key);
   }

/*
* SSL3-MAC Key Schedule
*/
void SSL3_MAC::key_schedule(const byte key[], size_t length)
   {
   hash->clear();
   std::fill(i_key.begin(), i_key.end(), 0x36);
   std::fill(o_key.begin(), o_key.end(), 0x5C);

   i_key.copy(key, length);
   o_key.copy(key, length);
   hash->update(i_key);
   }

/*
* Clear memory of sensitive data
*/
void SSL3_MAC::clear()
   {
   hash->clear();
   zeroise(i_key);
   zeroise(o_key);
   }

/*
* Return the name of this type
*/
std::string SSL3_MAC::name() const
   {
   return "SSL3-MAC(" + hash->name() + ")";
   }

/*
* Return a clone of this object
*/
MessageAuthenticationCode* SSL3_MAC::clone() const
   {
   return new SSL3_MAC(hash->clone());
   }

/*
* SSL3-MAC Constructor
*/
SSL3_MAC::SSL3_MAC(HashFunction* hash_in) : hash(hash_in)
   {
   if(hash->hash_block_size() == 0)
      throw Invalid_Argument("SSL3-MAC cannot be used with " + hash->name());

   // Quirk to deal with specification bug
   const size_t INNER_HASH_LENGTH =
      (hash->name() == "SHA-160") ? 60 : hash->hash_block_size();

   i_key.resize(INNER_HASH_LENGTH);
   o_key.resize(INNER_HASH_LENGTH);
   }

}
/*
* ANSI X9.19 MAC
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Update an ANSI X9.19 MAC Calculation
*/
void ANSI_X919_MAC::add_data(const byte input[], size_t length)
   {
   size_t xored = std::min(8 - position, length);
   xor_buf(&state[position], input, xored);
   position += xored;

   if(position < 8) return;

   e->encrypt(state);
   input += xored;
   length -= xored;
   while(length >= 8)
      {
      xor_buf(state, input, 8);
      e->encrypt(state);
      input += 8;
      length -= 8;
      }

   xor_buf(state, input, length);
   position = length;
   }

/*
* Finalize an ANSI X9.19 MAC Calculation
*/
void ANSI_X919_MAC::final_result(byte mac[])
   {
   if(position)
      e->encrypt(state);
   d->decrypt(state, mac);
   e->encrypt(mac);
   zeroise(state);
   position = 0;
   }

/*
* ANSI X9.19 MAC Key Schedule
*/
void ANSI_X919_MAC::key_schedule(const byte key[], size_t length)
   {
   e->set_key(key, 8);
   if(length == 8) d->set_key(key, 8);
   else            d->set_key(key + 8, 8);
   }

/*
* Clear memory of sensitive data
*/
void ANSI_X919_MAC::clear()
   {
   e->clear();
   d->clear();
   zeroise(state);
   position = 0;
   }

std::string ANSI_X919_MAC::name() const
   {
   return "X9.19-MAC";
   }

MessageAuthenticationCode* ANSI_X919_MAC::clone() const
   {
   return new ANSI_X919_MAC(e->clone());
   }

/*
* ANSI X9.19 MAC Constructor
*/
ANSI_X919_MAC::ANSI_X919_MAC(BlockCipher* e_in) :
   e(e_in), d(e->clone()), state(e->block_size()), position(0)
   {
   if(e->name() != "DES")
      throw Invalid_Argument("ANSI X9.19 MAC only supports DES");
   }

/*
* ANSI X9.19 MAC Destructor
le*/
ANSI_X919_MAC::~ANSI_X919_MAC()
   {
   delete e;
   delete d;
   }

}
/*
* BigInt Encoding/Decoding
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Encode a BigInt
*/
void BigInt::encode(byte output[], const BigInt& n, Base base)
   {
   if(base == Binary)
      n.binary_encode(output);
   else if(base == Hexadecimal)
      {
      SecureVector<byte> binary(n.encoded_size(Binary));
      n.binary_encode(&binary[0]);

      hex_encode(reinterpret_cast<char*>(output),
                 &binary[0], binary.size());
      }
   else if(base == Octal)
      {
      BigInt copy = n;
      const size_t output_size = n.encoded_size(Octal);
      for(size_t j = 0; j != output_size; ++j)
         {
         output[output_size - 1 - j] =
            Charset::digit2char(static_cast<byte>(copy % 8));

         copy /= 8;
         }
      }
   else if(base == Decimal)
      {
      BigInt copy = n;
      BigInt remainder;
      copy.set_sign(Positive);
      const size_t output_size = n.encoded_size(Decimal);
      for(size_t j = 0; j != output_size; ++j)
         {
         divide(copy, 10, copy, remainder);
         output[output_size - 1 - j] =
            Charset::digit2char(static_cast<byte>(remainder.word_at(0)));
         if(copy.is_zero())
            break;
         }
      }
   else
      throw Invalid_Argument("Unknown BigInt encoding method");
   }

/*
* Encode a BigInt
*/
SecureVector<byte> BigInt::encode(const BigInt& n, Base base)
   {
   SecureVector<byte> output(n.encoded_size(base));
   encode(&output[0], n, base);
   if(base != Binary)
      for(size_t j = 0; j != output.size(); ++j)
         if(output[j] == 0)
            output[j] = '0';
   return output;
   }

/*
* Encode a BigInt, with leading 0s if needed
*/
SecureVector<byte> BigInt::encode_1363(const BigInt& n, size_t bytes)
   {
   const size_t n_bytes = n.bytes();
   if(n_bytes > bytes)
      throw Encoding_Error("encode_1363: n is too large to encode properly");

   const size_t leading_0s = bytes - n_bytes;

   SecureVector<byte> output(bytes);
   encode(&output[leading_0s], n, Binary);
   return output;
   }

/*
* Decode a BigInt
*/
BigInt BigInt::decode(const MemoryRegion<byte>& buf, Base base)
   {
   return BigInt::decode(&buf[0], buf.size(), base);
   }

/*
* Decode a BigInt
*/
BigInt BigInt::decode(const byte buf[], size_t length, Base base)
   {
   BigInt r;
   if(base == Binary)
      r.binary_decode(buf, length);
   else if(base == Hexadecimal)
      {
      SecureVector<byte> binary;
      const char *cbuf = reinterpret_cast<const char *>(buf);

      if(length % 2)
         {
         // Handle lack of leading 0
         const char buf0_with_leading_0[2] = { '0', cbuf[0] };
         binary = hex_decode(buf0_with_leading_0, 2);

         binary += hex_decode(&cbuf[1], length - 1, false);
         }
      else
         binary = hex_decode(cbuf, length, false);

      r.binary_decode(&binary[0], binary.size());
      }
   else if(base == Decimal || base == Octal)
      {
      const size_t RADIX = ((base == Decimal) ? 10 : 8);
      for(size_t j = 0; j != length; ++j)
         {
         if(Charset::is_space(buf[j]))
            continue;

         if(!Charset::is_digit(buf[j]))
            throw Invalid_Argument("BigInt::decode: "
                                   "Invalid character in decimal input");

         byte x = Charset::char2digit(buf[j]);
         if(x >= RADIX)
            {
            if(RADIX == 10)
               throw Invalid_Argument("BigInt: Invalid decimal string");
            else
               throw Invalid_Argument("BigInt: Invalid octal string");
            }

         r *= RADIX;
         r += x;
         }
      }
   else
      throw Invalid_Argument("Unknown BigInt decoding method");
   return r;
   }

}
/*
* BigInt Input/Output
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <iostream>

namespace Botan {

/*
* Write the BigInt into a stream
*/
std::ostream& operator<<(std::ostream& stream, const BigInt& n)
   {
   BigInt::Base base = BigInt::Decimal;
   if(stream.flags() & std::ios::hex)
      base = BigInt::Hexadecimal;
   else if(stream.flags() & std::ios::oct)
      base = BigInt::Octal;

   if(n == 0)
      stream.write("0", 1);
   else
      {
      if(n < 0)
         stream.write("-", 1);
      SecureVector<byte> buffer = BigInt::encode(n, base);
      size_t skip = 0;
      while(buffer[skip] == '0' && skip < buffer.size())
         ++skip;
      stream.write(reinterpret_cast<const char*>(&buffer[0]) + skip,
                   buffer.size() - skip);
      }
   if(!stream.good())
      throw Stream_IO_Error("BigInt output operator has failed");
   return stream;
   }

/*
* Read the BigInt from a stream
*/
std::istream& operator>>(std::istream& stream, BigInt& n)
   {
   std::string str;
   std::getline(stream, str);
   if(stream.bad() || (stream.fail() && !stream.eof()))
      throw Stream_IO_Error("BigInt input operator has failed");
   n = BigInt(str);
   return stream;
   }

}
/*
* BigInt Assignment Operators
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Addition Operator
*/
BigInt& BigInt::operator+=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(sign() == y.sign())
      bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
   else
      {
      s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         SecureVector<word> z(reg_size - 1);
         bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw);
         copy_mem(&reg[0], &z[0], z.size());
         set_sign(y.sign());
         }
      else if(relative_size == 0)
         {
         zeroise(reg);
         set_sign(Positive);
         }
      else if(relative_size > 0)
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Subtraction Operator
*/
BigInt& BigInt::operator-=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(relative_size < 0)
      {
      if(sign() == y.sign())
         bigint_sub2_rev(get_reg(), y.data(), y_sw);
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);

      set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(sign() == y.sign())
         {
         clear();
         set_sign(Positive);
         }
      else
         bigint_shl1(get_reg(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(sign() == y.sign())
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Multiplication Operator
*/
BigInt& BigInt::operator*=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();
   set_sign((sign() == y.sign()) ? Positive : Negative);

   if(x_sw == 0 || y_sw == 0)
      {
      clear();
      set_sign(Positive);
      }
   else if(x_sw == 1 && y_sw)
      {
      grow_to(y_sw + 2);
      bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0));
      }
   else if(y_sw == 1 && x_sw)
      {
      grow_to(x_sw + 2);
      bigint_linmul2(get_reg(), x_sw, y.word_at(0));
      }
   else
      {
      grow_to(size() + y.size());

      SecureVector<word> z(data(), x_sw);
      SecureVector<word> workspace(size());

      bigint_mul(get_reg(), size(), workspace,
                 z, z.size(), x_sw,
                 y.data(), y.size(), y_sw);
      }

   return (*this);
   }

/*
* Division Operator
*/
BigInt& BigInt::operator/=(const BigInt& y)
   {
   if(y.sig_words() == 1 && power_of_2(y.word_at(0)))
      (*this) >>= (y.bits() - 1);
   else
      (*this) = (*this) / y;
   return (*this);
   }

/*
* Modulo Operator
*/
BigInt& BigInt::operator%=(const BigInt& mod)
   {
   return (*this = (*this) % mod);
   }

/*
* Modulo Operator
*/
word BigInt::operator%=(word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();
   if(power_of_2(mod))
       {
       word result = (word_at(0) & (mod - 1));
       clear();
       grow_to(2);
       get_reg()[0] = result;
       return result;
       }

   word remainder = 0;

   for(size_t j = sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, word_at(j-1), mod);
   clear();
   grow_to(2);

   if(remainder && sign() == BigInt::Negative)
      get_reg()[0] = mod - remainder;
   else
      get_reg()[0] = remainder;

   set_sign(BigInt::Positive);

   return word_at(0);
   }

/*
* Left Shift Operator
*/
BigInt& BigInt::operator<<=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS,
                   words = sig_words();

      grow_to(words + shift_words + (shift_bits ? 1 : 0));
      bigint_shl1(get_reg(), words, shift_words, shift_bits);
      }

   return (*this);
   }

/*
* Right Shift Operator
*/
BigInt& BigInt::operator>>=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS;

      bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits);

      if(is_zero())
         set_sign(Positive);
      }

   return (*this);
   }

}
/*
* BigInt Binary Operators
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Addition Operator
*/
BigInt operator+(const BigInt& x, const BigInt& y)
   {
   const size_t x_sw = x.sig_words(), y_sw = y.sig_words();

   BigInt z(x.sign(), std::max(x_sw, y_sw) + 1);

   if((x.sign() == y.sign()))
      bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw);
   else
      {
      s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw);
         z.set_sign(y.sign());
         }
      else if(relative_size == 0)
         z.set_sign(BigInt::Positive);
      else if(relative_size > 0)
         bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw);
      }

   return z;
   }

/*
* Subtraction Operator
*/
BigInt operator-(const BigInt& x, const BigInt& y)
   {
   const size_t x_sw = x.sig_words(), y_sw = y.sig_words();

   s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw);

   BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1);

   if(relative_size < 0)
      {
      if(x.sign() == y.sign())
         bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw);
      else
         bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw);
      z.set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(x.sign() != y.sign())
         bigint_shl2(z.get_reg(), x.data(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(x.sign() == y.sign())
         bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw);
      else
         bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw);
      z.set_sign(x.sign());
      }
   return z;
   }

/*
* Multiplication Operator
*/
BigInt operator*(const BigInt& x, const BigInt& y)
   {
   const size_t x_sw = x.sig_words(), y_sw = y.sig_words();

   BigInt z(BigInt::Positive, x.size() + y.size());

   if(x_sw == 1 && y_sw)
      bigint_linmul3(z.get_reg(), y.data(), y_sw, x.word_at(0));
   else if(y_sw == 1 && x_sw)
      bigint_linmul3(z.get_reg(), x.data(), x_sw, y.word_at(0));
   else if(x_sw && y_sw)
      {
      SecureVector<word> workspace(z.size());
      bigint_mul(z.get_reg(), z.size(), workspace,
                 x.data(), x.size(), x_sw,
                 y.data(), y.size(), y_sw);
      }

   if(x_sw && y_sw && x.sign() != y.sign())
      z.flip_sign();
   return z;
   }

/*
* Division Operator
*/
BigInt operator/(const BigInt& x, const BigInt& y)
   {
   BigInt q, r;
   divide(x, y, q, r);
   return q;
   }

/*
* Modulo Operator
*/
BigInt operator%(const BigInt& n, const BigInt& mod)
   {
   if(mod.is_zero())
      throw BigInt::DivideByZero();
   if(mod.is_negative())
      throw Invalid_Argument("BigInt::operator%: modulus must be > 0");
   if(n.is_positive() && mod.is_positive() && n < mod)
      return n;

   BigInt q, r;
   divide(n, mod, q, r);
   return r;
   }

/*
* Modulo Operator
*/
word operator%(const BigInt& n, word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();
   if(power_of_2(mod))
      return (n.word_at(0) & (mod - 1));

   word remainder = 0;

   for(size_t j = n.sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, n.word_at(j-1), mod);

   if(remainder && n.sign() == BigInt::Negative)
      return mod - remainder;
   return remainder;
   }

/*
* Left Shift Operator
*/
BigInt operator<<(const BigInt& x, size_t shift)
   {
   if(shift == 0)
      return x;

   const size_t shift_words = shift / MP_WORD_BITS,
                shift_bits  = shift % MP_WORD_BITS;

   const size_t x_sw = x.sig_words();

   BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0));
   bigint_shl2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits);
   return y;
   }

/*
* Right Shift Operator
*/
BigInt operator>>(const BigInt& x, size_t shift)
   {
   if(shift == 0)
      return x;
   if(x.bits() <= shift)
      return 0;

   const size_t shift_words = shift / MP_WORD_BITS,
                shift_bits  = shift % MP_WORD_BITS,
                x_sw = x.sig_words();

   BigInt y(x.sign(), x_sw - shift_words);
   bigint_shr2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits);
   return y;
   }

}
/*
* BigInt Random Generation
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Construct a BigInt of a specific form
*/
BigInt::BigInt(NumberType type, size_t bits)
   {
   set_sign(Positive);

   if(type == Power2)
      set_bit(bits);
   else
      throw Invalid_Argument("BigInt(NumberType): Unknown type");
   }

/*
* Randomize this number
*/
void BigInt::randomize(RandomNumberGenerator& rng,
                       size_t bitsize)
   {
   set_sign(Positive);

   if(bitsize == 0)
      clear();
   else
      {
      SecureVector<byte> array = rng.random_vec((bitsize + 7) / 8);

      if(bitsize % 8)
         array[0] &= 0xFF >> (8 - (bitsize % 8));
      array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0);
      binary_decode(&array[0], array.size());
      }
   }

/*
* Generate a random integer within given range
*/
BigInt BigInt::random_integer(RandomNumberGenerator& rng,
                              const BigInt& min, const BigInt& max)
   {
   BigInt range = max - min;

   if(range <= 0)
      throw Invalid_Argument("random_integer: invalid min/max values");

   return (min + (BigInt(rng, range.bits() + 2) % range));
   }

}
/*
* BigInt Base
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Construct a BigInt from a regular number
*/
BigInt::BigInt(u64bit n)
   {
   set_sign(Positive);

   if(n == 0)
      return;

   const size_t limbs_needed = sizeof(u64bit) / sizeof(word);

   reg.resize(4*limbs_needed);
   for(size_t i = 0; i != limbs_needed; ++i)
      reg[i] = ((n >> (i*MP_WORD_BITS)) & MP_WORD_MASK);
   }

/*
* Construct a BigInt of the specified size
*/
BigInt::BigInt(Sign s, size_t size)
   {
   reg.resize(round_up<size_t>(size, 8));
   signedness = s;
   }

/*
* Construct a BigInt from a "raw" BigInt
*/
BigInt::BigInt(const BigInt& b)
   {
   const size_t b_words = b.sig_words();

   if(b_words)
      {
      reg.resize(round_up<size_t>(b_words, 8));
      reg.copy(b.data(), b_words);
      set_sign(b.sign());
      }
   else
      {
      reg.resize(2);
      set_sign(Positive);
      }
   }

/*
* Construct a BigInt from a string
*/
BigInt::BigInt(const std::string& str)
   {
   Base base = Decimal;
   size_t markers = 0;
   bool negative = false;
   if(str.length() > 0 && str[0] == '-') { markers += 1; negative = true; }

   if(str.length() > markers + 2 && str[markers    ] == '0' &&
                                    str[markers + 1] == 'x')
      { markers += 2; base = Hexadecimal; }
   else if(str.length() > markers + 1 && str[markers] == '0')
      { markers += 1; base = Octal; }

   *this = decode(reinterpret_cast<const byte*>(str.data()) + markers,
                  str.length() - markers, base);

   if(negative) set_sign(Negative);
   else         set_sign(Positive);
   }

/*
* Construct a BigInt from an encoded BigInt
*/
BigInt::BigInt(const byte input[], size_t length, Base base)
   {
   set_sign(Positive);
   *this = decode(input, length, base);
   }

/*
* Construct a BigInt from an encoded BigInt
*/
BigInt::BigInt(RandomNumberGenerator& rng, size_t bits)
   {
   set_sign(Positive);
   randomize(rng, bits);
   }

/*
* Swap this BigInt with another
*/
void BigInt::swap(BigInt& other)
   {
   reg.swap(other.reg);
   std::swap(signedness, other.signedness);
   }

/*
* Grow the internal storage
*/
void BigInt::grow_reg(size_t n)
   {
   reg.resize(round_up<size_t>(size() + n, 8));
   }

/*
* Grow the internal storage
*/
void BigInt::grow_to(size_t n)
   {
   if(n > size())
      reg.resize(round_up<size_t>(n, 8));
   }

/*
* Comparison Function
*/
s32bit BigInt::cmp(const BigInt& n, bool check_signs) const
   {
   if(check_signs)
      {
      if(n.is_positive() && this->is_negative()) return -1;
      if(n.is_negative() && this->is_positive()) return 1;
      if(n.is_negative() && this->is_negative())
         return (-bigint_cmp(data(), sig_words(), n.data(), n.sig_words()));
      }
   return bigint_cmp(data(), sig_words(), n.data(), n.sig_words());
   }

/*
* Return byte n of this number
*/
byte BigInt::byte_at(size_t n) const
   {
   const size_t WORD_BYTES = sizeof(word);
   size_t word_num = n / WORD_BYTES, byte_num = n % WORD_BYTES;
   if(word_num >= size())
      return 0;
   else
      return get_byte(WORD_BYTES - byte_num - 1, reg[word_num]);
   }

/*
* Return bit n of this number
*/
bool BigInt::get_bit(size_t n) const
   {
   return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1);
   }

/*
* Return bits {offset...offset+length}
*/
u32bit BigInt::get_substring(size_t offset, size_t length) const
   {
   if(length > 32)
      throw Invalid_Argument("BigInt::get_substring: Substring size too big");

   u64bit piece = 0;
   for(size_t i = 0; i != 8; ++i)
      {
      const byte part = byte_at((offset / 8) + (7-i));
      piece = (piece << 8) | part;
      }

   const u64bit mask = (static_cast<u64bit>(1) << length) - 1;
   const size_t shift = (offset % 8);

   return static_cast<u32bit>((piece >> shift) & mask);
   }

/*
* Convert this number to a u32bit, if possible
*/
u32bit BigInt::to_u32bit() const
   {
   if(is_negative())
      throw Encoding_Error("BigInt::to_u32bit: Number is negative");
   if(bits() >= 32)
      throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert");

   u32bit out = 0;
   for(u32bit j = 0; j != 4; ++j)
      out = (out << 8) | byte_at(3-j);
   return out;
   }

/*
* Set bit number n
*/
void BigInt::set_bit(size_t n)
   {
   const size_t which = n / MP_WORD_BITS;
   const word mask = static_cast<word>(1) << (n % MP_WORD_BITS);
   if(which >= size()) grow_to(which + 1);
   reg[which] |= mask;
   }

/*
* Clear bit number n
*/
void BigInt::clear_bit(size_t n)
   {
   const size_t which = n / MP_WORD_BITS;
   const word mask = static_cast<word>(1) << (n % MP_WORD_BITS);
   if(which < size())
      reg[which] &= ~mask;
   }

/*
* Clear all but the lowest n bits
*/
void BigInt::mask_bits(size_t n)
   {
   if(n == 0) { clear(); return; }
   if(n >= bits()) return;

   const size_t top_word = n / MP_WORD_BITS;
   const word mask = (static_cast<word>(1) << (n % MP_WORD_BITS)) - 1;

   if(top_word < size())
      for(size_t i = top_word + 1; i != size(); ++i)
         reg[i] = 0;

   reg[top_word] &= mask;
   }

/*
* Count how many bytes are being used
*/
size_t BigInt::bytes() const
   {
   return (bits() + 7) / 8;
   }

/*
* Count how many bits are being used
*/
size_t BigInt::bits() const
   {
   const size_t words = sig_words();

   if(words == 0)
      return 0;

   size_t full_words = words - 1, top_bits = MP_WORD_BITS;
   word top_word = word_at(full_words), mask = MP_WORD_TOP_BIT;

   while(top_bits && ((top_word & mask) == 0))
      { mask >>= 1; top_bits--; }

   return (full_words * MP_WORD_BITS + top_bits);
   }

/*
* Calcluate the size in a certain base
*/
size_t BigInt::encoded_size(Base base) const
   {
   static const double LOG_2_BASE_10 = 0.30102999566;

   if(base == Binary)
      return bytes();
   else if(base == Hexadecimal)
      return 2*bytes();
   else if(base == Octal)
      return ((bits() + 2) / 3);
   else if(base == Decimal)
      return static_cast<size_t>((bits() * LOG_2_BASE_10) + 1);
   else
      throw Invalid_Argument("Unknown base for BigInt encoding");
   }

/*
* Set the sign
*/
void BigInt::set_sign(Sign s)
   {
   if(is_zero())
      signedness = Positive;
   else
      signedness = s;
   }

/*
* Reverse the value of the sign flag
*/
void BigInt::flip_sign()
   {
   set_sign(reverse_sign());
   }

/*
* Return the opposite value of the current sign
*/
BigInt::Sign BigInt::reverse_sign() const
   {
   if(sign() == Positive)
      return Negative;
   return Positive;
   }

/*
* Return the negation of this number
*/
BigInt BigInt::operator-() const
   {
   BigInt x = (*this);
   x.flip_sign();
   return x;
   }

/*
* Return the absolute value of this number
*/
BigInt BigInt::abs() const
   {
   BigInt x = (*this);
   x.set_sign(Positive);
   return x;
   }

/*
* Encode this number into bytes
*/
void BigInt::binary_encode(byte output[]) const
   {
   const size_t sig_bytes = bytes();
   for(size_t i = 0; i != sig_bytes; ++i)
      output[sig_bytes-i-1] = byte_at(i);
   }

/*
* Set this number to the value in buf
*/
void BigInt::binary_decode(const byte buf[], size_t length)
   {
   const size_t WORD_BYTES = sizeof(word);

   clear();
   reg.resize(round_up<size_t>((length / WORD_BYTES) + 1, 8));

   for(size_t i = 0; i != length / WORD_BYTES; ++i)
      {
      const size_t top = length - WORD_BYTES*i;
      for(size_t j = WORD_BYTES; j > 0; --j)
         reg[i] = (reg[i] << 8) | buf[top - j];
      }

   for(size_t i = 0; i != length % WORD_BYTES; ++i)
      reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[i];
   }

/*
* Set this number to the value in buf
*/
void BigInt::binary_decode(const MemoryRegion<byte>& buf)
   {
   binary_decode(buf, buf.size());
   }

}
/*
* Division Algorithm
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Handle signed operands, if necessary
*/
void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r)
   {
   if(x.sign() == BigInt::Negative)
      {
      q.flip_sign();
      if(r.is_nonzero()) { --q; r = y.abs() - r; }
      }
   if(y.sign() == BigInt::Negative)
      q.flip_sign();
   }

}

/*
* Solve x = q * y + r
*/
void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r)
   {
   if(y_arg.is_zero())
      throw BigInt::DivideByZero();

   BigInt y = y_arg;
   const size_t y_words = y.sig_words();

   r = x;
   q = 0;

   r.set_sign(BigInt::Positive);
   y.set_sign(BigInt::Positive);

   s32bit compare = r.cmp(y);

   if(compare == 0)
      {
      q = 1;
      r = 0;
      }
   else if(compare > 0)
      {
      size_t shifts = 0;
      word y_top = y[y.sig_words()-1];
      while(y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; }
      y <<= shifts;
      r <<= shifts;

      const size_t n = r.sig_words() - 1, t = y_words - 1;

      if(n < t)
         throw Internal_Error("BigInt division word sizes");

      q.get_reg().resize(n - t + 1);
      if(n <= t)
         {
         while(r > y) { r -= y; ++q; }
         r >>= shifts;
         sign_fixup(x, y_arg, q, r);
         return;
         }

      BigInt temp = y << (MP_WORD_BITS * (n-t));

      while(r >= temp) { r -= temp; ++q[n-t]; }

      for(size_t j = n; j != t; --j)
         {
         const word x_j0  = r.word_at(j);
         const word x_j1 = r.word_at(j-1);
         const word y_t  = y.word_at(t);

         if(x_j0 == y_t)
            q[j-t-1] = MP_WORD_MAX;
         else
            q[j-t-1] = bigint_divop(x_j0, x_j1, y_t);

         while(bigint_divcore(q[j-t-1], y_t, y.word_at(t-1),
                              x_j0, x_j1, r.word_at(j-2)))
            --q[j-t-1];

         r -= (q[j-t-1] * y) << (MP_WORD_BITS * (j-t-1));
         if(r.is_negative())
            {
            r += y << (MP_WORD_BITS * (j-t-1));
            --q[j-t-1];
            }
         }
      r >>= shifts;
      }

   sign_fixup(x, y_arg, q, r);
   }

}
/*
* Point arithmetic on elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
*     2008-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

PointGFp::PointGFp(const CurveGFp& curve) :
   curve(curve), ws(2 * (curve.get_p_words() + 2))
   {
   coord_x = 0;
   coord_y = monty_mult(1, curve.get_r2());
   coord_z = 0;
   }

PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
   curve(curve), ws(2 * (curve.get_p_words() + 2))
   {
   coord_x = monty_mult(x, curve.get_r2());
   coord_y = monty_mult(y, curve.get_r2());
   coord_z = monty_mult(1, curve.get_r2());
   }

// Montgomery multiplication
void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const
   {
   //assert(&z != &x && &z != &y);

   if(x.is_zero() || y.is_zero())
      {
      z = 0;
      return;
      }

   const BigInt& p = curve.get_p();
   const size_t p_size = curve.get_p_words();
   const word p_dash = curve.get_p_dash();

   SecureVector<word>& z_reg = z.get_reg();
   z_reg.resize(2*p_size+1);
   zeroise(z_reg);

   bigint_monty_mul(&z_reg[0], z_reg.size(),
                    x.data(), x.size(), x.sig_words(),
                    y.data(), y.size(), y.sig_words(),
                    p.data(), p_size, p_dash,
                    &ws[0]);
   }

// Montgomery squaring
void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const
   {
   //assert(&z != &x);

   if(x.is_zero())
      {
      z = 0;
      return;
      }

   const BigInt& p = curve.get_p();
   const size_t p_size = curve.get_p_words();
   const word p_dash = curve.get_p_dash();

   SecureVector<word>& z_reg = z.get_reg();
   z_reg.resize(2*p_size+1);
   zeroise(z_reg);

   bigint_monty_sqr(&z_reg[0], z_reg.size(),
                    x.data(), x.size(), x.sig_words(),
                    p.data(), p_size, p_dash,
                    &ws[0]);
   }

// Point addition
void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
   {
   if(is_zero())
      {
      coord_x = rhs.coord_x;
      coord_y = rhs.coord_y;
      coord_z = rhs.coord_z;
      return;
      }
   else if(rhs.is_zero())
      return;

   const BigInt& p = curve.get_p();

   BigInt& rhs_z2 = ws_bn[0];
   BigInt& U1 = ws_bn[1];
   BigInt& S1 = ws_bn[2];

   BigInt& lhs_z2 = ws_bn[3];
   BigInt& U2 = ws_bn[4];
   BigInt& S2 = ws_bn[5];

   BigInt& H = ws_bn[6];
   BigInt& r = ws_bn[7];

   monty_sqr(rhs_z2, rhs.coord_z);
   monty_mult(U1, coord_x, rhs_z2);
   monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2));

   monty_sqr(lhs_z2, coord_z);
   monty_mult(U2, rhs.coord_x, lhs_z2);
   monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2));

   H = U2;
   H -= U1;
   if(H.is_negative())
      H += p;

   r = S2;
   r -= S1;
   if(r.is_negative())
      r += p;

   if(H.is_zero())
      {
      if(r.is_zero())
         {
         mult2(ws_bn);
         return;
         }

      *this = PointGFp(curve); // setting myself to zero
      return;
      }

   monty_sqr(U2, H);

   monty_mult(S2, U2, H);

   U2 = monty_mult(U1, U2);

   monty_sqr(coord_x, r);
   coord_x -= S2;
   coord_x -= (U2 << 1);
   while(coord_x.is_negative())
      coord_x += p;

   U2 -= coord_x;
   if(U2.is_negative())
      U2 += p;

   monty_mult(coord_y, r, U2);
   coord_y -= monty_mult(S1, S2);
   if(coord_y.is_negative())
      coord_y += p;

   monty_mult(coord_z, monty_mult(coord_z, rhs.coord_z), H);
   }

// *this *= 2
void PointGFp::mult2(std::vector<BigInt>& ws_bn)
   {
   if(is_zero())
      return;
   else if(coord_y.is_zero())
      {
      *this = PointGFp(curve); // setting myself to zero
      return;
      }

   const BigInt& p = curve.get_p();

   BigInt& y_2 = ws_bn[0];
   BigInt& S = ws_bn[1];
   BigInt& z4 = ws_bn[2];
   BigInt& a_z4 = ws_bn[3];
   BigInt& M = ws_bn[4];
   BigInt& U = ws_bn[5];
   BigInt& x = ws_bn[6];
   BigInt& y = ws_bn[7];
   BigInt& z = ws_bn[8];

   monty_sqr(y_2, coord_y);

   monty_mult(S, coord_x, y_2);
   S <<= 2; // * 4
   while(S >= p)
      S -= p;

   monty_sqr(z4, monty_sqr(coord_z));
   monty_mult(a_z4, curve.get_a_r(), z4);

   M = 3 * monty_sqr(coord_x);
   M += a_z4;
   while(M >= p)
      M -= p;

   monty_sqr(x, M);
   x -= (S << 1);
   while(x.is_negative())
      x += p;

   monty_sqr(U, y_2);
   U <<= 3;
   while(U >= p)
      U -= p;

   S -= x;
   while(S.is_negative())
      S += p;

   monty_mult(y, M, S);
   y -= U;
   if(y.is_negative())
      y += p;

   monty_mult(z, coord_y, coord_z);
   z <<= 1;
   if(z >= p)
      z -= p;

   coord_x = x;
   coord_y = y;
   coord_z = z;
   }

// arithmetic operators
PointGFp& PointGFp::operator+=(const PointGFp& rhs)
   {
   std::vector<BigInt> ws(9);
   add(rhs, ws);
   return *this;
   }

PointGFp& PointGFp::operator-=(const PointGFp& rhs)
   {
   PointGFp minus_rhs = PointGFp(rhs).negate();

   if(is_zero())
      *this = minus_rhs;
   else
      *this += minus_rhs;

   return *this;
   }

PointGFp& PointGFp::operator*=(const BigInt& scalar)
   {
   *this = scalar * *this;
   return *this;
   }

PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1,
                            const PointGFp& p2, const BigInt& z2)
   {
   const PointGFp p3 = p1 + p2;

   PointGFp H(p1.curve); // create as zero
   size_t bits_left = std::max(z1.bits(), z2.bits());

   std::vector<BigInt> ws(9);

   while(bits_left)
      {
      H.mult2(ws);

      const bool z1_b = z1.get_bit(bits_left - 1);
      const bool z2_b = z2.get_bit(bits_left - 1);

      if(z1_b == true && z2_b == true)
         H.add(p3, ws);
      else if(z1_b)
         H.add(p1, ws);
      else if(z2_b)
         H.add(p2, ws);

      --bits_left;
      }

   if(z1.is_negative() != z2.is_negative())
      H.negate();

   return H;
   }

PointGFp operator*(const BigInt& scalar, const PointGFp& point)
   {
   const CurveGFp& curve = point.get_curve();

   if(scalar.is_zero())
      return PointGFp(curve); // zero point

   std::vector<BigInt> ws(9);

   if(scalar.abs() <= 2) // special cases for small values
      {
      byte value = scalar.abs().byte_at(0);

      PointGFp result = point;

      if(value == 2)
         result.mult2(ws);

      if(scalar.is_negative())
         result.negate();

      return result;
      }

   const size_t scalar_bits = scalar.bits();

#if 0

   PointGFp x1 = PointGFp(curve);
   PointGFp x2 = point;

   size_t bits_left = scalar_bits;

   // Montgomery Ladder
   while(bits_left)
      {
      const bool bit_set = scalar.get_bit(bits_left - 1);

      if(bit_set)
         {
         x1.add(x2, ws);
         x2.mult2(ws);
         }
      else
         {
         x2.add(x1, ws);
         x1.mult2(ws);
         }

      --bits_left;
      }

   if(scalar.is_negative())
      x1.negate();

   return x1;

#else
   const size_t window_size = 4;

   std::vector<PointGFp> Ps(1 << window_size);
   Ps[0] = PointGFp(curve);
   Ps[1] = point;

   for(size_t i = 2; i != Ps.size(); ++i)
      {
      Ps[i] = Ps[i-1];
      Ps[i].add(point, ws);
      }

   PointGFp H(curve); // create as zero
   size_t bits_left = scalar_bits;

   while(bits_left >= window_size)
      {
      for(size_t i = 0; i != window_size; ++i)
         H.mult2(ws);

      const u32bit nibble = scalar.get_substring(bits_left - window_size,
                                                 window_size);

      H.add(Ps[nibble], ws);

      bits_left -= window_size;
      }

   while(bits_left)
      {
      H.mult2(ws);
      if(scalar.get_bit(bits_left-1))
         H.add(point, ws);

      --bits_left;
      }

   if(scalar.is_negative())
      H.negate();

   return H;
#endif
   }

BigInt PointGFp::get_affine_x() const
   {
   if(is_zero())
      throw Illegal_Transformation("Cannot convert zero point to affine");

   const BigInt& r2 = curve.get_r2();

   BigInt z2 = monty_sqr(coord_z);
   z2 = inverse_mod(z2, curve.get_p());

   z2 = monty_mult(z2, r2);
   return monty_mult(coord_x, z2);
   }

BigInt PointGFp::get_affine_y() const
   {
   if(is_zero())
      throw Illegal_Transformation("Cannot convert zero point to affine");

   const BigInt& r2 = curve.get_r2();

   BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z));
   z3 = inverse_mod(z3, curve.get_p());
   z3 = monty_mult(z3, r2);
   return monty_mult(coord_y, z3);
   }

bool PointGFp::on_the_curve() const
   {
   /*
   Is the point still on the curve?? (If everything is correct, the
   point is always on its curve; then the function will return true.
   If somehow the state is corrupted, which suggests a fault attack
   (or internal computational error), then return false.
   */

   if(is_zero())
      return true;

   BigInt y2 = monty_mult(monty_sqr(coord_y), 1);
   BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x));

   BigInt ax = monty_mult(coord_x, curve.get_a_r());

   const BigInt& b_r = curve.get_b_r();

   BigInt z2 = monty_sqr(coord_z);

   if(coord_z == z2) // Is z equal to 1 (in Montgomery form)?
      {
      if(y2 != monty_mult(x3 + ax + b_r, 1))
         return false;
      }

   BigInt z3 = monty_mult(coord_z, z2);

   BigInt ax_z4 = monty_mult(ax, monty_sqr(z2));

   BigInt b_z6 = monty_mult(b_r, monty_sqr(z3));

   if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1))
      return false;

   return true;
   }

// swaps the states of *this and other, does not throw!
void PointGFp::swap(PointGFp& other)
   {
   curve.swap(other.curve);
   coord_x.swap(other.coord_x);
   coord_y.swap(other.coord_y);
   coord_z.swap(other.coord_z);
   ws.swap(other.ws);
   }

bool PointGFp::operator==(const PointGFp& other) const
   {
   if(get_curve() != other.get_curve())
      return false;

   // If this is zero, only equal if other is also zero
   if(is_zero())
      return other.is_zero();

   return (get_affine_x() == other.get_affine_x() &&
           get_affine_y() == other.get_affine_y());
   }

// encoding and decoding
SecureVector<byte> EC2OSP(const PointGFp& point, byte format)
   {
   if(point.is_zero())
      return SecureVector<byte>(1); // single 0 byte

   const size_t p_bytes = point.get_curve().get_p().bytes();

   BigInt x = point.get_affine_x();
   BigInt y = point.get_affine_y();

   SecureVector<byte> bX = BigInt::encode_1363(x, p_bytes);
   SecureVector<byte> bY = BigInt::encode_1363(y, p_bytes);

   if(format == PointGFp::UNCOMPRESSED)
      {
      SecureVector<byte> result;
      result.push_back(0x04);

      result += bX;
      result += bY;

      return result;
      }
   else if(format == PointGFp::COMPRESSED)
      {
      SecureVector<byte> result;
      result.push_back(0x02 | static_cast<byte>(y.get_bit(0)));

      result += bX;

      return result;
      }
   else if(format == PointGFp::HYBRID)
      {
      SecureVector<byte> result;
      result.push_back(0x06 | static_cast<byte>(y.get_bit(0)));

      result += bX;
      result += bY;

      return result;
      }
   else
      throw Invalid_Argument("illegal point encoding format specification");
   }

namespace {

BigInt decompress_point(bool yMod2,
                        const BigInt& x,
                        const CurveGFp& curve)
   {
   BigInt xpow3 = x * x * x;

   BigInt g = curve.get_a() * x;
   g += xpow3;
   g += curve.get_b();
   g = g % curve.get_p();

   BigInt z = ressol(g, curve.get_p());

   if(z < 0)
      throw Illegal_Point("error during decompression");

   if(z.get_bit(0) != yMod2)
      z = curve.get_p() - z;

   return z;
   }

}

PointGFp OS2ECP(const byte data[], size_t data_len,
                const CurveGFp& curve)
   {
   if(data_len <= 1)
      return PointGFp(curve); // return zero

   const byte pc = data[0];

   BigInt x, y;

   if(pc == 2 || pc == 3)
      {
      //compressed form
      x = BigInt::decode(&data[1], data_len - 1);

      const bool y_mod_2 = ((pc & 0x01) == 1);
      y = decompress_point(y_mod_2, x, curve);
      }
   else if(pc == 4)
      {
      const size_t l = (data_len - 1) / 2;

      // uncompressed form
      x = BigInt::decode(&data[1], l);
      y = BigInt::decode(&data[l+1], l);
      }
   else if(pc == 6 || pc == 7)
      {
      const size_t l = (data_len - 1) / 2;

      // hybrid form
      x = BigInt::decode(&data[1], l);
      y = BigInt::decode(&data[l+1], l);

      const bool y_mod_2 = ((pc & 0x01) == 1);

      if(decompress_point(y_mod_2, x, curve) != y)
         throw Illegal_Point("OS2ECP: Decoding error in hybrid format");
      }
   else
      throw Invalid_Argument("OS2ECP: Unknown format type");

   PointGFp result(curve, x, y);

   if(!result.on_the_curve())
      throw Illegal_Point("OS2ECP: Decoded point was not on the curve");

   return result;
   }

}
/*
* Lowest Level MPI Algorithms
* (C) 1999-2010 Jack Lloyd
*     2006 Luca Piccarreta
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Two Operand Addition, No Carry
*/
word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size)
   {
   word carry = 0;

   const size_t blocks = y_size - (y_size % 8);

   for(size_t i = 0; i != blocks; i += 8)
      carry = word8_add2(x + i, y + i, carry);

   for(size_t i = blocks; i != y_size; ++i)
      x[i] = word_add(x[i], y[i], &carry);

   for(size_t i = y_size; i != x_size; ++i)
      x[i] = word_add(x[i], 0, &carry);

   return carry;
   }

/*
* Three Operand Addition, No Carry
*/
word bigint_add3_nc(word z[], const word x[], size_t x_size,
                              const word y[], size_t y_size)
   {
   if(x_size < y_size)
      { return bigint_add3_nc(z, y, y_size, x, x_size); }

   word carry = 0;

   const size_t blocks = y_size - (y_size % 8);

   for(size_t i = 0; i != blocks; i += 8)
      carry = word8_add3(z + i, x + i, y + i, carry);

   for(size_t i = blocks; i != y_size; ++i)
      z[i] = word_add(x[i], y[i], &carry);

   for(size_t i = y_size; i != x_size; ++i)
      z[i] = word_add(x[i], 0, &carry);

   return carry;
   }

/*
* Two Operand Addition
*/
void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size)
   {
   if(bigint_add2_nc(x, x_size, y, y_size))
      x[x_size] += 1;
   }

/*
* Three Operand Addition
*/
void bigint_add3(word z[], const word x[], size_t x_size,
                           const word y[], size_t y_size)
   {
   z[(x_size > y_size ? x_size : y_size)] +=
      bigint_add3_nc(z, x, x_size, y, y_size);
   }

/*
* Two Operand Subtraction
*/
word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size)
   {
   word borrow = 0;

   const size_t blocks = y_size - (y_size % 8);

   for(size_t i = 0; i != blocks; i += 8)
      borrow = word8_sub2(x + i, y + i, borrow);

   for(size_t i = blocks; i != y_size; ++i)
      x[i] = word_sub(x[i], y[i], &borrow);

   for(size_t i = y_size; i != x_size; ++i)
      x[i] = word_sub(x[i], 0, &borrow);

   return borrow;
   }

/*
* Two Operand Subtraction x = y - x
*/
void bigint_sub2_rev(word x[],  const word y[], size_t y_size)
   {
   word borrow = 0;

   const size_t blocks = y_size - (y_size % 8);

   for(size_t i = 0; i != blocks; i += 8)
      borrow = word8_sub2_rev(x + i, y + i, borrow);

   for(size_t i = blocks; i != y_size; ++i)
      x[i] = word_sub(y[i], x[i], &borrow);

   if(borrow)
      throw Internal_Error("bigint_sub2_rev: x >= y");
   }

/*
* Three Operand Subtraction
*/
word bigint_sub3(word z[], const word x[], size_t x_size,
                           const word y[], size_t y_size)
   {
   word borrow = 0;

   const size_t blocks = y_size - (y_size % 8);

   for(size_t i = 0; i != blocks; i += 8)
      borrow = word8_sub3(z + i, x + i, y + i, borrow);

   for(size_t i = blocks; i != y_size; ++i)
      z[i] = word_sub(x[i], y[i], &borrow);

   for(size_t i = y_size; i != x_size; ++i)
      z[i] = word_sub(x[i], 0, &borrow);

   return borrow;
   }

/*
* Two Operand Linear Multiply
*/
void bigint_linmul2(word x[], size_t x_size, word y)
   {
   const size_t blocks = x_size - (x_size % 8);

   word carry = 0;

   for(size_t i = 0; i != blocks; i += 8)
      carry = word8_linmul2(x + i, y, carry);

   for(size_t i = blocks; i != x_size; ++i)
      x[i] = word_madd2(x[i], y, &carry);

   x[x_size] = carry;
   }

/*
* Three Operand Linear Multiply
*/
void bigint_linmul3(word z[], const word x[], size_t x_size, word y)
   {
   const size_t blocks = x_size - (x_size % 8);

   word carry = 0;

   for(size_t i = 0; i != blocks; i += 8)
      carry = word8_linmul3(z + i, x + i, y, carry);

   for(size_t i = blocks; i != x_size; ++i)
      z[i] = word_madd2(x[i], y, &carry);

   z[x_size] = carry;
   }

}

}
/*
* Comba Multiplication and Squaring
* (C) 1999-2007,2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Comba 4x4 Squaring
*/
void bigint_comba_sqr4(word z[8], const word x[4])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]);
   z[ 1] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]);
   z[ 2] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]);
   z[ 3] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]);
   z[ 4] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]);
   z[ 5] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]);
   z[ 6] = w0;
   z[ 7] = w1;
   }

/*
* Comba 4x4 Multiplication
*/
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]);
   z[ 1] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]);
   z[ 2] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]);
   z[ 3] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]);
   z[ 4] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]);
   z[ 5] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]);
   z[ 6] = w0;
   z[ 7] = w1;
   }

/*
* Comba 6x6 Squaring
*/
void bigint_comba_sqr6(word z[12], const word x[6])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]);
   z[ 1] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]);
   z[ 2] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]);
   z[ 3] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]);
   z[ 4] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]);
   z[ 5] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]);
   z[ 6] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]);
   z[ 7] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]);
   z[ 8] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]);
   z[ 9] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]);
   z[10] = w1;
   z[11] = w2;
   }

/*
* Comba 6x6 Multiplication
*/
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]);
   z[ 1] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]);
   z[ 2] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]);
   z[ 3] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]);
   z[ 4] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]);
   z[ 5] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]);
   z[ 6] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]);
   z[ 7] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]);
   z[ 8] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]);
   z[ 9] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]);
   z[10] = w1;
   z[11] = w2;
   }

/*
* Comba 8x8 Squaring
*/
void bigint_comba_sqr8(word z[16], const word x[8])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]);
   z[ 1] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]);
   z[ 2] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]);
   z[ 3] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]);
   z[ 4] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]);
   z[ 5] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]);
   z[ 6] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]);
   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]);
   z[ 7] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]);
   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]);
   z[ 8] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]);
   word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]);
   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]);
   z[ 9] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]);
   word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]);
   z[10] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]);
   word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]);
   z[11] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]);
   z[12] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]);
   z[13] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]);
   z[14] = w2;
   z[15] = w0;
   }

/*
* Comba 8x8 Multiplication
*/
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]);
   z[ 1] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]);
   z[ 2] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]);
   z[ 3] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]);
   z[ 4] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]);
   z[ 5] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]);
   z[ 6] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]);
   z[ 7] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]);
   z[ 8] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]);
   z[ 9] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]);
   z[10] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]);
   z[11] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]);
   z[12] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]);
   z[13] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]);
   z[14] = w2;
   z[15] = w0;
   }

/*
* Comba 16x16 Squaring
*/
void bigint_comba_sqr16(word z[32], const word x[16])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]);
   z[ 1] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]);
   z[ 2] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]);
   z[ 3] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]);
   z[ 4] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]);
   z[ 5] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]);
   z[ 6] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]);
   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]);
   z[ 7] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]);
   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]);
   z[ 8] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]);
   word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]);
   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]);
   z[ 9] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]);
   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]);
   word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]);
   z[10] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]);
   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]);
   word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]);
   word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]);
   z[11] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]);
   word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]);
   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]);
   word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]);
   z[12] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]);
   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]);
   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]);
   word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]);
   word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]);
   word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]);
   z[13] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]);
   word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]);
   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]);
   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]);
   word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]);
   word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]);
   word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]);
   word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]);
   z[14] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]);
   word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]);
   word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]);
   word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]);
   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]);
   word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]);
   word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]);
   word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]);
   z[15] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]);
   word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]);
   word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]);
   word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]);
   word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]);
   word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]);
   word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]);
   word3_muladd(&w0, &w2, &w1, x[ 8], x[ 8]);
   z[16] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]);
   word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]);
   word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]);
   word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]);
   word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]);
   word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]);
   word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]);
   z[17] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]);
   word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]);
   word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]);
   word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]);
   word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]);
   word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]);
   word3_muladd(&w2, &w1, &w0, x[ 9], x[ 9]);
   z[18] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]);
   word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]);
   word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]);
   word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]);
   word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]);
   word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]);
   z[19] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]);
   word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]);
   word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]);
   word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]);
   word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]);
   word3_muladd(&w1, &w0, &w2, x[10], x[10]);
   z[20] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]);
   word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]);
   word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]);
   word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]);
   word3_muladd_2(&w2, &w1, &w0, x[10], x[11]);
   z[21] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]);
   word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]);
   word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]);
   word3_muladd_2(&w0, &w2, &w1, x[10], x[12]);
   word3_muladd(&w0, &w2, &w1, x[11], x[11]);
   z[22] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]);
   word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]);
   word3_muladd_2(&w1, &w0, &w2, x[10], x[13]);
   word3_muladd_2(&w1, &w0, &w2, x[11], x[12]);
   z[23] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]);
   word3_muladd_2(&w2, &w1, &w0, x[10], x[14]);
   word3_muladd_2(&w2, &w1, &w0, x[11], x[13]);
   word3_muladd(&w2, &w1, &w0, x[12], x[12]);
   z[24] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[10], x[15]);
   word3_muladd_2(&w0, &w2, &w1, x[11], x[14]);
   word3_muladd_2(&w0, &w2, &w1, x[12], x[13]);
   z[25] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[11], x[15]);
   word3_muladd_2(&w1, &w0, &w2, x[12], x[14]);
   word3_muladd(&w1, &w0, &w2, x[13], x[13]);
   z[26] = w2; w2 = 0;

   word3_muladd_2(&w2, &w1, &w0, x[12], x[15]);
   word3_muladd_2(&w2, &w1, &w0, x[13], x[14]);
   z[27] = w0; w0 = 0;

   word3_muladd_2(&w0, &w2, &w1, x[13], x[15]);
   word3_muladd(&w0, &w2, &w1, x[14], x[14]);
   z[28] = w1; w1 = 0;

   word3_muladd_2(&w1, &w0, &w2, x[14], x[15]);
   z[29] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[15], x[15]);
   z[30] = w0;
   z[31] = w1;
   }

/*
* Comba 16x16 Multiplication
*/
void bigint_comba_mul16(word z[32], const word x[16], const word y[16])
   {
   word w2 = 0, w1 = 0, w0 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]);
   z[ 0] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]);
   z[ 1] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]);
   z[ 2] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]);
   z[ 3] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]);
   z[ 4] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]);
   z[ 5] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]);
   z[ 6] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]);
   z[ 7] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]);
   z[ 8] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]);
   z[ 9] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[10]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[10], y[ 0]);
   z[10] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[11]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[10]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[10], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[11], y[ 0]);
   z[11] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[12]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[11]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[10]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[10], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[11], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[12], y[ 0]);
   z[12] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 0], y[13]);
   word3_muladd(&w0, &w2, &w1, x[ 1], y[12]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[11]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[10]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[10], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[11], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[12], y[ 1]);
   word3_muladd(&w0, &w2, &w1, x[13], y[ 0]);
   z[13] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 0], y[14]);
   word3_muladd(&w1, &w0, &w2, x[ 1], y[13]);
   word3_muladd(&w1, &w0, &w2, x[ 2], y[12]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[11]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[10]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[10], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[11], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[12], y[ 2]);
   word3_muladd(&w1, &w0, &w2, x[13], y[ 1]);
   word3_muladd(&w1, &w0, &w2, x[14], y[ 0]);
   z[14] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 0], y[15]);
   word3_muladd(&w2, &w1, &w0, x[ 1], y[14]);
   word3_muladd(&w2, &w1, &w0, x[ 2], y[13]);
   word3_muladd(&w2, &w1, &w0, x[ 3], y[12]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[11]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[10]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]);
   word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[10], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[11], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[12], y[ 3]);
   word3_muladd(&w2, &w1, &w0, x[13], y[ 2]);
   word3_muladd(&w2, &w1, &w0, x[14], y[ 1]);
   word3_muladd(&w2, &w1, &w0, x[15], y[ 0]);
   z[15] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 1], y[15]);
   word3_muladd(&w0, &w2, &w1, x[ 2], y[14]);
   word3_muladd(&w0, &w2, &w1, x[ 3], y[13]);
   word3_muladd(&w0, &w2, &w1, x[ 4], y[12]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[11]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[10]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]);
   word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]);
   word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[10], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[11], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[12], y[ 4]);
   word3_muladd(&w0, &w2, &w1, x[13], y[ 3]);
   word3_muladd(&w0, &w2, &w1, x[14], y[ 2]);
   word3_muladd(&w0, &w2, &w1, x[15], y[ 1]);
   z[16] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 2], y[15]);
   word3_muladd(&w1, &w0, &w2, x[ 3], y[14]);
   word3_muladd(&w1, &w0, &w2, x[ 4], y[13]);
   word3_muladd(&w1, &w0, &w2, x[ 5], y[12]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[11]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[10]);
   word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]);
   word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]);
   word3_muladd(&w1, &w0, &w2, x[10], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[11], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[12], y[ 5]);
   word3_muladd(&w1, &w0, &w2, x[13], y[ 4]);
   word3_muladd(&w1, &w0, &w2, x[14], y[ 3]);
   word3_muladd(&w1, &w0, &w2, x[15], y[ 2]);
   z[17] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 3], y[15]);
   word3_muladd(&w2, &w1, &w0, x[ 4], y[14]);
   word3_muladd(&w2, &w1, &w0, x[ 5], y[13]);
   word3_muladd(&w2, &w1, &w0, x[ 6], y[12]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[11]);
   word3_muladd(&w2, &w1, &w0, x[ 8], y[10]);
   word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]);
   word3_muladd(&w2, &w1, &w0, x[10], y[ 8]);
   word3_muladd(&w2, &w1, &w0, x[11], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[12], y[ 6]);
   word3_muladd(&w2, &w1, &w0, x[13], y[ 5]);
   word3_muladd(&w2, &w1, &w0, x[14], y[ 4]);
   word3_muladd(&w2, &w1, &w0, x[15], y[ 3]);
   z[18] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 4], y[15]);
   word3_muladd(&w0, &w2, &w1, x[ 5], y[14]);
   word3_muladd(&w0, &w2, &w1, x[ 6], y[13]);
   word3_muladd(&w0, &w2, &w1, x[ 7], y[12]);
   word3_muladd(&w0, &w2, &w1, x[ 8], y[11]);
   word3_muladd(&w0, &w2, &w1, x[ 9], y[10]);
   word3_muladd(&w0, &w2, &w1, x[10], y[ 9]);
   word3_muladd(&w0, &w2, &w1, x[11], y[ 8]);
   word3_muladd(&w0, &w2, &w1, x[12], y[ 7]);
   word3_muladd(&w0, &w2, &w1, x[13], y[ 6]);
   word3_muladd(&w0, &w2, &w1, x[14], y[ 5]);
   word3_muladd(&w0, &w2, &w1, x[15], y[ 4]);
   z[19] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 5], y[15]);
   word3_muladd(&w1, &w0, &w2, x[ 6], y[14]);
   word3_muladd(&w1, &w0, &w2, x[ 7], y[13]);
   word3_muladd(&w1, &w0, &w2, x[ 8], y[12]);
   word3_muladd(&w1, &w0, &w2, x[ 9], y[11]);
   word3_muladd(&w1, &w0, &w2, x[10], y[10]);
   word3_muladd(&w1, &w0, &w2, x[11], y[ 9]);
   word3_muladd(&w1, &w0, &w2, x[12], y[ 8]);
   word3_muladd(&w1, &w0, &w2, x[13], y[ 7]);
   word3_muladd(&w1, &w0, &w2, x[14], y[ 6]);
   word3_muladd(&w1, &w0, &w2, x[15], y[ 5]);
   z[20] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 6], y[15]);
   word3_muladd(&w2, &w1, &w0, x[ 7], y[14]);
   word3_muladd(&w2, &w1, &w0, x[ 8], y[13]);
   word3_muladd(&w2, &w1, &w0, x[ 9], y[12]);
   word3_muladd(&w2, &w1, &w0, x[10], y[11]);
   word3_muladd(&w2, &w1, &w0, x[11], y[10]);
   word3_muladd(&w2, &w1, &w0, x[12], y[ 9]);
   word3_muladd(&w2, &w1, &w0, x[13], y[ 8]);
   word3_muladd(&w2, &w1, &w0, x[14], y[ 7]);
   word3_muladd(&w2, &w1, &w0, x[15], y[ 6]);
   z[21] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[ 7], y[15]);
   word3_muladd(&w0, &w2, &w1, x[ 8], y[14]);
   word3_muladd(&w0, &w2, &w1, x[ 9], y[13]);
   word3_muladd(&w0, &w2, &w1, x[10], y[12]);
   word3_muladd(&w0, &w2, &w1, x[11], y[11]);
   word3_muladd(&w0, &w2, &w1, x[12], y[10]);
   word3_muladd(&w0, &w2, &w1, x[13], y[ 9]);
   word3_muladd(&w0, &w2, &w1, x[14], y[ 8]);
   word3_muladd(&w0, &w2, &w1, x[15], y[ 7]);
   z[22] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[ 8], y[15]);
   word3_muladd(&w1, &w0, &w2, x[ 9], y[14]);
   word3_muladd(&w1, &w0, &w2, x[10], y[13]);
   word3_muladd(&w1, &w0, &w2, x[11], y[12]);
   word3_muladd(&w1, &w0, &w2, x[12], y[11]);
   word3_muladd(&w1, &w0, &w2, x[13], y[10]);
   word3_muladd(&w1, &w0, &w2, x[14], y[ 9]);
   word3_muladd(&w1, &w0, &w2, x[15], y[ 8]);
   z[23] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[ 9], y[15]);
   word3_muladd(&w2, &w1, &w0, x[10], y[14]);
   word3_muladd(&w2, &w1, &w0, x[11], y[13]);
   word3_muladd(&w2, &w1, &w0, x[12], y[12]);
   word3_muladd(&w2, &w1, &w0, x[13], y[11]);
   word3_muladd(&w2, &w1, &w0, x[14], y[10]);
   word3_muladd(&w2, &w1, &w0, x[15], y[ 9]);
   z[24] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[10], y[15]);
   word3_muladd(&w0, &w2, &w1, x[11], y[14]);
   word3_muladd(&w0, &w2, &w1, x[12], y[13]);
   word3_muladd(&w0, &w2, &w1, x[13], y[12]);
   word3_muladd(&w0, &w2, &w1, x[14], y[11]);
   word3_muladd(&w0, &w2, &w1, x[15], y[10]);
   z[25] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[11], y[15]);
   word3_muladd(&w1, &w0, &w2, x[12], y[14]);
   word3_muladd(&w1, &w0, &w2, x[13], y[13]);
   word3_muladd(&w1, &w0, &w2, x[14], y[12]);
   word3_muladd(&w1, &w0, &w2, x[15], y[11]);
   z[26] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[12], y[15]);
   word3_muladd(&w2, &w1, &w0, x[13], y[14]);
   word3_muladd(&w2, &w1, &w0, x[14], y[13]);
   word3_muladd(&w2, &w1, &w0, x[15], y[12]);
   z[27] = w0; w0 = 0;

   word3_muladd(&w0, &w2, &w1, x[13], y[15]);
   word3_muladd(&w0, &w2, &w1, x[14], y[14]);
   word3_muladd(&w0, &w2, &w1, x[15], y[13]);
   z[28] = w1; w1 = 0;

   word3_muladd(&w1, &w0, &w2, x[14], y[15]);
   word3_muladd(&w1, &w0, &w2, x[15], y[14]);
   z[29] = w2; w2 = 0;

   word3_muladd(&w2, &w1, &w0, x[15], y[15]);
   z[30] = w0;
   z[31] = w1;
   }

}

}
/*
* Karatsuba Multiplication/Squaring
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Karatsuba Multiplication Operation
*/
void karatsuba_mul(word z[], const word x[], const word y[], size_t N,
                   word workspace[])
   {
   if(N < BOTAN_KARAT_MUL_THRESHOLD || N % 2)
      {
      if(N == 6)
         return bigint_comba_mul6(z, x, y);
      else if(N == 8)
         return bigint_comba_mul8(z, x, y);
      else if(N == 16)
         return bigint_comba_mul16(z, x, y);
      else
         return bigint_simple_mul(z, x, N, y, N);
      }

   const size_t N2 = N / 2;

   const word* x0 = x;
   const word* x1 = x + N2;
   const word* y0 = y;
   const word* y1 = y + N2;
   word* z0 = z;
   word* z1 = z + N;

   const s32bit cmp0 = bigint_cmp(x0, N2, x1, N2);
   const s32bit cmp1 = bigint_cmp(y1, N2, y0, N2);

   clear_mem(workspace, 2*N);

   if(cmp0 && cmp1)
      {
      if(cmp0 > 0)
         bigint_sub3(z0, x0, N2, x1, N2);
      else
         bigint_sub3(z0, x1, N2, x0, N2);

      if(cmp1 > 0)
         bigint_sub3(z1, y1, N2, y0, N2);
      else
         bigint_sub3(z1, y0, N2, y1, N2);

      karatsuba_mul(workspace, z0, z1, N2, workspace+N);
      }

   karatsuba_mul(z0, x0, y0, N2, workspace+N);
   karatsuba_mul(z1, x1, y1, N2, workspace+N);

   const size_t blocks_of_8 = N - (N % 8);

   word ws_carry = 0;

   for(size_t j = 0; j != blocks_of_8; j += 8)
      ws_carry = word8_add3(workspace + N + j, z0 + j, z1 + j, ws_carry);

   for(size_t j = blocks_of_8; j != N; ++j)
      workspace[N + j] = word_add(z0[j], z1[j], &ws_carry);

   word z_carry = 0;

   for(size_t j = 0; j != blocks_of_8; j += 8)
      z_carry = word8_add2(z + N2 + j, workspace + N + j, z_carry);

   for(size_t j = blocks_of_8; j != N; ++j)
      z[N2 + j] = word_add(z[N2 + j], workspace[N + j], &z_carry);

   z[N + N2] = word_add(z[N + N2], ws_carry, &z_carry);

   if(z_carry)
      for(size_t j = 1; j != N2; ++j)
         if(++z[N + N2 + j])
            break;

   if((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0))
      bigint_add2(z + N2, 2*N-N2, workspace, N);
   else
      bigint_sub2(z + N2, 2*N-N2, workspace, N);
   }

/*
* Karatsuba Squaring Operation
*/
void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[])
   {
   if(N < BOTAN_KARAT_SQR_THRESHOLD || N % 2)
      {
      if(N == 6)
         return bigint_comba_sqr6(z, x);
      else if(N == 8)
         return bigint_comba_sqr8(z, x);
      else if(N == 16)
         return bigint_comba_sqr16(z, x);
      else
         return bigint_simple_sqr(z, x, N);
      }

   const size_t N2 = N / 2;

   const word* x0 = x;
   const word* x1 = x + N2;
   word* z0 = z;
   word* z1 = z + N;

   const s32bit cmp = bigint_cmp(x0, N2, x1, N2);

   clear_mem(workspace, 2*N);

   if(cmp)
      {
      if(cmp > 0)
         bigint_sub3(z0, x0, N2, x1, N2);
      else
         bigint_sub3(z0, x1, N2, x0, N2);

      karatsuba_sqr(workspace, z0, N2, workspace+N);
      }

   karatsuba_sqr(z0, x0, N2, workspace+N);
   karatsuba_sqr(z1, x1, N2, workspace+N);

   const size_t blocks_of_8 = N - (N % 8);

   word ws_carry = 0;

   for(size_t j = 0; j != blocks_of_8; j += 8)
      ws_carry = word8_add3(workspace + N + j, z0 + j, z1 + j, ws_carry);

   for(size_t j = blocks_of_8; j != N; ++j)
      workspace[N + j] = word_add(z0[j], z1[j], &ws_carry);

   word z_carry = 0;

   for(size_t j = 0; j != blocks_of_8; j += 8)
      z_carry = word8_add2(z + N2 + j, workspace + N + j, z_carry);

   for(size_t j = blocks_of_8; j != N; ++j)
      z[N2 + j] = word_add(z[N2 + j], workspace[N + j], &z_carry);

   z[N + N2] = word_add(z[N + N2], ws_carry, &z_carry);

   if(z_carry)
      for(size_t j = 1; j != N2; ++j)
         if(++z[N + N2 + j])
            break;

   /*
   * This is only actually required if cmp is != 0, however
   * if cmp==0 then workspace[0:N] == 0 and avoiding the jump
   * hides a timing channel.
   */
   bigint_sub2(z + N2, 2*N-N2, workspace, N);
   }

/*
* Pick a good size for the Karatsuba multiply
*/
size_t karatsuba_size(size_t z_size,
                      size_t x_size, size_t x_sw,
                      size_t y_size, size_t y_sw)
   {
   if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size)
      return 0;

   if(((x_size == x_sw) && (x_size % 2)) ||
      ((y_size == y_sw) && (y_size % 2)))
      return 0;

   const size_t start = (x_sw > y_sw) ? x_sw : y_sw;
   const size_t end = (x_size < y_size) ? x_size : y_size;

   if(start == end)
      {
      if(start % 2)
         return 0;
      return start;
      }

   for(size_t j = start; j <= end; ++j)
      {
      if(j % 2)
         continue;

      if(2*j > z_size)
         return 0;

      if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size)
         {
         if(j % 4 == 2 &&
            (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size)
            return j+2;
         return j;
         }
      }

   return 0;
   }

/*
* Pick a good size for the Karatsuba squaring
*/
size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw)
   {
   if(x_sw == x_size)
      {
      if(x_sw % 2)
         return 0;
      return x_sw;
      }

   for(size_t j = x_sw; j <= x_size; ++j)
      {
      if(j % 2)
         continue;

      if(2*j > z_size)
         return 0;

      if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size)
         return j+2;
      return j;
      }

   return 0;
   }

}

/*
* Multiplication Algorithm Dispatcher
*/
void bigint_mul(word z[], size_t z_size, word workspace[],
                const word x[], size_t x_size, size_t x_sw,
                const word y[], size_t y_size, size_t y_sw)
   {
   if(x_sw == 1)
      {
      bigint_linmul3(z, y, y_sw, x[0]);
      }
   else if(y_sw == 1)
      {
      bigint_linmul3(z, x, x_sw, y[0]);
      }
   else if(x_sw <= 4 && x_size >= 4 &&
           y_sw <= 4 && y_size >= 4 && z_size >= 8)
      {
      bigint_comba_mul4(z, x, y);
      }
   else if(x_sw <= 6 && x_size >= 6 &&
           y_sw <= 6 && y_size >= 6 && z_size >= 12)
      {
      bigint_comba_mul6(z, x, y);
      }
   else if(x_sw <= 8 && x_size >= 8 &&
           y_sw <= 8 && y_size >= 8 && z_size >= 16)
      {
      bigint_comba_mul8(z, x, y);
      }
   else if(x_sw <= 16 && x_size >= 16 &&
           y_sw <= 16 && y_size >= 16 && z_size >= 32)
      {
      bigint_comba_mul16(z, x, y);
      }
   else if(x_sw < BOTAN_KARAT_MUL_THRESHOLD ||
           y_sw < BOTAN_KARAT_MUL_THRESHOLD ||
           !workspace)
      {
      bigint_simple_mul(z, x, x_sw, y, y_sw);
      }
   else
      {
      const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw);

      if(N)
         {
         clear_mem(workspace, 2*N);
         karatsuba_mul(z, x, y, N, workspace);
         }
      else
         bigint_simple_mul(z, x, x_sw, y, y_sw);
      }
   }

/*
* Squaring Algorithm Dispatcher
*/
void bigint_sqr(word z[], size_t z_size, word workspace[],
                const word x[], size_t x_size, size_t x_sw)
   {
   if(x_sw == 1)
      {
      bigint_linmul3(z, x, x_sw, x[0]);
      }
   else if(x_sw <= 4 && x_size >= 4 && z_size >= 8)
      {
      bigint_comba_sqr4(z, x);
      }
   else if(x_sw <= 6 && x_size >= 6 && z_size >= 12)
      {
      bigint_comba_sqr6(z, x);
      }
   else if(x_sw <= 8 && x_size >= 8 && z_size >= 16)
      {
      bigint_comba_sqr8(z, x);
      }
   else if(x_sw <= 16 && x_size >= 16 && z_size >= 32)
      {
      bigint_comba_sqr16(z, x);
      }
   else if(x_size < BOTAN_KARAT_SQR_THRESHOLD || !workspace)
      {
      bigint_simple_sqr(z, x, x_sw);
      }
   else
      {
      const size_t N = karatsuba_size(z_size, x_size, x_sw);

      if(N)
         {
         clear_mem(workspace, 2*N);
         karatsuba_sqr(z, x, N, workspace);
         }
      else
         bigint_simple_sqr(z, x, x_sw);
      }
   }

}
/*
* MP Misc Functions
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Core Division Operation
*/
size_t bigint_divcore(word q, word y2, word y1,
                      word x3, word x2, word x1)
   {
   // Compute (y2,y1) * q

   word y3 = 0;
   y1 = word_madd2(q, y1, &y3);
   y2 = word_madd2(q, y2, &y3);

   // Return (y3,y2,y1) >? (x3,x2,x1)

   if(y3 > x3) return 1;
   if(y3 < x3) return 0;
   if(y2 > x2) return 1;
   if(y2 < x2) return 0;
   if(y1 > x1) return 1;
   if(y1 < x1) return 0;
   return 0;
   }

/*
* Compare two MP integers
*/
s32bit bigint_cmp(const word x[], size_t x_size,
                  const word y[], size_t y_size)
   {
   if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); }

   while(x_size > y_size)
      {
      if(x[x_size-1])
         return 1;
      x_size--;
      }

   for(size_t j = x_size; j > 0; --j)
      {
      if(x[j-1] > y[j-1])
         return 1;
      if(x[j-1] < y[j-1])
         return -1;
      }

   return 0;
   }

/*
* Do a 2-word/1-word Division
*/
word bigint_divop(word n1, word n0, word d)
   {
   word high = n1 % d, quotient = 0;

   for(size_t j = 0; j != MP_WORD_BITS; ++j)
      {
      word high_top_bit = (high & MP_WORD_TOP_BIT);

      high <<= 1;
      high |= (n0 >> (MP_WORD_BITS-1-j)) & 1;
      quotient <<= 1;

      if(high_top_bit || high >= d)
         {
         high -= d;
         quotient |= 1;
         }
      }

   return quotient;
   }

/*
* Do a 2-word/1-word Modulo
*/
word bigint_modop(word n1, word n0, word d)
   {
   word z = bigint_divop(n1, n0, d);
   word dummy = 0;
   z = word_madd2(z, d, &dummy);
   return (n0-z);
   }

}

}
/*
* Montgomery Reduction
* (C) 1999-2011 Jack Lloyd
*     2006 Luca Piccarreta
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Montgomery Reduction Algorithm
*/
void bigint_monty_redc(word z[], size_t z_size,
                       const word p[], size_t p_size,
                       word p_dash, word ws[])
   {
   const size_t blocks_of_8 = p_size - (p_size % 8);

   for(size_t i = 0; i != p_size; ++i)
      {
      word* z_i = z + i;

      const word y = z_i[0] * p_dash;

      /*
      bigint_linmul3(ws, p, p_size, y);
      bigint_add2(z_i, z_size - i, ws, p_size+1);
      */

      word carry = 0;

      for(size_t j = 0; j != blocks_of_8; j += 8)
         carry = word8_madd3(z_i + j, p + j, y, carry);

      for(size_t j = blocks_of_8; j != p_size; ++j)
         z_i[j] = word_madd3(p[j], y, z_i[j], &carry);

      word z_sum = z_i[p_size] + carry;
      carry = (z_sum < z_i[p_size]);
      z_i[p_size] = z_sum;

      for(size_t j = p_size + 1; carry && j != z_size - i; ++j)
         {
         ++z_i[j];
         carry = !z_i[j];
         }
      }

   word borrow = 0;
   for(size_t i = 0; i != p_size; ++i)
      ws[i] = word_sub(z[p_size + i], p[i], &borrow);

   ws[p_size] = word_sub(z[p_size+p_size], 0, &borrow);

   copy_mem(ws + p_size + 1, z + p_size, p_size + 1);

   copy_mem(z, ws + borrow*(p_size+1), p_size + 1);
   clear_mem(z + p_size + 1, z_size - p_size - 1);
   }

void bigint_monty_mul(word z[], size_t z_size,
                      const word x[], size_t x_size, size_t x_sw,
                      const word y[], size_t y_size, size_t y_sw,
                      const word p[], size_t p_size, word p_dash,
                      word ws[])
   {
   bigint_mul(&z[0], z_size, &ws[0],
              &x[0], x_size, x_sw,
              &y[0], y_size, y_sw);

   bigint_monty_redc(&z[0], z_size,
                     &p[0], p_size, p_dash,
                     &ws[0]);
   }

void bigint_monty_sqr(word z[], size_t z_size,
                      const word x[], size_t x_size, size_t x_sw,
                      const word p[], size_t p_size, word p_dash,
                      word ws[])
   {
   bigint_sqr(&z[0], z_size, &ws[0],
              &x[0], x_size, x_sw);

   bigint_monty_redc(&z[0], z_size,
                     &p[0], p_size, p_dash,
                     &ws[0]);
   }

}

}
/*
* Simple O(N^2) Multiplication and Squaring
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Simple O(N^2) Multiplication
*/
void bigint_simple_mul(word z[], const word x[], size_t x_size,
                                 const word y[], size_t y_size)
   {
   const size_t x_size_8 = x_size - (x_size % 8);

   clear_mem(z, x_size + y_size);

   for(size_t i = 0; i != y_size; ++i)
      {
      const word y_i = y[i];

      word carry = 0;

      for(size_t j = 0; j != x_size_8; j += 8)
         carry = word8_madd3(z + i + j, x + j, y_i, carry);

      for(size_t j = x_size_8; j != x_size; ++j)
         z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry);

      z[x_size+i] = carry;
      }
   }

/*
* Simple O(N^2) Squaring
*
* This is exactly the same algorithm as bigint_simple_mul, however
* because C/C++ compilers suck at alias analysis it is good to have
* the version where the compiler knows that x == y
*
* There is an O(n^1.5) squaring algorithm specified in Handbook of
* Applied Cryptography, chapter 14
*
*/
void bigint_simple_sqr(word z[], const word x[], size_t x_size)
   {
   const size_t x_size_8 = x_size - (x_size % 8);

   clear_mem(z, 2*x_size);

   for(size_t i = 0; i != x_size; ++i)
      {
      const word x_i = x[i];
      word carry = 0;

      for(size_t j = 0; j != x_size_8; j += 8)
         carry = word8_madd3(z + i + j, x + j, x_i, carry);

      for(size_t j = x_size_8; j != x_size; ++j)
         z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry);

      z[x_size+i] = carry;
      }
   }

}

}
/*
* MP Shift Algorithms
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

extern "C" {

/*
* Single Operand Left Shift
*/
void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
   {
   if(word_shift)
      {
      for(size_t j = 1; j != x_size + 1; ++j)
         x[(x_size - j) + word_shift] = x[x_size - j];
      clear_mem(x, word_shift);
      }

   if(bit_shift)
      {
      word carry = 0;
      for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
         {
         word temp = x[j];
         x[j] = (temp << bit_shift) | carry;
         carry = (temp >> (MP_WORD_BITS - bit_shift));
         }
      }
   }

/*
* Single Operand Right Shift
*/
void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
   {
   if(x_size < word_shift)
      {
      clear_mem(x, x_size);
      return;
      }

   if(word_shift)
      {
      copy_mem(x, x + word_shift, x_size - word_shift);
      clear_mem(x + x_size - word_shift, word_shift);
      }

   if(bit_shift)
      {
      word carry = 0;

      size_t top = x_size - word_shift;

      while(top >= 4)
         {
         word w = x[top-1];
         x[top-1] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));

         w = x[top-2];
         x[top-2] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));

         w = x[top-3];
         x[top-3] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));

         w = x[top-4];
         x[top-4] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));

         top -= 4;
         }

      while(top)
         {
         word w = x[top-1];
         x[top-1] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));

         top--;
         }
      }
   }

/*
* Two Operand Left Shift
*/
void bigint_shl2(word y[], const word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift)
   {
   for(size_t j = 0; j != x_size; ++j)
      y[j + word_shift] = x[j];
   if(bit_shift)
      {
      word carry = 0;
      for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
         {
         word w = y[j];
         y[j] = (w << bit_shift) | carry;
         carry = (w >> (MP_WORD_BITS - bit_shift));
         }
      }
   }

/*
* Two Operand Right Shift
*/
void bigint_shr2(word y[], const word x[], size_t x_size,
                 size_t word_shift, size_t bit_shift)
   {
   if(x_size < word_shift) return;

   for(size_t j = 0; j != x_size - word_shift; ++j)
      y[j] = x[j + word_shift];
   if(bit_shift)
      {
      word carry = 0;
      for(size_t j = x_size - word_shift; j > 0; --j)
         {
         word w = y[j-1];
         y[j-1] = (w >> bit_shift) | carry;
         carry = (w << (MP_WORD_BITS - bit_shift));
         }
      }
   }

}

}
/*
* DSA Parameter Generation
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

namespace {

/*
* Check if this size is allowed by FIPS 186-3
*/
bool fips186_3_valid_size(size_t pbits, size_t qbits)
   {
   if(qbits == 160)
      return (pbits == 512 || pbits == 768 || pbits == 1024);

   if(qbits == 224)
      return (pbits == 2048);

   if(qbits == 256)
      return (pbits == 2048 || pbits == 3072);

   return false;
   }

}

/*
* Attempt DSA prime generation with given seed
*/
bool generate_dsa_primes(RandomNumberGenerator& rng,
                         Algorithm_Factory& af,
                         BigInt& p, BigInt& q,
                         size_t pbits, size_t qbits,
                         const MemoryRegion<byte>& seed_c)
   {
   if(!fips186_3_valid_size(pbits, qbits))
      throw Invalid_Argument(
         "FIPS 186-3 does not allow DSA domain parameters of " +
         to_string(pbits) + "/" + to_string(qbits) + " bits long");

   if(seed_c.size() * 8 < qbits)
      throw Invalid_Argument(
         "Generating a DSA parameter set with a " + to_string(qbits) +
         "long q requires a seed at least as many bits long");

   std::auto_ptr<HashFunction> hash(
      af.make_hash_function("SHA-" + to_string(qbits)));

   const size_t HASH_SIZE = hash->output_length();

   class Seed
      {
      public:
         Seed(const MemoryRegion<byte>& s) : seed(s) {}

         operator MemoryRegion<byte>& () { return seed; }

         Seed& operator++()
            {
            for(size_t j = seed.size(); j > 0; --j)
               if(++seed[j-1])
                  break;
            return (*this);
            }
      private:
         SecureVector<byte> seed;
      };

   Seed seed(seed_c);

   q.binary_decode(hash->process(seed));
   q.set_bit(qbits-1);
   q.set_bit(0);

   if(!check_prime(q, rng))
      return false;

   const size_t n = (pbits-1) / (HASH_SIZE * 8),
                b = (pbits-1) % (HASH_SIZE * 8);

   BigInt X;
   SecureVector<byte> V(HASH_SIZE * (n+1));

   for(size_t j = 0; j != 4096; ++j)
      {
      for(size_t k = 0; k <= n; ++k)
         {
         ++seed;
         hash->update(seed);
         hash->final(&V[HASH_SIZE * (n-k)]);
         }

      X.binary_decode(&V[HASH_SIZE - 1 - b/8],
                      V.size() - (HASH_SIZE - 1 - b/8));
      X.set_bit(pbits-1);

      p = X - (X % (2*q) - 1);

      if(p.bits() == pbits && check_prime(p, rng))
         return true;
      }
   return false;
   }

/*
* Generate DSA Primes
*/
SecureVector<byte> generate_dsa_primes(RandomNumberGenerator& rng,
                                       Algorithm_Factory& af,
                                       BigInt& p, BigInt& q,
                                       size_t pbits, size_t qbits)
   {
   while(true)
      {
      SecureVector<byte> seed = rng.random_vec(qbits / 8);

      if(generate_dsa_primes(rng, af, p, q, pbits, qbits, seed))
         return seed;
      }
   }

}
/*
* Jacobi Function
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Calculate the Jacobi symbol
*/
s32bit jacobi(const BigInt& a, const BigInt& n)
   {
   if(a.is_negative())
      throw Invalid_Argument("jacobi: first argument must be non-negative");
   if(n.is_even() || n < 2)
      throw Invalid_Argument("jacobi: second argument must be odd and > 1");

   BigInt x = a, y = n;
   s32bit J = 1;

   while(y > 1)
      {
      x %= y;
      if(x > y / 2)
         {
         x = y - x;
         if(y % 4 == 3)
            J = -J;
         }
      if(x.is_zero())
         return 0;

      size_t shifts = low_zero_bits(x);
      x >>= shifts;
      if(shifts % 2)
         {
         word y_mod_8 = y % 8;
         if(y_mod_8 == 3 || y_mod_8 == 5)
            J = -J;
         }

      if(x % 4 == 3 && y % 4 == 3)
         J = -J;
      std::swap(x, y);
      }
   return J;
   }

}
/*
* Prime Generation
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Generate a random prime
*/
BigInt random_prime(RandomNumberGenerator& rng,
                    size_t bits, const BigInt& coprime,
                    size_t equiv, size_t modulo)
   {
   if(bits <= 1)
      throw Invalid_Argument("random_prime: Can't make a prime of " +
                             to_string(bits) + " bits");
   else if(bits == 2)
      return ((rng.next_byte() % 2) ? 2 : 3);
   else if(bits == 3)
      return ((rng.next_byte() % 2) ? 5 : 7);
   else if(bits == 4)
      return ((rng.next_byte() % 2) ? 11 : 13);

   if(coprime <= 0)
      throw Invalid_Argument("random_prime: coprime must be > 0");
   if(modulo % 2 == 1 || modulo == 0)
      throw Invalid_Argument("random_prime: Invalid modulo value");
   if(equiv >= modulo || equiv % 2 == 0)
      throw Invalid_Argument("random_prime: equiv must be < modulo, and odd");

   while(true)
      {
      BigInt p(rng, bits);

      // Force lowest and two top bits on
      p.set_bit(bits - 1);
      p.set_bit(bits - 2);
      p.set_bit(0);

      if(p % modulo != equiv)
         p += (modulo - p % modulo) + equiv;

      const size_t sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE);
      SecureVector<size_t> sieve(sieve_size);

      for(size_t j = 0; j != sieve.size(); ++j)
         sieve[j] = p % PRIMES[j];

      size_t counter = 0;
      while(true)
         {
         if(counter == 4096 || p.bits() > bits)
            break;

         bool passes_sieve = true;
         ++counter;
         p += modulo;

         if(p.bits() > bits)
            break;

         for(size_t j = 0; j != sieve.size(); ++j)
            {
            sieve[j] = (sieve[j] + modulo) % PRIMES[j];
            if(sieve[j] == 0)
               passes_sieve = false;
            }

         if(!passes_sieve || gcd(p - 1, coprime) != 1)
            continue;
         if(check_prime(p, rng))
            return p;
         }
      }
   }

/*
* Generate a random safe prime
*/
BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits)
   {
   if(bits <= 64)
      throw Invalid_Argument("random_safe_prime: Can't make a prime of " +
                             to_string(bits) + " bits");

   BigInt p;
   do
      p = (random_prime(rng, bits - 1) << 1) + 1;
   while(!check_prime(p, rng));
   return p;
   }

}
/*
* Fused and Important MP Algorithms
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Square a BigInt
*/
BigInt square(const BigInt& x)
   {
   const size_t x_sw = x.sig_words();

   BigInt z(BigInt::Positive, round_up<size_t>(2*x_sw, 16));
   SecureVector<word> workspace(z.size());

   bigint_sqr(z.get_reg(), z.size(), workspace,
              x.data(), x.size(), x_sw);
   return z;
   }

/*
* Multiply-Add Operation
*/
BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c)
   {
   if(c.is_negative() || c.is_zero())
      throw Invalid_Argument("mul_add: Third argument must be > 0");

   BigInt::Sign sign = BigInt::Positive;
   if(a.sign() != b.sign())
      sign = BigInt::Negative;

   const size_t a_sw = a.sig_words();
   const size_t b_sw = b.sig_words();
   const size_t c_sw = c.sig_words();

   BigInt r(sign, std::max(a.size() + b.size(), c_sw) + 1);
   SecureVector<word> workspace(r.size());

   bigint_mul(r.get_reg(), r.size(), workspace,
              a.data(), a.size(), a_sw,
              b.data(), b.size(), b_sw);
   const size_t r_size = std::max(r.sig_words(), c_sw);
   bigint_add2(r.get_reg(), r_size, c.data(), c_sw);
   return r;
   }

/*
* Subtract-Multiply Operation
*/
BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c)
   {
   if(a.is_negative() || b.is_negative())
      throw Invalid_Argument("sub_mul: First two arguments must be >= 0");

   BigInt r = a;
   r -= b;
   r *= c;
   return r;
   }

}
/*
* Number Theory Functions
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

/*
* Miller-Rabin Primality Tester
*/
class MillerRabin_Test
   {
   public:
      bool is_witness(const BigInt& nonce);
      MillerRabin_Test(const BigInt& num);
   private:
      BigInt n, r, n_minus_1;
      size_t s;
      Fixed_Exponent_Power_Mod pow_mod;
      Modular_Reducer reducer;
   };

/*
* Miller-Rabin Test, as described in Handbook of Applied Cryptography
* section 4.24
*/
bool MillerRabin_Test::is_witness(const BigInt& a)
   {
   if(a < 2 || a >= n_minus_1)
      throw Invalid_Argument("Bad size for nonce in Miller-Rabin test");

   BigInt y = pow_mod(a);
   if(y == 1 || y == n_minus_1)
      return false;

   for(size_t i = 1; i != s; ++i)
      {
      y = reducer.square(y);

      if(y == 1) // found a non-trivial square root
         return true;

      if(y == n_minus_1) // -1, trivial square root, so give up
         return false;
      }

   if(y != n_minus_1) // fails Fermat test
      return true;

   return false;
   }

/*
* Miller-Rabin Constructor
*/
MillerRabin_Test::MillerRabin_Test(const BigInt& num)
   {
   if(num.is_even() || num < 3)
      throw Invalid_Argument("MillerRabin_Test: Invalid number for testing");

   n = num;
   n_minus_1 = n - 1;
   s = low_zero_bits(n_minus_1);
   r = n_minus_1 >> s;

   pow_mod = Fixed_Exponent_Power_Mod(r, n);
   reducer = Modular_Reducer(n);
   }

/*
* Miller-Rabin Iterations
*/
size_t miller_rabin_test_iterations(size_t bits, size_t level)
   {
   struct mapping { size_t bits; size_t verify_iter; size_t check_iter; };

   static const mapping tests[] = {
      {   50, 55, 25 },
      {  100, 38, 22 },
      {  160, 32, 18 },
      {  163, 31, 17 },
      {  168, 30, 16 },
      {  177, 29, 16 },
      {  181, 28, 15 },
      {  185, 27, 15 },
      {  190, 26, 15 },
      {  195, 25, 14 },
      {  201, 24, 14 },
      {  208, 23, 14 },
      {  215, 22, 13 },
      {  222, 21, 13 },
      {  231, 20, 13 },
      {  241, 19, 12 },
      {  252, 18, 12 },
      {  264, 17, 12 },
      {  278, 16, 11 },
      {  294, 15, 10 },
      {  313, 14,  9 },
      {  334, 13,  8 },
      {  360, 12,  8 },
      {  392, 11,  7 },
      {  430, 10,  7 },
      {  479,  9,  6 },
      {  542,  8,  6 },
      {  626,  7,  5 },
      {  746,  6,  4 },
      {  926,  5,  3 },
      { 1232,  4,  2 },
      { 1853,  3,  2 },
      {    0,  0,  0 }
   };

   for(size_t i = 0; tests[i].bits; ++i)
      {
      if(bits <= tests[i].bits)
         {
         if(level >= 2)
            return tests[i].verify_iter;
         else if(level == 1)
            return tests[i].check_iter;
         else if(level == 0)
            return std::max<size_t>(tests[i].check_iter / 4, 1);
         }
      }

   return level > 0 ? 2 : 1; // for large inputs
   }

}

/*
* Return the number of 0 bits at the end of n
*/
size_t low_zero_bits(const BigInt& n)
   {
   size_t low_zero = 0;

   if(n.is_positive() && n.is_nonzero())
      {
      for(size_t i = 0; i != n.size(); ++i)
         {
         word x = n[i];

         if(x)
            {
            low_zero += ctz(x);
            break;
            }
         else
            low_zero += BOTAN_MP_WORD_BITS;
         }
      }

   return low_zero;
   }

/*
* Calculate the GCD
*/
BigInt gcd(const BigInt& a, const BigInt& b)
   {
   if(a.is_zero() || b.is_zero()) return 0;
   if(a == 1 || b == 1)           return 1;

   BigInt x = a, y = b;
   x.set_sign(BigInt::Positive);
   y.set_sign(BigInt::Positive);
   size_t shift = std::min(low_zero_bits(x), low_zero_bits(y));

   x >>= shift;
   y >>= shift;

   while(x.is_nonzero())
      {
      x >>= low_zero_bits(x);
      y >>= low_zero_bits(y);
      if(x >= y) { x -= y; x >>= 1; }
      else       { y -= x; y >>= 1; }
      }

   return (y << shift);
   }

/*
* Calculate the LCM
*/
BigInt lcm(const BigInt& a, const BigInt& b)
   {
   return ((a * b) / gcd(a, b));
   }

/*
* Find the Modular Inverse
*/
BigInt inverse_mod(const BigInt& n, const BigInt& mod)
   {
   if(mod.is_zero())
      throw BigInt::DivideByZero();
   if(mod.is_negative() || n.is_negative())
      throw Invalid_Argument("inverse_mod: arguments must be non-negative");

   if(n.is_zero() || (n.is_even() && mod.is_even()))
      return 0;

   BigInt x = mod, y = n, u = mod, v = n;
   BigInt A = 1, B = 0, C = 0, D = 1;

   while(u.is_nonzero())
      {
      size_t zero_bits = low_zero_bits(u);
      u >>= zero_bits;
      for(size_t i = 0; i != zero_bits; ++i)
         {
         if(A.is_odd() || B.is_odd())
            { A += y; B -= x; }
         A >>= 1; B >>= 1;
         }

      zero_bits = low_zero_bits(v);
      v >>= zero_bits;
      for(size_t i = 0; i != zero_bits; ++i)
         {
         if(C.is_odd() || D.is_odd())
            { C += y; D -= x; }
         C >>= 1; D >>= 1;
         }

      if(u >= v) { u -= v; A -= C; B -= D; }
      else       { v -= u; C -= A; D -= B; }
      }

   if(v != 1)
      return 0;

   while(D.is_negative()) D += mod;
   while(D >= mod) D -= mod;

   return D;
   }

/*
* Modular Exponentiation
*/
BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
   {
   Power_Mod pow_mod(mod);
   pow_mod.set_base(base);
   pow_mod.set_exponent(exp);
   return pow_mod.execute();
   }

/*
* Test for primaility using Miller-Rabin
*/
bool primality_test(const BigInt& n,
                    RandomNumberGenerator& rng,
                    size_t level)
   {
   const size_t PREF_NONCE_BITS = 64;

   if(n == 2)
      return true;
   if(n <= 1 || n.is_even())
      return false;

   // Fast path testing for small numbers (<= 65521)
   if(n <= PRIMES[PRIME_TABLE_SIZE-1])
      {
      const word num = n.word_at(0);

      for(size_t i = 0; PRIMES[i]; ++i)
         {
         if(num == PRIMES[i])
            return true;
         if(num < PRIMES[i])
            return false;
         }

      return false;
      }

   if(level > 2)
      level = 2;

   const size_t NONCE_BITS = std::min(n.bits() - 2, PREF_NONCE_BITS);

   MillerRabin_Test mr(n);

   const size_t tests = miller_rabin_test_iterations(n.bits(), level);

   BigInt nonce;
   for(size_t i = 0; i != tests; ++i)
      {
      while(nonce < 2 || nonce >= (n-1))
         nonce.randomize(rng, NONCE_BITS);

      if(mr.is_witness(nonce))
         return false;
      }
   return true;
   }

}
/*
* Modular Exponentiation Proxy
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Power_Mod Constructor
*/
Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints)
   {
   core = 0;
   set_modulus(n, hints);
   }

/*
* Power_Mod Copy Constructor
*/
Power_Mod::Power_Mod(const Power_Mod& other)
   {
   core = 0;
   if(other.core)
      core = other.core->copy();
   }

/*
* Power_Mod Assignment Operator
*/
Power_Mod& Power_Mod::operator=(const Power_Mod& other)
   {
   delete core;
   core = 0;
   if(other.core)
      core = other.core->copy();
   return (*this);
   }

/*
* Power_Mod Destructor
*/
Power_Mod::~Power_Mod()
   {
   delete core;
   }

/*
* Set the modulus
*/
void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints) const
   {
   delete core;
   core = 0;

   if(n != 0)
      {
      Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

      while(const Engine* engine = i.next())
         {
         core = engine->mod_exp(n, hints);

         if(core)
            break;
         }

      if(!core)
         throw Lookup_Error("Power_Mod: Unable to find a working engine");
      }
   }

/*
* Set the base
*/
void Power_Mod::set_base(const BigInt& b) const
   {
   if(b.is_zero() || b.is_negative())
      throw Invalid_Argument("Power_Mod::set_base: arg must be > 0");

   if(!core)
      throw Internal_Error("Power_Mod::set_base: core was NULL");
   core->set_base(b);
   }

/*
* Set the exponent
*/
void Power_Mod::set_exponent(const BigInt& e) const
   {
   if(e.is_negative())
      throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0");

   if(!core)
      throw Internal_Error("Power_Mod::set_exponent: core was NULL");
   core->set_exponent(e);
   }

/*
* Compute the result
*/
BigInt Power_Mod::execute() const
   {
   if(!core)
      throw Internal_Error("Power_Mod::execute: core was NULL");
   return core->execute();
   }

/*
* Try to choose a good window size
*/
size_t Power_Mod::window_bits(size_t exp_bits, size_t,
                              Power_Mod::Usage_Hints hints)
   {
   static const size_t wsize[][2] = {
      { 1434, 7 },
      {  539, 6 },
      {  197, 4 },
      {   70, 3 },
      {   25, 2 },
      {    0, 0 }
   };

   size_t window_bits = 1;

   if(exp_bits)
      {
      for(size_t j = 0; wsize[j][0]; ++j)
         {
         if(exp_bits >= wsize[j][0])
            {
            window_bits += wsize[j][1];
            break;
            }
         }
      }

   if(hints & Power_Mod::BASE_IS_FIXED)
      window_bits += 2;
   if(hints & Power_Mod::EXP_IS_LARGE)
      ++window_bits;

   return window_bits;
   }

namespace {

/*
* Choose potentially useful hints
*/
Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n)
   {
   if(b == 2)
      return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 |
                                    Power_Mod::BASE_IS_SMALL);

   const size_t b_bits = b.bits();
   const size_t n_bits = n.bits();

   if(b_bits < n_bits / 32)
      return Power_Mod::BASE_IS_SMALL;
   if(b_bits > n_bits / 4)
      return Power_Mod::BASE_IS_LARGE;

   return Power_Mod::NO_HINTS;
   }

/*
* Choose potentially useful hints
*/
Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n)
   {
   const size_t e_bits = e.bits();
   const size_t n_bits = n.bits();

   if(e_bits < n_bits / 32)
      return Power_Mod::BASE_IS_SMALL;
   if(e_bits > n_bits / 4)
      return Power_Mod::BASE_IS_LARGE;
   return Power_Mod::NO_HINTS;
   }

}

/*
* Fixed_Exponent_Power_Mod Constructor
*/
Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e,
                                                   const BigInt& n,
                                                   Usage_Hints hints) :
   Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n)))
   {
   set_exponent(e);
   }

/*
* Fixed_Base_Power_Mod Constructor
*/
Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n,
                                           Usage_Hints hints) :
   Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n)))
   {
   set_base(b);
   }

}
/*
* Fixed Window Exponentiation
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <vector>

namespace Botan {

/*
* Set the exponent
*/
void Fixed_Window_Exponentiator::set_exponent(const BigInt& e)
   {
   exp = e;
   }

/*
* Set the base
*/
void Fixed_Window_Exponentiator::set_base(const BigInt& base)
   {
   window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints);

   g.resize((1 << window_bits) - 1);
   g[0] = base;
   for(size_t j = 1; j != g.size(); ++j)
      g[j] = reducer.multiply(g[j-1], g[0]);
   }

/*
* Compute the result
*/
BigInt Fixed_Window_Exponentiator::execute() const
   {
   const size_t exp_nibbles = (exp.bits() + window_bits - 1) / window_bits;

   BigInt x = 1;
   for(size_t j = exp_nibbles; j > 0; --j)
      {
      for(size_t k = 0; k != window_bits; ++k)
         x = reducer.square(x);

      if(u32bit nibble = exp.get_substring(window_bits*(j-1), window_bits))
         x = reducer.multiply(x, g[nibble-1]);
      }
   return x;
   }

/*
* Fixed_Window_Exponentiator Constructor
*/
Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n,
   Power_Mod::Usage_Hints hints)
   {
   reducer = Modular_Reducer(n);
   this->hints = hints;
   window_bits = 0;
   }

}
/*
* Montgomery Exponentiation
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Set the exponent
*/
void Montgomery_Exponentiator::set_exponent(const BigInt& exp)
   {
   this->exp = exp;
   exp_bits = exp.bits();
   }

/*
* Set the base
*/
void Montgomery_Exponentiator::set_base(const BigInt& base)
   {
   window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints);

   g.resize((1 << window_bits) - 1);

   SecureVector<word> z(2 * (mod_words + 1));
   SecureVector<word> workspace(z.size());

   g[0] = (base >= modulus) ? (base % modulus) : base;

   bigint_monty_mul(&z[0], z.size(),
                    g[0].data(), g[0].size(), g[0].sig_words(),
                    R2.data(), R2.size(), R2.sig_words(),
                    modulus.data(), mod_words, mod_prime,
                    &workspace[0]);

   g[0].assign(&z[0], mod_words + 1);

   const BigInt& x = g[0];
   const size_t x_sig = x.sig_words();

   for(size_t i = 1; i != g.size(); ++i)
      {
      const BigInt& y = g[i-1];
      const size_t y_sig = y.sig_words();

      zeroise(z);
      bigint_monty_mul(&z[0], z.size(),
                       x.data(), x.size(), x_sig,
                       y.data(), y.size(), y_sig,
                       modulus.data(), mod_words, mod_prime,
                       &workspace[0]);

      g[i].assign(&z[0], mod_words + 1);
      }
   }

/*
* Compute the result
*/
BigInt Montgomery_Exponentiator::execute() const
   {
   const size_t exp_nibbles = (exp_bits + window_bits - 1) / window_bits;

   BigInt x = R_mod;
   SecureVector<word> z(2 * (mod_words + 1));
   SecureVector<word> workspace(2 * (mod_words + 1));

   for(size_t i = exp_nibbles; i > 0; --i)
      {
      for(size_t k = 0; k != window_bits; ++k)
         {
         zeroise(z);

         bigint_monty_sqr(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          modulus.data(), mod_words, mod_prime,
                          &workspace[0]);

         x.assign(&z[0], mod_words + 1);
         }

      if(u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits))
         {
         const BigInt& y = g[nibble-1];

         zeroise(z);
         bigint_monty_mul(&z[0], z.size(),
                          x.data(), x.size(), x.sig_words(),
                          y.data(), y.size(), y.sig_words(),
                          modulus.data(), mod_words, mod_prime,
                          &workspace[0]);

         x.assign(&z[0], mod_words + 1);
         }
      }

   x.get_reg().resize(2*mod_words+1);

   bigint_monty_redc(&x[0], x.size(),
                     modulus.data(), mod_words, mod_prime,
                     &workspace[0]);

   x.get_reg().resize(mod_words+1);

   return x;
   }

/*
* Montgomery_Exponentiator Constructor
*/
Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod,
   Power_Mod::Usage_Hints hints)
   {
   // Montgomery reduction only works for positive odd moduli
   if(!mod.is_positive() || mod.is_even())
      throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus");

   window_bits = 0;
   this->hints = hints;
   modulus = mod;

   mod_words = modulus.sig_words();

   BigInt r(BigInt::Power2, mod_words * BOTAN_MP_WORD_BITS);
   mod_prime = (((r * inverse_mod(r, mod)) - 1) / mod).word_at(0);

   R_mod = r % modulus;

   R2 = (R_mod * R_mod) % modulus;
   }

}
/*
* Small Primes Table
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const u16bit PRIMES[PRIME_TABLE_SIZE+1] = {
    3,     5,     7,    11,    13,    17,    19,    23,    29,    31,    37,
   41,    43,    47,    53,    59,    61,    67,    71,    73,    79,    83,
   89,    97,   101,   103,   107,   109,   113,   127,   131,   137,   139,
  149,   151,   157,   163,   167,   173,   179,   181,   191,   193,   197,
  199,   211,   223,   227,   229,   233,   239,   241,   251,   257,   263,
  269,   271,   277,   281,   283,   293,   307,   311,   313,   317,   331,
  337,   347,   349,   353,   359,   367,   373,   379,   383,   389,   397,
  401,   409,   419,   421,   431,   433,   439,   443,   449,   457,   461,
  463,   467,   479,   487,   491,   499,   503,   509,   521,   523,   541,
  547,   557,   563,   569,   571,   577,   587,   593,   599,   601,   607,
  613,   617,   619,   631,   641,   643,   647,   653,   659,   661,   673,
  677,   683,   691,   701,   709,   719,   727,   733,   739,   743,   751,
  757,   761,   769,   773,   787,   797,   809,   811,   821,   823,   827,
  829,   839,   853,   857,   859,   863,   877,   881,   883,   887,   907,
  911,   919,   929,   937,   941,   947,   953,   967,   971,   977,   983,
  991,   997,  1009,  1013,  1019,  1021,  1031,  1033,  1039,  1049,  1051,
 1061,  1063,  1069,  1087,  1091,  1093,  1097,  1103,  1109,  1117,  1123,
 1129,  1151,  1153,  1163,  1171,  1181,  1187,  1193,  1201,  1213,  1217,
 1223,  1229,  1231,  1237,  1249,  1259,  1277,  1279,  1283,  1289,  1291,
 1297,  1301,  1303,  1307,  1319,  1321,  1327,  1361,  1367,  1373,  1381,
 1399,  1409,  1423,  1427,  1429,  1433,  1439,  1447,  1451,  1453,  1459,
 1471,  1481,  1483,  1487,  1489,  1493,  1499,  1511,  1523,  1531,  1543,
 1549,  1553,  1559,  1567,  1571,  1579,  1583,  1597,  1601,  1607,  1609,
 1613,  1619,  1621,  1627,  1637,  1657,  1663,  1667,  1669,  1693,  1697,
 1699,  1709,  1721,  1723,  1733,  1741,  1747,  1753,  1759,  1777,  1783,
 1787,  1789,  1801,  1811,  1823,  1831,  1847,  1861,  1867,  1871,  1873,
 1877,  1879,  1889,  1901,  1907,  1913,  1931,  1933,  1949,  1951,  1973,
 1979,  1987,  1993,  1997,  1999,  2003,  2011,  2017,  2027,  2029,  2039,
 2053,  2063,  2069,  2081,  2083,  2087,  2089,  2099,  2111,  2113,  2129,
 2131,  2137,  2141,  2143,  2153,  2161,  2179,  2203,  2207,  2213,  2221,
 2237,  2239,  2243,  2251,  2267,  2269,  2273,  2281,  2287,  2293,  2297,
 2309,  2311,  2333,  2339,  2341,  2347,  2351,  2357,  2371,  2377,  2381,
 2383,  2389,  2393,  2399,  2411,  2417,  2423,  2437,  2441,  2447,  2459,
 2467,  2473,  2477,  2503,  2521,  2531,  2539,  2543,  2549,  2551,  2557,
 2579,  2591,  2593,  2609,  2617,  2621,  2633,  2647,  2657,  2659,  2663,
 2671,  2677,  2683,  2687,  2689,  2693,  2699,  2707,  2711,  2713,  2719,
 2729,  2731,  2741,  2749,  2753,  2767,  2777,  2789,  2791,  2797,  2801,
 2803,  2819,  2833,  2837,  2843,  2851,  2857,  2861,  2879,  2887,  2897,
 2903,  2909,  2917,  2927,  2939,  2953,  2957,  2963,  2969,  2971,  2999,
 3001,  3011,  3019,  3023,  3037,  3041,  3049,  3061,  3067,  3079,  3083,
 3089,  3109,  3119,  3121,  3137,  3163,  3167,  3169,  3181,  3187,  3191,
 3203,  3209,  3217,  3221,  3229,  3251,  3253,  3257,  3259,  3271,  3299,
 3301,  3307,  3313,  3319,  3323,  3329,  3331,  3343,  3347,  3359,  3361,
 3371,  3373,  3389,  3391,  3407,  3413,  3433,  3449,  3457,  3461,  3463,
 3467,  3469,  3491,  3499,  3511,  3517,  3527,  3529,  3533,  3539,  3541,
 3547,  3557,  3559,  3571,  3581,  3583,  3593,  3607,  3613,  3617,  3623,
 3631,  3637,  3643,  3659,  3671,  3673,  3677,  3691,  3697,  3701,  3709,
 3719,  3727,  3733,  3739,  3761,  3767,  3769,  3779,  3793,  3797,  3803,
 3821,  3823,  3833,  3847,  3851,  3853,  3863,  3877,  3881,  3889,  3907,
 3911,  3917,  3919,  3923,  3929,  3931,  3943,  3947,  3967,  3989,  4001,
 4003,  4007,  4013,  4019,  4021,  4027,  4049,  4051,  4057,  4073,  4079,
 4091,  4093,  4099,  4111,  4127,  4129,  4133,  4139,  4153,  4157,  4159,
 4177,  4201,  4211,  4217,  4219,  4229,  4231,  4241,  4243,  4253,  4259,
 4261,  4271,  4273,  4283,  4289,  4297,  4327,  4337,  4339,  4349,  4357,
 4363,  4373,  4391,  4397,  4409,  4421,  4423,  4441,  4447,  4451,  4457,
 4463,  4481,  4483,  4493,  4507,  4513,  4517,  4519,  4523,  4547,  4549,
 4561,  4567,  4583,  4591,  4597,  4603,  4621,  4637,  4639,  4643,  4649,
 4651,  4657,  4663,  4673,  4679,  4691,  4703,  4721,  4723,  4729,  4733,
 4751,  4759,  4783,  4787,  4789,  4793,  4799,  4801,  4813,  4817,  4831,
 4861,  4871,  4877,  4889,  4903,  4909,  4919,  4931,  4933,  4937,  4943,
 4951,  4957,  4967,  4969,  4973,  4987,  4993,  4999,  5003,  5009,  5011,
 5021,  5023,  5039,  5051,  5059,  5077,  5081,  5087,  5099,  5101,  5107,
 5113,  5119,  5147,  5153,  5167,  5171,  5179,  5189,  5197,  5209,  5227,
 5231,  5233,  5237,  5261,  5273,  5279,  5281,  5297,  5303,  5309,  5323,
 5333,  5347,  5351,  5381,  5387,  5393,  5399,  5407,  5413,  5417,  5419,
 5431,  5437,  5441,  5443,  5449,  5471,  5477,  5479,  5483,  5501,  5503,
 5507,  5519,  5521,  5527,  5531,  5557,  5563,  5569,  5573,  5581,  5591,
 5623,  5639,  5641,  5647,  5651,  5653,  5657,  5659,  5669,  5683,  5689,
 5693,  5701,  5711,  5717,  5737,  5741,  5743,  5749,  5779,  5783,  5791,
 5801,  5807,  5813,  5821,  5827,  5839,  5843,  5849,  5851,  5857,  5861,
 5867,  5869,  5879,  5881,  5897,  5903,  5923,  5927,  5939,  5953,  5981,
 5987,  6007,  6011,  6029,  6037,  6043,  6047,  6053,  6067,  6073,  6079,
 6089,  6091,  6101,  6113,  6121,  6131,  6133,  6143,  6151,  6163,  6173,
 6197,  6199,  6203,  6211,  6217,  6221,  6229,  6247,  6257,  6263,  6269,
 6271,  6277,  6287,  6299,  6301,  6311,  6317,  6323,  6329,  6337,  6343,
 6353,  6359,  6361,  6367,  6373,  6379,  6389,  6397,  6421,  6427,  6449,
 6451,  6469,  6473,  6481,  6491,  6521,  6529,  6547,  6551,  6553,  6563,
 6569,  6571,  6577,  6581,  6599,  6607,  6619,  6637,  6653,  6659,  6661,
 6673,  6679,  6689,  6691,  6701,  6703,  6709,  6719,  6733,  6737,  6761,
 6763,  6779,  6781,  6791,  6793,  6803,  6823,  6827,  6829,  6833,  6841,
 6857,  6863,  6869,  6871,  6883,  6899,  6907,  6911,  6917,  6947,  6949,
 6959,  6961,  6967,  6971,  6977,  6983,  6991,  6997,  7001,  7013,  7019,
 7027,  7039,  7043,  7057,  7069,  7079,  7103,  7109,  7121,  7127,  7129,
 7151,  7159,  7177,  7187,  7193,  7207,  7211,  7213,  7219,  7229,  7237,
 7243,  7247,  7253,  7283,  7297,  7307,  7309,  7321,  7331,  7333,  7349,
 7351,  7369,  7393,  7411,  7417,  7433,  7451,  7457,  7459,  7477,  7481,
 7487,  7489,  7499,  7507,  7517,  7523,  7529,  7537,  7541,  7547,  7549,
 7559,  7561,  7573,  7577,  7583,  7589,  7591,  7603,  7607,  7621,  7639,
 7643,  7649,  7669,  7673,  7681,  7687,  7691,  7699,  7703,  7717,  7723,
 7727,  7741,  7753,  7757,  7759,  7789,  7793,  7817,  7823,  7829,  7841,
 7853,  7867,  7873,  7877,  7879,  7883,  7901,  7907,  7919,  7927,  7933,
 7937,  7949,  7951,  7963,  7993,  8009,  8011,  8017,  8039,  8053,  8059,
 8069,  8081,  8087,  8089,  8093,  8101,  8111,  8117,  8123,  8147,  8161,
 8167,  8171,  8179,  8191,  8209,  8219,  8221,  8231,  8233,  8237,  8243,
 8263,  8269,  8273,  8287,  8291,  8293,  8297,  8311,  8317,  8329,  8353,
 8363,  8369,  8377,  8387,  8389,  8419,  8423,  8429,  8431,  8443,  8447,
 8461,  8467,  8501,  8513,  8521,  8527,  8537,  8539,  8543,  8563,  8573,
 8581,  8597,  8599,  8609,  8623,  8627,  8629,  8641,  8647,  8663,  8669,
 8677,  8681,  8689,  8693,  8699,  8707,  8713,  8719,  8731,  8737,  8741,
 8747,  8753,  8761,  8779,  8783,  8803,  8807,  8819,  8821,  8831,  8837,
 8839,  8849,  8861,  8863,  8867,  8887,  8893,  8923,  8929,  8933,  8941,
 8951,  8963,  8969,  8971,  8999,  9001,  9007,  9011,  9013,  9029,  9041,
 9043,  9049,  9059,  9067,  9091,  9103,  9109,  9127,  9133,  9137,  9151,
 9157,  9161,  9173,  9181,  9187,  9199,  9203,  9209,  9221,  9227,  9239,
 9241,  9257,  9277,  9281,  9283,  9293,  9311,  9319,  9323,  9337,  9341,
 9343,  9349,  9371,  9377,  9391,  9397,  9403,  9413,  9419,  9421,  9431,
 9433,  9437,  9439,  9461,  9463,  9467,  9473,  9479,  9491,  9497,  9511,
 9521,  9533,  9539,  9547,  9551,  9587,  9601,  9613,  9619,  9623,  9629,
 9631,  9643,  9649,  9661,  9677,  9679,  9689,  9697,  9719,  9721,  9733,
 9739,  9743,  9749,  9767,  9769,  9781,  9787,  9791,  9803,  9811,  9817,
 9829,  9833,  9839,  9851,  9857,  9859,  9871,  9883,  9887,  9901,  9907,
 9923,  9929,  9931,  9941,  9949,  9967,  9973, 10007, 10009, 10037, 10039,
10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139,
10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243,
10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321,
10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433,
10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531,
10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651,
10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739,
10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861,
10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973,
10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083,
11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173,
11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287,
11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399,
11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497,
11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621,
11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743,
11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833,
11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939,
11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041,
12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143,
12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251,
12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347,
12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451,
12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539,
12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619,
12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721,
12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829,
12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941,
12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033,
13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147,
13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241,
13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339,
13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463,
13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591,
13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691,
13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763,
13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879,
13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997,
13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087,
14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243,
14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369,
14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449,
14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557,
14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657,
14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753,
14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843,
14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947,
14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077,
15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173,
15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271,
15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359,
15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451,
15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569,
15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661,
15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761,
15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877,
15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971,
15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073,
16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189,
16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319,
16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427,
16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547,
16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651,
16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759,
16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889,
16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987,
16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093,
17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203,
17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327,
17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417,
17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497,
17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609,
17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737,
17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851,
17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957,
17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049,
18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143,
18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251,
18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341,
18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443,
18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541,
18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701,
18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803,
18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973,
18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081,
19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213,
19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319,
19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427,
19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489,
19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597,
19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739,
19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843,
19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961,
19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047,
20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143,
20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249,
20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357,
20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477,
20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593,
20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719,
20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809,
20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939,
20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023,
21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149,
21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247,
21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379,
21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491,
21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569,
21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661,
21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773,
21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871,
21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003,
22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091,
22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171,
22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291,
22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433,
22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543,
22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651,
22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741,
22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861,
22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993,
23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059,
23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173,
23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293,
23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417,
23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557,
23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629,
23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747,
23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833,
23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929,
23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043,
24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113,
24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229,
24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379,
24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499,
24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631,
24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767,
24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889,
24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989,
25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121,
25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237,
25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343,
25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453,
25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583,
25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673,
25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793,
25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913,
25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003,
26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119,
26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237,
26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339,
26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437,
26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573,
26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693,
26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777,
26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881,
26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987,
26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091,
27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241,
27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367,
27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487,
27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631,
27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743,
27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809,
27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941,
27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031,
28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151,
28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289,
28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411,
28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537,
28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607,
28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687,
28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793,
28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909,
28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027,
29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153,
29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251,
29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383,
29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473,
29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599,
29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741,
29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867,
29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011,
30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113,
30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211,
30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323,
30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469,
30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577,
30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703,
30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829,
30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931,
30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051,
31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153,
31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247,
31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333,
31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489,
31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601,
31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723,
31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849,
31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003,
32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089,
32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203,
32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321,
32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401,
32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503,
32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603,
32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717,
32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833,
32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957,
32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049,
33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161,
33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301,
33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391,
33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503,
33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599,
33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703,
33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797,
33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911,
33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039,
34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183,
34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297,
34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381,
34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501,
34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607,
34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721,
34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843,
34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961,
34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089,
35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201,
35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323,
35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437,
35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537,
35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729,
35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837,
35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951,
35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037,
36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161,
36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293,
36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433,
36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529,
36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637,
36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739,
36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833,
36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929,
36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039,
37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181,
37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309,
37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409,
37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517,
37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591,
37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717,
37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871,
37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993,
37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153,
38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261,
38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351,
38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543,
38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651,
38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729,
38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851,
38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959,
38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097,
39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191,
39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301,
39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397,
39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521,
39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667,
39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779,
39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869,
39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989,
40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123,
40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231,
40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387,
40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507,
40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627,
40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771,
40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867,
40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993,
41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117,
41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203,
41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299,
41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443,
41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549,
41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647,
41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771,
41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893,
41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981,
41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083,
42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197,
42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307,
42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407,
42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487,
42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641,
42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719,
42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829,
42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943,
42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051,
43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201,
43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331,
43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487,
43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609,
43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721,
43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867,
43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987,
43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087,
44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189,
44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279,
44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453,
44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549,
44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657,
44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777,
44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893,
44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007,
45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139,
45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289,
45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389,
45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533,
45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659,
45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767,
45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887,
45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049,
46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153,
46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273,
46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411,
46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511,
46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639,
46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747,
46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853,
46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017,
47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137,
47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279,
47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381,
47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501,
47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599,
47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711,
47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809,
47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939,
47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073,
48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193,
48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337,
48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463,
48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541,
48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673,
48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787,
48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883,
48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031,
49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123,
49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223,
49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367,
49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463,
49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597,
49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711,
49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811,
49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937,
49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051,
50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131,
50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273,
50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383,
50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527,
50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647,
50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789,
50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923,
50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047,
51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193,
51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287,
51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419,
51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487,
51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599,
51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713,
51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829,
51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941,
51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067,
52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183,
52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301,
52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457,
52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571,
52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709,
52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817,
52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951,
52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069,
53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161,
53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279,
53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407,
53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551,
53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639,
53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777,
53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891,
53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001,
54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139,
54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293,
54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403,
54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499,
54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583,
54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713,
54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851,
54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979,
54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103,
55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219,
55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343,
55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501,
55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631,
55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717,
55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823,
55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927,
55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053,
56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171,
56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299,
56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437,
56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519,
56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633,
56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747,
56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857,
56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951,
56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073,
57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173,
57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271,
57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389,
57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557,
57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679,
57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781,
57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881,
57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027,
58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129,
58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217,
58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367,
58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451,
58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601,
58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727,
58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901,
58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997,
59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083,
59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197,
59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333,
59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417,
59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513,
59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651,
59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747,
59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921,
59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041,
60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149,
60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289,
60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427,
60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601,
60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679,
60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779,
60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917,
60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043,
61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211,
61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343,
61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471,
61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561,
61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667,
61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813,
61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961,
61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053,
62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171,
62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303,
62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467,
62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581,
62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687,
62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827,
62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969,
62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079,
63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241,
63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353,
63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443,
63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559,
63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649,
63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737,
63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841,
63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007,
64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151,
64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279,
64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433,
64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579,
64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679,
64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849,
64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951,
64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089,
65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173,
65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309,
65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423,
65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 };

}
/*
* Modular Reducer
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Modular_Reducer Constructor
*/
Modular_Reducer::Modular_Reducer(const BigInt& mod)
   {
   if(mod <= 0)
      throw Invalid_Argument("Modular_Reducer: modulus must be positive");

   modulus = mod;
   mod_words = modulus.sig_words();

   modulus_2 = Botan::square(modulus);

   mu = BigInt(BigInt::Power2, 2 * MP_WORD_BITS * mod_words) / modulus;
   }

/*
* Barrett Reduction
*/
BigInt Modular_Reducer::reduce(const BigInt& x) const
   {
   if(mod_words == 0)
      throw Invalid_State("Modular_Reducer: Never initalized");

   if(x.cmp(modulus, false) < 0)
      {
      if(x.is_negative())
         return x + modulus; // make positive
      return x;
      }
   else if(x.cmp(modulus_2, false) < 0)
      {
      BigInt t1 = x;
      t1.set_sign(BigInt::Positive);
      t1 >>= (MP_WORD_BITS * (mod_words - 1));
      t1 *= mu;

      t1 >>= (MP_WORD_BITS * (mod_words + 1));
      t1 *= modulus;

      t1.mask_bits(MP_WORD_BITS * (mod_words + 1));

      BigInt t2 = x;
      t2.set_sign(BigInt::Positive);
      t2.mask_bits(MP_WORD_BITS * (mod_words + 1));

      t2 -= t1;

      if(t2.is_negative())
         {
         BigInt b_to_k1(BigInt::Power2, MP_WORD_BITS * (mod_words + 1));
         t2 += b_to_k1;
         }

      while(t2 >= modulus)
         t2 -= modulus;

      if(x.is_positive())
         return t2;
      else
         return (modulus - t2);
      }
   else
      {
      // too big, fall back to normal division
      return (x % modulus);
      }
   }

}
/*
* Shanks-Tonnelli (RESSOL)
* (C) 2007-2008 Falko Strenzke, FlexSecure GmbH
* (C) 2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Shanks-Tonnelli algorithm
*/
BigInt ressol(const BigInt& a, const BigInt& p)
   {
   if(a < 0)
      throw Invalid_Argument("ressol(): a to solve for must be positive");
   if(p <= 1)
      throw Invalid_Argument("ressol(): prime must be > 1");

   if(a == 0)
      return 0;
   if(p == 2)
      return a;

   if(jacobi(a, p) != 1) // not a quadratic residue
      return -BigInt(1);

   if(p % 4 == 3)
      return power_mod(a, ((p+1) >> 2), p);

   size_t s = low_zero_bits(p - 1);
   BigInt q = p >> s;

   q -= 1;
   q >>= 1;

   Modular_Reducer mod_p(p);

   BigInt r = power_mod(a, q, p);
   BigInt n = mod_p.multiply(a, mod_p.square(r));
   r = mod_p.multiply(r, a);

   if(n == 1)
      return r;

   // find random non quadratic residue z
   BigInt z = 2;
   while(jacobi(z, p) == 1) // while z quadratic residue
      ++z;

   BigInt c = power_mod(z, (q << 1) + 1, p);

   while(n > 1)
      {
      q = n;

      size_t i = 0;
      while(q != 1)
         {
         q = mod_p.square(q);
         ++i;
         }

      if(s <= i)
         return -BigInt(1);

      c = power_mod(c, BigInt(BigInt::Power2, s-i-1), p);
      r = mod_p.multiply(r, c);
      c = mod_p.square(c);
      n = mod_p.multiply(n, c);
      s = i;
      }

   return r;
   }

}
/*
* No-Op Mutex Factory
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* No-Op Mutex Factory
*/
Mutex* Noop_Mutex_Factory::make()
   {
   class Noop_Mutex : public Mutex
      {
      public:
         class Mutex_State_Error : public Internal_Error
            {
            public:
               Mutex_State_Error(const std::string& where) :
                  Internal_Error("Noop_Mutex::" + where + ": " +
                                 "Mutex is already " + where + "ed") {}
            };

         void lock()
            {
            if(locked)
               throw Mutex_State_Error("lock");
            locked = true;
            }

         void unlock()
            {
            if(!locked)
               throw Mutex_State_Error("unlock");
            locked = false;
            }

         Noop_Mutex() { locked = false; }
      private:
         bool locked;
      };

   return new Noop_Mutex;
   }

}

#ifdef Q_OS_WIN
/*
* Win32 Mutex
* (C) 2006 Luca Piccarreta
*     2006-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <windows.h>

namespace Botan {

/*
* Win32 Mutex Factory
*/
Mutex* Win32_Mutex_Factory::make()
   {
   class Win32_Mutex : public Mutex
      {
      public:
         void lock() { EnterCriticalSection(&mutex); }
         void unlock() { LeaveCriticalSection(&mutex); }

         Win32_Mutex() { InitializeCriticalSection(&mutex); }
         ~Win32_Mutex() { DeleteCriticalSection(&mutex); }
      private:
         CRITICAL_SECTION mutex;
      };

   return new Win32_Mutex();
   }

}
#endif

#ifdef Q_OS_UNIX
/*
* Pthread Mutex
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#ifndef _POSIX_C_SOURCE
  #define _POSIX_C_SOURCE 199506
#endif

#include <pthread.h>

namespace Botan {

/*
* Pthread Mutex Factory
*/
Mutex* Pthread_Mutex_Factory::make()
   {

   class Pthread_Mutex : public Mutex
      {
      public:
         void lock()
            {
            if(pthread_mutex_lock(&mutex) != 0)
               throw Invalid_State("Pthread_Mutex::lock: Error occured");
            }

         void unlock()
            {
            if(pthread_mutex_unlock(&mutex) != 0)
               throw Invalid_State("Pthread_Mutex::unlock: Error occured");
            }

         Pthread_Mutex()
            {
            if(pthread_mutex_init(&mutex, 0) != 0)
               throw Invalid_State("Pthread_Mutex: initialization failed");
            }

         ~Pthread_Mutex()
            {
            if(pthread_mutex_destroy(&mutex) != 0)
               throw Invalid_State("~Pthread_Mutex: mutex is still locked");
            }
      private:
         pthread_mutex_t mutex;
      };

   return new Pthread_Mutex();
   }

}
#endif

/*
* Bcrypt Password Hashing
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

std::string bcrypt_base64_encode(const byte input[], size_t length)
   {
   // Bcrypt uses a non-standard base64 alphabet
   const byte OPENBSD_BASE64_SUB[256] = {
      0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39,
      0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45,
      0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
      0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
      0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
      0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80
   };

   std::string b64 = base64_encode(input, length);

   while(b64.size() && b64[b64.size()-1] == '=')
      b64 = b64.substr(0, b64.size() - 1);

   for(size_t i = 0; i != b64.size(); ++i)
      b64[i] = OPENBSD_BASE64_SUB[static_cast<byte>(b64[i])];

   return b64;
   }

MemoryVector<byte> bcrypt_base64_decode(std::string input)
   {
   const byte OPENBSD_BASE64_SUB[256] = {
      0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42,
      0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
      0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
      0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
      0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
      0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
      0x80, 0x80, 0x80, 0x80
   };

   for(size_t i = 0; i != input.size(); ++i)
      input[i] = OPENBSD_BASE64_SUB[static_cast<byte>(input[i])];

   return base64_decode(input);
   }

std::string make_bcrypt(const std::string& pass,
                        const MemoryRegion<byte>& salt,
                        u16bit work_factor)
   {
   const byte magic[24] = {
      0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42,
      0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53,
      0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74
   };

   MemoryVector<byte> ctext(magic, 24);

   Blowfish blowfish;

   // Include the trailing NULL byte
   blowfish.eks_key_schedule(reinterpret_cast<const byte*>(pass.c_str()),
                             pass.length() + 1,
                             salt,
                             work_factor);

   for(size_t i = 0; i != 64; ++i)
      blowfish.encrypt_n(&ctext[0], &ctext[0], 3);

   std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size());

   return "$2a$" + to_string(work_factor, 2) + "$" + salt_b64.substr(0, 22) +
             bcrypt_base64_encode(&ctext[0], ctext.size() - 1);
   }

}

std::string generate_bcrypt(const std::string& pass,
                            RandomNumberGenerator& rng,
                            u16bit work_factor)
   {
   return make_bcrypt(pass, rng.random_vec(16), work_factor);
   }

bool check_bcrypt(const std::string& pass, const std::string& hash)
   {
   if(hash.size() != 60 ||
      hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' ||
      hash[3] != '$' || hash[6] != '$')
      {
      return false;
      }

   const u16bit workfactor = to_u32bit(hash.substr(4, 2));

   MemoryVector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22));

   const std::string compare = make_bcrypt(pass, salt, workfactor);

   return (hash == compare);
   }

}
/*
* Passhash9 Password Hashing
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

const std::string MAGIC_PREFIX = "$9$";

const size_t WORKFACTOR_BYTES = 2;
const size_t ALGID_BYTES = 1;
const size_t SALT_BYTES = 12; // 96 bits of salt
const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output

const size_t WORK_FACTOR_SCALE = 10000;

MessageAuthenticationCode* get_pbkdf_prf(byte alg_id)
   {
   Algorithm_Factory& af = global_state().algorithm_factory();

   try
      {
      if(alg_id == 0)
         return af.make_mac("HMAC(SHA-1)");
      else if(alg_id == 1)
         return af.make_mac("HMAC(SHA-256)");
      else if(alg_id == 2)
         return af.make_mac("CMAC(Blowfish)");
      }
   catch(Algorithm_Not_Found) {}

   return 0;
   }

}

std::string generate_passhash9(const std::string& pass,
                               RandomNumberGenerator& rng,
                               u16bit work_factor,
                               byte alg_id)
   {
   MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id);

   if(!prf)
      throw Invalid_Argument("Passhash9: Algorithm id " + to_string(alg_id) +
                             " is not defined");

   PKCS5_PBKDF2 kdf(prf); // takes ownership of pointer

   SecureVector<byte> salt(SALT_BYTES);
   rng.randomize(&salt[0], salt.size());

   const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;

   SecureVector<byte> pbkdf2_output =
      kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
                     pass,
                     &salt[0], salt.size(),
                     kdf_iterations).bits_of();

   Pipe pipe(new Base64_Encoder);
   pipe.start_msg();
   pipe.write(alg_id);
   pipe.write(get_byte(0, work_factor));
   pipe.write(get_byte(1, work_factor));
   pipe.write(salt);
   pipe.write(pbkdf2_output);
   pipe.end_msg();

   return MAGIC_PREFIX + pipe.read_all_as_string();
   }

bool check_passhash9(const std::string& pass, const std::string& hash)
   {
   const size_t BINARY_LENGTH =
     ALGID_BYTES +
     WORKFACTOR_BYTES +
     PASSHASH9_PBKDF_OUTPUT_LEN +
     SALT_BYTES;

   const size_t BASE64_LENGTH =
      MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;

   if(hash.size() != BASE64_LENGTH)
      return false;

   for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
      if(hash[i] != MAGIC_PREFIX[i])
         return false;

   Pipe pipe(new Base64_Decoder);
   pipe.start_msg();
   pipe.write(hash.c_str() + MAGIC_PREFIX.size());
   pipe.end_msg();

   SecureVector<byte> bin = pipe.read_all();

   if(bin.size() != BINARY_LENGTH)
      return false;

   byte alg_id = bin[0];

   const size_t kdf_iterations =
      WORK_FACTOR_SCALE * load_be<u16bit>(&bin[ALGID_BYTES], 0);

   if(kdf_iterations == 0)
      return false;

   MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id);

   if(pbkdf_prf == 0)
      return false; // unknown algorithm, reject

   PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer

   SecureVector<byte> cmp = kdf.derive_key(
      PASSHASH9_PBKDF_OUTPUT_LEN,
      pass,
      &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
      kdf_iterations).bits_of();

   return same_mem(&cmp[0],
                   &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
                   PASSHASH9_PBKDF_OUTPUT_LEN);
   }

}
/*
* PBE Retrieval
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_PBE_PKCS_V15)
#endif

#if defined(BOTAN_HAS_PBE_PKCS_V20)
#endif

namespace Botan {

/*
* Get an encryption PBE, set new parameters
*/
PBE* get_pbe(const std::string& algo_spec)
   {
   SCAN_Name request(algo_spec);

   const std::string pbe = request.algo_name();
   std::string digest_name = request.arg(0);
   const std::string cipher = request.arg(1);

   std::vector<std::string> cipher_spec = split_on(cipher, '/');
   if(cipher_spec.size() != 2)
      throw Invalid_Argument("PBE: Invalid cipher spec " + cipher);

   const std::string cipher_algo = global_state().deref_alias(cipher_spec[0]);
   const std::string cipher_mode = cipher_spec[1];

   if(cipher_mode != "CBC")
      throw Invalid_Argument("PBE: Invalid cipher mode " + cipher);

   Algorithm_Factory& af = global_state().algorithm_factory();

   const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo);
   if(!block_cipher)
      throw Algorithm_Not_Found(cipher_algo);

   const HashFunction* hash_function = af.prototype_hash_function(digest_name);
   if(!hash_function)
      throw Algorithm_Not_Found(digest_name);

   if(request.arg_count() != 2)
      throw Invalid_Algorithm_Name(algo_spec);

#if defined(BOTAN_HAS_PBE_PKCS_V15)
   if(pbe == "PBE-PKCS5v15")
      return new PBE_PKCS5v15(block_cipher->clone(),
                              hash_function->clone(),
                              ENCRYPTION);
#endif

#if defined(BOTAN_HAS_PBE_PKCS_V20)
   if(pbe == "PBE-PKCS5v20")
      return new PBE_PKCS5v20(block_cipher->clone(),
                              hash_function->clone());
#endif

   throw Algorithm_Not_Found(algo_spec);
   }

/*
* Get a decryption PBE, decode parameters
*/
PBE* get_pbe(const OID& pbe_oid, DataSource& params)
   {
   SCAN_Name request(OIDS::lookup(pbe_oid));

   const std::string pbe = request.algo_name();

#if defined(BOTAN_HAS_PBE_PKCS_V15)
   if(pbe == "PBE-PKCS5v15")
      {
      if(request.arg_count() != 2)
         throw Invalid_Algorithm_Name(request.as_string());

      std::string digest_name = request.arg(0);
      const std::string cipher = request.arg(1);

      std::vector<std::string> cipher_spec = split_on(cipher, '/');
      if(cipher_spec.size() != 2)
         throw Invalid_Argument("PBE: Invalid cipher spec " + cipher);

      const std::string cipher_algo = global_state().deref_alias(cipher_spec[0]);
      const std::string cipher_mode = cipher_spec[1];

      if(cipher_mode != "CBC")
         throw Invalid_Argument("PBE: Invalid cipher mode " + cipher);

      Algorithm_Factory& af = global_state().algorithm_factory();

      const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo);
      if(!block_cipher)
         throw Algorithm_Not_Found(cipher_algo);

      const HashFunction* hash_function =
         af.prototype_hash_function(digest_name);

      if(!hash_function)
         throw Algorithm_Not_Found(digest_name);

      PBE* pbe = new PBE_PKCS5v15(block_cipher->clone(),
                                  hash_function->clone(),
                                  DECRYPTION);
      pbe->decode_params(params);
      return pbe;
      }
#endif

#if defined(BOTAN_HAS_PBE_PKCS_V20)
   if(pbe == "PBE-PKCS5v20")
      return new PBE_PKCS5v20(params);
#endif

   throw Algorithm_Not_Found(pbe_oid.as_string());
   }

}
/*
* PKCS #5 PBES1
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Encrypt some bytes using PBES1
*/
void PBE_PKCS5v15::write(const byte input[], size_t length)
   {
   pipe.write(input, length);
   flush_pipe(true);
   }

/*
* Start encrypting with PBES1
*/
void PBE_PKCS5v15::start_msg()
   {
   if(direction == ENCRYPTION)
      pipe.append(new CBC_Encryption(block_cipher->clone(),
                                     new PKCS7_Padding,
                                     key, iv));
   else
      pipe.append(new CBC_Decryption(block_cipher->clone(),
                                     new PKCS7_Padding,
                                     key, iv));

   pipe.start_msg();
   if(pipe.message_count() > 1)
      pipe.set_default_msg(pipe.default_msg() + 1);
   }

/*
* Finish encrypting with PBES1
*/
void PBE_PKCS5v15::end_msg()
   {
   pipe.end_msg();
   flush_pipe(false);
   pipe.reset();
   }

/*
* Flush the pipe
*/
void PBE_PKCS5v15::flush_pipe(bool safe_to_skip)
   {
   if(safe_to_skip && pipe.remaining() < 64)
      return;

   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(pipe.remaining())
      {
      size_t got = pipe.read(&buffer[0], buffer.size());
      send(buffer, got);
      }
   }

/*
* Set the passphrase to use
*/
void PBE_PKCS5v15::set_key(const std::string& passphrase)
   {
   PKCS5_PBKDF1 pbkdf(hash_function->clone());

   SecureVector<byte> key_and_iv = pbkdf.derive_key(16, passphrase,
                                                    &salt[0], salt.size(),
                                                    iterations).bits_of();

   key.resize(8);
   iv.resize(8);
   copy_mem(&key[0], &key_and_iv[0], 8);
   copy_mem(&iv[0], &key_and_iv[8], 8);
   }

/*
* Create a new set of PBES1 parameters
*/
void PBE_PKCS5v15::new_params(RandomNumberGenerator& rng)
   {
   iterations = 10000;
   salt = rng.random_vec(8);
   }

/*
* Encode PKCS#5 PBES1 parameters
*/
MemoryVector<byte> PBE_PKCS5v15::encode_params() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode(salt, OCTET_STRING)
         .encode(iterations)
      .end_cons()
   .get_contents();
   }

/*
* Decode PKCS#5 PBES1 parameters
*/
void PBE_PKCS5v15::decode_params(DataSource& source)
   {
   BER_Decoder(source)
      .start_cons(SEQUENCE)
         .decode(salt, OCTET_STRING)
         .decode(iterations)
         .verify_end()
      .end_cons();

   if(salt.size() != 8)
      throw Decoding_Error("PBES1: Encoded salt is not 8 octets");
   }

/*
* Return an OID for this PBES1 type
*/
OID PBE_PKCS5v15::get_oid() const
   {
   const OID base_pbes1_oid("1.2.840.113549.1.5");

   const std::string cipher = block_cipher->name();
   const std::string digest = hash_function->name();

   if(cipher == "DES" && digest == "MD2")
      return (base_pbes1_oid + 1);
   else if(cipher == "DES" && digest == "MD5")
      return (base_pbes1_oid + 3);
   else if(cipher == "DES" && digest == "SHA-160")
      return (base_pbes1_oid + 10);
   else if(cipher == "RC2" && digest == "MD2")
      return (base_pbes1_oid + 4);
   else if(cipher == "RC2" && digest == "MD5")
      return (base_pbes1_oid + 6);
   else if(cipher == "RC2" && digest == "SHA-160")
      return (base_pbes1_oid + 11);
   else
      throw Internal_Error("PBE-PKCS5 v1.5: get_oid() has run out of options");
   }

std::string PBE_PKCS5v15::name() const
   {
   return "PBE-PKCS5v15(" + block_cipher->name() + "," +
                            hash_function->name() + ")";
   }

/*
* PKCS#5 v1.5 PBE Constructor
*/
PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher,
                           HashFunction* hash,
                           Cipher_Dir dir) :
   direction(dir), block_cipher(cipher), hash_function(hash)
   {
   if(cipher->name() != "DES" && cipher->name() != "RC2")
      {
      throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " +
                             cipher->name());
      }

   if(hash->name() != "MD2" && hash->name() != "MD5" &&
      hash->name() != "SHA-160")
      {
      throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " +
                             hash->name());
      }
   }

PBE_PKCS5v15::~PBE_PKCS5v15()
   {
   delete block_cipher;
   delete hash_function;
   }

}
/*
* PKCS #5 PBES2
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <memory>

namespace Botan {

/*
* Encrypt some bytes using PBES2
*/
void PBE_PKCS5v20::write(const byte input[], size_t length)
   {
   pipe.write(input, length);
   flush_pipe(true);
   }

/*
* Start encrypting with PBES2
*/
void PBE_PKCS5v20::start_msg()
   {
   if(direction == ENCRYPTION)
      pipe.append(new CBC_Encryption(block_cipher->clone(),
                                     new PKCS7_Padding,
                                     key, iv));
   else
      pipe.append(new CBC_Decryption(block_cipher->clone(),
                                     new PKCS7_Padding,
                                     key, iv));

   pipe.start_msg();
   if(pipe.message_count() > 1)
      pipe.set_default_msg(pipe.default_msg() + 1);
   }

/*
* Finish encrypting with PBES2
*/
void PBE_PKCS5v20::end_msg()
   {
   pipe.end_msg();
   flush_pipe(false);
   pipe.reset();
   }

/*
* Flush the pipe
*/
void PBE_PKCS5v20::flush_pipe(bool safe_to_skip)
   {
   if(safe_to_skip && pipe.remaining() < 64)
      return;

   SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
   while(pipe.remaining())
      {
      size_t got = pipe.read(&buffer[0], buffer.size());
      send(buffer, got);
      }
   }

/*
* Set the passphrase to use
*/
void PBE_PKCS5v20::set_key(const std::string& passphrase)
   {
   PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone()));

   key = pbkdf.derive_key(key_length, passphrase,
                          &salt[0], salt.size(),
                          iterations).bits_of();
   }

/*
* Create a new set of PBES2 parameters
*/
void PBE_PKCS5v20::new_params(RandomNumberGenerator& rng)
   {
   iterations = 10000;
   key_length = block_cipher->maximum_keylength();

   salt = rng.random_vec(12);
   iv = rng.random_vec(block_cipher->block_size());
   }

/*
* Encode PKCS#5 PBES2 parameters
*/
MemoryVector<byte> PBE_PKCS5v20::encode_params() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
      .encode(
         AlgorithmIdentifier("PKCS5.PBKDF2",
            DER_Encoder()
               .start_cons(SEQUENCE)
                  .encode(salt, OCTET_STRING)
                  .encode(iterations)
                  .encode(key_length)
               .end_cons()
            .get_contents()
            )
         )
      .encode(
         AlgorithmIdentifier(block_cipher->name() + "/CBC",
            DER_Encoder()
               .encode(iv, OCTET_STRING)
            .get_contents()
            )
         )
      .end_cons()
      .get_contents();
   }

/*
* Decode PKCS#5 PBES2 parameters
*/
void PBE_PKCS5v20::decode_params(DataSource& source)
   {
   AlgorithmIdentifier kdf_algo, enc_algo;

   BER_Decoder(source)
      .start_cons(SEQUENCE)
         .decode(kdf_algo)
         .decode(enc_algo)
         .verify_end()
      .end_cons();

   if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2"))
      {
      BER_Decoder(kdf_algo.parameters)
         .start_cons(SEQUENCE)
            .decode(salt, OCTET_STRING)
            .decode(iterations)
            .decode_optional(key_length, INTEGER, UNIVERSAL)
            .verify_end()
         .end_cons();
      }
   else
      throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
                           kdf_algo.oid.as_string());

   Algorithm_Factory& af = global_state().algorithm_factory();

   std::string cipher = OIDS::lookup(enc_algo.oid);
   std::vector<std::string> cipher_spec = split_on(cipher, '/');
   if(cipher_spec.size() != 2)
      throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);

   if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC")
      throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " +
                           cipher);

   BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();

   block_cipher = af.make_block_cipher(cipher_spec[0]);
   hash_function = af.make_hash_function("SHA-160");

   if(key_length == 0)
      key_length = block_cipher->maximum_keylength();

   if(salt.size() < 8)
      throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
   }

/*
* Return an OID for PBES2
*/
OID PBE_PKCS5v20::get_oid() const
   {
   return OIDS::lookup("PBE-PKCS5v20");
   }

/*
* Check if this is a known PBES2 cipher
*/
bool PBE_PKCS5v20::known_cipher(const std::string& algo)
   {
   if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256")
      return true;
   if(algo == "DES" || algo == "TripleDES")
      return true;
   return false;
   }

std::string PBE_PKCS5v20::name() const
   {
   return "PBE-PKCS5v20(" + block_cipher->name() + "," +
                            hash_function->name() + ")";
   }

/*
* PKCS#5 v2.0 PBE Constructor
*/
PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher,
                           HashFunction* digest) :
   direction(ENCRYPTION), block_cipher(cipher), hash_function(digest)
   {
   if(!known_cipher(block_cipher->name()))
      throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher->name());
   if(hash_function->name() != "SHA-160")
      throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest->name());
   }

/*
* PKCS#5 v2.0 PBE Constructor
*/
PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION)
   {
   hash_function = 0;
   block_cipher = 0;
   decode_params(params);
   }

PBE_PKCS5v20::~PBE_PKCS5v20()
   {
   delete hash_function;
   delete block_cipher;
   }

}
/*
* PBKDF1
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Return a PKCS#5 PBKDF1 derived key
*/
OctetString PKCS5_PBKDF1::derive_key(size_t key_len,
                                     const std::string& passphrase,
                                     const byte salt[], size_t salt_size,
                                     size_t iterations) const
   {
   if(iterations == 0)
      throw Invalid_Argument("PKCS5_PBKDF1: Invalid iteration count");

   if(key_len > hash->output_length())
      throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long");

   hash->update(passphrase);
   hash->update(salt, salt_size);
   SecureVector<byte> key = hash->final();

   for(size_t j = 1; j != iterations; ++j)
      {
      hash->update(key);
      hash->final(&key[0]);
      }

   return OctetString(&key[0], std::min<size_t>(key_len, key.size()));
   }

}
/*
* PBKDF2
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Return a PKCS #5 PBKDF2 derived key
*/
OctetString PKCS5_PBKDF2::derive_key(size_t key_len,
                                     const std::string& passphrase,
                                     const byte salt[], size_t salt_size,
                                     size_t iterations) const
   {
   if(iterations == 0)
      throw Invalid_Argument("PKCS#5 PBKDF2: Invalid iteration count");

   try
      {
      mac->set_key(reinterpret_cast<const byte*>(passphrase.data()),
                   passphrase.length());
      }
   catch(Invalid_Key_Length)
      {
      throw Exception(name() + " cannot accept passphrases of length " +
                      to_string(passphrase.length()));
      }

   SecureVector<byte> key(key_len);

   byte* T = &key[0];

   SecureVector<byte> U(mac->output_length());

   u32bit counter = 1;
   while(key_len)
      {
      size_t T_size = std::min<size_t>(mac->output_length(), key_len);

      mac->update(salt, salt_size);
      mac->update_be(counter);
      mac->final(&U[0]);

      xor_buf(T, U, T_size);

      for(size_t j = 1; j != iterations; ++j)
         {
         mac->update(U);
         mac->final(&U[0]);
         xor_buf(T, U, T_size);
         }

      key_len -= T_size;
      T += T_size;
      ++counter;
      }

   return key;
   }

}
/*
* OpenPGP S2K
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Derive a key using the OpenPGP S2K algorithm
*/
OctetString OpenPGP_S2K::derive_key(size_t key_len,
                                    const std::string& passphrase,
                                    const byte salt_buf[], size_t salt_size,
                                    size_t iterations) const
   {
   SecureVector<byte> key(key_len), hash_buf;

   size_t pass = 0, generated = 0,
          total_size = passphrase.size() + salt_size;
   size_t to_hash = std::max(iterations, total_size);

   hash->clear();
   while(key_len > generated)
      {
      for(size_t j = 0; j != pass; ++j)
         hash->update(0);

      size_t left = to_hash;
      while(left >= total_size)
         {
         hash->update(salt_buf, salt_size);
         hash->update(passphrase);
         left -= total_size;
         }
      if(left <= salt_size)
         hash->update(salt_buf, left);
      else
         {
         hash->update(salt_buf, salt_size);
         left -= salt_size;
         hash->update(reinterpret_cast<const byte*>(passphrase.data()), left);
         }

      hash_buf = hash->final();
      key.copy(generated, &hash_buf[0], hash->output_length());
      generated += hash->output_length();
      ++pass;
      }

   return key;
   }

}
/*
* EME Base Class
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Encode a message
*/
SecureVector<byte> EME::encode(const byte msg[], size_t msg_len,
                               size_t key_bits,
                               RandomNumberGenerator& rng) const
   {
   return pad(msg, msg_len, key_bits, rng);
   }

/*
* Encode a message
*/
SecureVector<byte> EME::encode(const MemoryRegion<byte>& msg,
                               size_t key_bits,
                               RandomNumberGenerator& rng) const
   {
   return pad(&msg[0], msg.size(), key_bits, rng);
   }

/*
* Decode a message
*/
SecureVector<byte> EME::decode(const byte msg[], size_t msg_len,
                               size_t key_bits) const
   {
   return unpad(msg, msg_len, key_bits);
   }

/*
* Decode a message
*/
SecureVector<byte> EME::decode(const MemoryRegion<byte>& msg,
                               size_t key_bits) const
   {
   return unpad(&msg[0], msg.size(), key_bits);
   }

}
/*
* EME1 (aka OAEP)
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

/*
* EME1 Pad Operation
*/
SecureVector<byte> EME1::pad(const byte in[], size_t in_length,
                             size_t key_length,
                             RandomNumberGenerator& rng) const
   {
   key_length /= 8;

   if(in_length > key_length - 2*Phash.size() - 1)
      throw Invalid_Argument("EME1: Input is too large");

   SecureVector<byte> out(key_length);

   rng.randomize(&out[0], Phash.size());

   out.copy(Phash.size(), &Phash[0], Phash.size());
   out[out.size() - in_length - 1] = 0x01;
   out.copy(out.size() - in_length, in, in_length);

   mgf->mask(&out[0], Phash.size(),
             &out[Phash.size()], out.size() - Phash.size());

   mgf->mask(&out[Phash.size()], out.size() - Phash.size(),
             &out[0], Phash.size());

   return out;
   }

/*
* EME1 Unpad Operation
*/
SecureVector<byte> EME1::unpad(const byte in[], size_t in_length,
                               size_t key_length) const
   {
   /*
   Must be careful about error messages here; if an attacker can
   distinguish them, it is easy to use the differences as an oracle to
   find the secret key, as described in "A Chosen Ciphertext Attack on
   RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
   PKCS #1 v2.0", James Manger, Crypto 2001

   Also have to be careful about timing attacks! Pointed out by Falko
   Strenzke.
   */

   key_length /= 8;

   // Invalid input: truncate to zero length input, causing later
   // checks to fail
   if(in_length > key_length)
      in_length = 0;

   SecureVector<byte> input(key_length);
   input.copy(key_length - in_length, in, in_length);

   mgf->mask(&input[Phash.size()], input.size() - Phash.size(),
             &input[0], Phash.size());
   mgf->mask(&input[0], Phash.size(),
             &input[Phash.size()], input.size() - Phash.size());

   bool waiting_for_delim = true;
   bool bad_input = false;
   size_t delim_idx = 2 * Phash.size();

   /*
   * GCC 4.5 on x86-64 compiles this in a way that is still vunerable
   * to timing analysis. Other compilers, or GCC on other platforms,
   * may or may not.
   */
   for(size_t i = delim_idx; i != input.size(); ++i)
      {
      const bool zero_p = !input[i];
      const bool one_p = input[i] == 0x01;

      const bool add_1 = waiting_for_delim && zero_p;

      bad_input |= waiting_for_delim && !(zero_p || one_p);

      delim_idx += add_1;

      waiting_for_delim &= zero_p;
      }

   // If we never saw any non-zero byte, then it's not valid input
   bad_input |= waiting_for_delim;

   bad_input |= !same_mem(&input[Phash.size()], &Phash[0], Phash.size());

   if(bad_input)
      throw Decoding_Error("Invalid EME1 encoding");

   return SecureVector<byte>(input + delim_idx + 1,
                             input.size() - delim_idx - 1);
   }

/*
* Return the max input size for a given key size
*/
size_t EME1::maximum_input_size(size_t keybits) const
   {
   if(keybits / 8 > 2*Phash.size() + 1)
      return ((keybits / 8) - 2*Phash.size() - 1);
   else
      return 0;
   }

/*
* EME1 Constructor
*/
EME1::EME1(HashFunction* hash, const std::string& P)
   {
   Phash = hash->process(P);
   mgf = new MGF1(hash);
   }

}
/*
* PKCS1 EME
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* PKCS1 Pad Operation
*/
SecureVector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen,
                                     size_t olen,
                                     RandomNumberGenerator& rng) const
   {
   olen /= 8;

   if(olen < 10)
      throw Encoding_Error("PKCS1: Output space too small");
   if(inlen > olen - 10)
      throw Encoding_Error("PKCS1: Input is too large");

   SecureVector<byte> out(olen);

   out[0] = 0x02;
   for(size_t j = 1; j != olen - inlen - 1; ++j)
      while(out[j] == 0)
         out[j] = rng.next_byte();
   out.copy(olen - inlen, in, inlen);

   return out;
   }

/*
* PKCS1 Unpad Operation
*/
SecureVector<byte> EME_PKCS1v15::unpad(const byte in[], size_t inlen,
                                       size_t key_len) const
   {
   if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02)
      throw Decoding_Error("PKCS1::unpad");

   size_t seperator = 0;
   for(size_t j = 0; j != inlen; ++j)
      if(in[j] == 0)
         {
         seperator = j;
         break;
         }
   if(seperator < 9)
      throw Decoding_Error("PKCS1::unpad");

   return SecureVector<byte>(in + seperator + 1, inlen - seperator - 1);
   }

/*
* Return the max input size for a given key size
*/
size_t EME_PKCS1v15::maximum_input_size(size_t keybits) const
   {
   if(keybits / 8 > 10)
      return ((keybits / 8) - 10);
   else
      return 0;
   }

}
/*
* EMSA1
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

SecureVector<byte> emsa1_encoding(const MemoryRegion<byte>& msg,
                                  size_t output_bits)
   {
   if(8*msg.size() <= output_bits)
      return msg;

   size_t shift = 8*msg.size() - output_bits;

   size_t byte_shift = shift / 8, bit_shift = shift % 8;
   SecureVector<byte> digest(msg.size() - byte_shift);

   for(size_t j = 0; j != msg.size() - byte_shift; ++j)
      digest[j] = msg[j];

   if(bit_shift)
      {
      byte carry = 0;
      for(size_t j = 0; j != digest.size(); ++j)
         {
         byte temp = digest[j];
         digest[j] = (temp >> bit_shift) | carry;
         carry = (temp << (8 - bit_shift));
         }
      }
   return digest;
   }

}

/*
* EMSA1 Update Operation
*/
void EMSA1::update(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA1::raw_data()
   {
   return hash->final();
   }

/*
* EMSA1 Encode Operation
*/
SecureVector<byte> EMSA1::encoding_of(const MemoryRegion<byte>& msg,
                                      size_t output_bits,
                                      RandomNumberGenerator&)
   {
   if(msg.size() != hash->output_length())
      throw Encoding_Error("EMSA1::encoding_of: Invalid size for input");
   return emsa1_encoding(msg, output_bits);
   }

/*
* EMSA1 Decode/Verify Operation
*/
bool EMSA1::verify(const MemoryRegion<byte>& coded,
                   const MemoryRegion<byte>& raw, size_t key_bits)
   {
   try {
      if(raw.size() != hash->output_length())
         throw Encoding_Error("EMSA1::encoding_of: Invalid size for input");

      SecureVector<byte> our_coding = emsa1_encoding(raw, key_bits);

      if(our_coding == coded) return true;
      if(our_coding[0] != 0) return false;
      if(our_coding.size() <= coded.size()) return false;

      size_t offset = 0;
      while(our_coding[offset] == 0 && offset < our_coding.size())
         ++offset;
      if(our_coding.size() - offset != coded.size())
         return false;

      for(size_t j = 0; j != coded.size(); ++j)
         if(coded[j] != our_coding[j+offset])
            return false;

      return true;
      }
   catch(Invalid_Argument)
      {
      return false;
      }
   }

}
/*
* EMSA1 BSI
* (C) 1999-2008 Jack Lloyd
*     2008 Falko Strenzke, FlexSecure GmbH
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* EMSA1 BSI Encode Operation
*/
SecureVector<byte> EMSA1_BSI::encoding_of(const MemoryRegion<byte>& msg,
                                          size_t output_bits,
                                          RandomNumberGenerator&)
   {
   if(msg.size() != hash_ptr()->output_length())
      throw Encoding_Error("EMSA1_BSI::encoding_of: Invalid size for input");

   if(8*msg.size() <= output_bits)
      return msg;

   throw Encoding_Error("EMSA1_BSI::encoding_of: max key input size exceeded");
   }

}
/*
* EMSA2
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* EMSA2 Encode Operation
*/
SecureVector<byte> emsa2_encoding(const MemoryRegion<byte>& msg,
                                  size_t output_bits,
                                  const MemoryRegion<byte>& empty_hash,
                                  byte hash_id)
   {
   const size_t HASH_SIZE = empty_hash.size();

   size_t output_length = (output_bits + 1) / 8;

   if(msg.size() != HASH_SIZE)
      throw Encoding_Error("EMSA2::encoding_of: Bad input length");
   if(output_length < HASH_SIZE + 4)
      throw Encoding_Error("EMSA2::encoding_of: Output length is too small");

   bool empty = true;
   for(size_t j = 0; j != HASH_SIZE; ++j)
      if(empty_hash[j] != msg[j])
         empty = false;

   SecureVector<byte> output(output_length);

   output[0] = (empty ? 0x4B : 0x6B);
   output[output_length - 3 - HASH_SIZE] = 0xBA;
   set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB);
   output.copy(output_length - (HASH_SIZE + 2), &msg[0], msg.size());
   output[output_length-2] = hash_id;
   output[output_length-1] = 0xCC;

   return output;
   }

}

/*
* EMSA2 Update Operation
*/
void EMSA2::update(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA2::raw_data()
   {
   return hash->final();
   }

/*
* EMSA2 Encode Operation
*/
SecureVector<byte> EMSA2::encoding_of(const MemoryRegion<byte>& msg,
                                      size_t output_bits,
                                      RandomNumberGenerator&)
   {
   return emsa2_encoding(msg, output_bits, empty_hash, hash_id);
   }

/*
* EMSA2 Verify Operation
*/
bool EMSA2::verify(const MemoryRegion<byte>& coded,
                   const MemoryRegion<byte>& raw,
                   size_t key_bits)
   {
   try
      {
      return (coded == emsa2_encoding(raw, key_bits,
                                      empty_hash, hash_id));
      }
   catch(...)
      {
      return false;
      }
   }

/*
* EMSA2 Constructor
*/
EMSA2::EMSA2(HashFunction* hash_in) : hash(hash_in)
   {
   empty_hash = hash->final();

   hash_id = ieee1363_hash_id(hash->name());

   if(hash_id == 0)
      {
      delete hash;
      throw Encoding_Error("EMSA2 cannot be used with " + hash->name());
      }
   }

}
/*
* EMSA3 and EMSA3_Raw
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* EMSA3 Encode Operation
*/
SecureVector<byte> emsa3_encoding(const MemoryRegion<byte>& msg,
                                  size_t output_bits,
                                  const byte hash_id[],
                                  size_t hash_id_length)
   {
   size_t output_length = output_bits / 8;
   if(output_length < hash_id_length + msg.size() + 10)
      throw Encoding_Error("emsa3_encoding: Output length is too small");

   SecureVector<byte> T(output_length);
   const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2;

   T[0] = 0x01;
   set_mem(&T[1], P_LENGTH, 0xFF);
   T[P_LENGTH+1] = 0x00;
   T.copy(P_LENGTH+2, hash_id, hash_id_length);
   T.copy(output_length-msg.size(), &msg[0], msg.size());
   return T;
   }

}

/*
* EMSA3 Update Operation
*/
void EMSA3::update(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA3::raw_data()
   {
   return hash->final();
   }

/*
* EMSA3 Encode Operation
*/
SecureVector<byte> EMSA3::encoding_of(const MemoryRegion<byte>& msg,
                                      size_t output_bits,
                                      RandomNumberGenerator&)
   {
   if(msg.size() != hash->output_length())
      throw Encoding_Error("EMSA3::encoding_of: Bad input length");

   return emsa3_encoding(msg, output_bits,
                         &hash_id[0], hash_id.size());
   }

/*
* Default signature decoding
*/
bool EMSA3::verify(const MemoryRegion<byte>& coded,
                   const MemoryRegion<byte>& raw,
                   size_t key_bits)
   {
   if(raw.size() != hash->output_length())
      return false;

   try
      {
      return (coded == emsa3_encoding(raw, key_bits,
                                      &hash_id[0], hash_id.size()));
      }
   catch(...)
      {
      return false;
      }
   }

/*
* EMSA3 Constructor
*/
EMSA3::EMSA3(HashFunction* hash_in) : hash(hash_in)
   {
   hash_id = pkcs_hash_id(hash->name());
   }

/*
* EMSA3 Destructor
*/
EMSA3::~EMSA3()
   {
   delete hash;
   }

/*
* EMSA3_Raw Update Operation
*/
void EMSA3_Raw::update(const byte input[], size_t length)
   {
   message += std::make_pair(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA3_Raw::raw_data()
   {
   SecureVector<byte> ret;
   std::swap(ret, message);
   return ret;
   }

/*
* EMSA3_Raw Encode Operation
*/
SecureVector<byte> EMSA3_Raw::encoding_of(const MemoryRegion<byte>& msg,
                                          size_t output_bits,
                                          RandomNumberGenerator&)
   {
   return emsa3_encoding(msg, output_bits, 0, 0);
   }

/*
* Default signature decoding
*/
bool EMSA3_Raw::verify(const MemoryRegion<byte>& coded,
                       const MemoryRegion<byte>& raw,
                       size_t key_bits)
   {
   try
      {
      return (coded == emsa3_encoding(raw, key_bits, 0, 0));
      }
   catch(...)
      {
      return false;
      }
   }

}
/*
* EMSA4
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* EMSA4 Update Operation
*/
void EMSA4::update(const byte input[], size_t length)
   {
   hash->update(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA4::raw_data()
   {
   return hash->final();
   }

/*
* EMSA4 Encode Operation
*/
SecureVector<byte> EMSA4::encoding_of(const MemoryRegion<byte>& msg,
                                      size_t output_bits,
                                      RandomNumberGenerator& rng)
   {
   const size_t HASH_SIZE = hash->output_length();

   if(msg.size() != HASH_SIZE)
      throw Encoding_Error("EMSA4::encoding_of: Bad input length");
   if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
      throw Encoding_Error("EMSA4::encoding_of: Output length is too small");

   const size_t output_length = (output_bits + 7) / 8;

   SecureVector<byte> salt = rng.random_vec(SALT_SIZE);

   for(size_t j = 0; j != 8; ++j)
      hash->update(0);
   hash->update(msg);
   hash->update(salt, SALT_SIZE);
   SecureVector<byte> H = hash->final();

   SecureVector<byte> EM(output_length);

   EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
   EM.copy(output_length - 1 - HASH_SIZE - SALT_SIZE, salt, SALT_SIZE);
   mgf->mask(H, HASH_SIZE, EM, output_length - HASH_SIZE - 1);
   EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
   EM.copy(output_length - 1 - HASH_SIZE, H, HASH_SIZE);
   EM[output_length-1] = 0xBC;

   return EM;
   }

/*
* EMSA4 Decode/Verify Operation
*/
bool EMSA4::verify(const MemoryRegion<byte>& const_coded,
                   const MemoryRegion<byte>& raw, size_t key_bits)
   {
   const size_t HASH_SIZE = hash->output_length();
   const size_t KEY_BYTES = (key_bits + 7) / 8;

   if(key_bits < 8*HASH_SIZE + 9)
      return false;

   if(raw.size() != HASH_SIZE)
      return false;

   if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1)
      return false;

   if(const_coded[const_coded.size()-1] != 0xBC)
      return false;

   SecureVector<byte> coded = const_coded;
   if(coded.size() < KEY_BYTES)
      {
      SecureVector<byte> temp(KEY_BYTES);
      temp.copy(KEY_BYTES - coded.size(), coded, coded.size());
      coded = temp;
      }

   const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
   if(TOP_BITS > 8 - high_bit(coded[0]))
      return false;

   SecureVector<byte> DB(&coded[0], coded.size() - HASH_SIZE - 1);
   SecureVector<byte> H(&coded[coded.size() - HASH_SIZE - 1], HASH_SIZE);

   mgf->mask(H, H.size(), DB, coded.size() - H.size() - 1);
   DB[0] &= 0xFF >> TOP_BITS;

   size_t salt_offset = 0;
   for(size_t j = 0; j != DB.size(); ++j)
      {
      if(DB[j] == 0x01)
         { salt_offset = j + 1; break; }
      if(DB[j])
         return false;
      }
   if(salt_offset == 0)
      return false;

   SecureVector<byte> salt(&DB[salt_offset], DB.size() - salt_offset);

   for(size_t j = 0; j != 8; ++j)
      hash->update(0);
   hash->update(raw);
   hash->update(salt);
   SecureVector<byte> H2 = hash->final();

   return (H == H2);
   }

/*
* EMSA4 Constructor
*/
EMSA4::EMSA4(HashFunction* h) :
   SALT_SIZE(h->output_length()), hash(h)
   {
   mgf = new MGF1(hash->clone());
   }

/*
* EMSA4 Constructor
*/
EMSA4::EMSA4(HashFunction* h, size_t salt_size) :
   SALT_SIZE(salt_size), hash(h)
   {
   mgf = new MGF1(hash->clone());
   }

}
/*
* EMSA-Raw
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* EMSA-Raw Encode Operation
*/
void EMSA_Raw::update(const byte input[], size_t length)
   {
   message += std::make_pair(input, length);
   }

/*
* Return the raw (unencoded) data
*/
SecureVector<byte> EMSA_Raw::raw_data()
   {
   SecureVector<byte> output;
   std::swap(message, output);
   return output;
   }

/*
* EMSA-Raw Encode Operation
*/
SecureVector<byte> EMSA_Raw::encoding_of(const MemoryRegion<byte>& msg,
                                         size_t,
                                         RandomNumberGenerator&)
   {
   return msg;
   }

/*
* EMSA-Raw Verify Operation
*/
bool EMSA_Raw::verify(const MemoryRegion<byte>& coded,
                      const MemoryRegion<byte>& raw,
                      size_t)
   {
   if(coded.size() == raw.size())
      return (coded == raw);

   if(coded.size() > raw.size())
      return false;

   // handle zero padding differences
   const size_t leading_zeros_expected = raw.size() - coded.size();

   bool same_modulo_leading_zeros = true;

   for(size_t i = 0; i != leading_zeros_expected; ++i)
      if(raw[i])
         same_modulo_leading_zeros = false;

   if(!same_mem(&coded[0], &raw[leading_zeros_expected], coded.size()))
      same_modulo_leading_zeros = false;

   return same_modulo_leading_zeros;
   }

}
/*
* Hash Function Identification
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

const byte MD2_PKCS_ID[] = {
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 };

const byte MD5_PKCS_ID[] = {
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };

const byte RIPEMD_128_PKCS_ID[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02,
0x02, 0x05, 0x00, 0x04, 0x14 };

const byte RIPEMD_160_PKCS_ID[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02,
0x01, 0x05, 0x00, 0x04, 0x14 };

const byte SHA_160_PKCS_ID[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02,
0x1A, 0x05, 0x00, 0x04, 0x14 };

const byte SHA_224_PKCS_ID[] = {
0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C };

const byte SHA_256_PKCS_ID[] = {
0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };

const byte SHA_384_PKCS_ID[] = {
0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 };

const byte SHA_512_PKCS_ID[] = {
0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 };

const byte TIGER_PKCS_ID[] = {
0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04,
0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 };

}

/*
* HashID as specified by PKCS
*/
MemoryVector<byte> pkcs_hash_id(const std::string& name)
   {
   // Special case for SSL/TLS RSA signatures
   if(name == "Parallel(MD5,SHA-160)")
      return MemoryVector<byte>();

   if(name == "MD2")
      return MemoryVector<byte>(MD2_PKCS_ID, sizeof(MD2_PKCS_ID));
   if(name == "MD5")
      return MemoryVector<byte>(MD5_PKCS_ID, sizeof(MD5_PKCS_ID));
   if(name == "RIPEMD-128")
      return MemoryVector<byte>(RIPEMD_128_PKCS_ID, sizeof(RIPEMD_128_PKCS_ID));
   if(name == "RIPEMD-160")
      return MemoryVector<byte>(RIPEMD_160_PKCS_ID, sizeof(RIPEMD_160_PKCS_ID));
   if(name == "SHA-160")
      return MemoryVector<byte>(SHA_160_PKCS_ID, sizeof(SHA_160_PKCS_ID));
   if(name == "SHA-224")
      return MemoryVector<byte>(SHA_224_PKCS_ID, sizeof(SHA_224_PKCS_ID));
   if(name == "SHA-256")
      return MemoryVector<byte>(SHA_256_PKCS_ID, sizeof(SHA_256_PKCS_ID));
   if(name == "SHA-384")
      return MemoryVector<byte>(SHA_384_PKCS_ID, sizeof(SHA_384_PKCS_ID));
   if(name == "SHA-512")
      return MemoryVector<byte>(SHA_512_PKCS_ID, sizeof(SHA_512_PKCS_ID));
   if(name == "Tiger(24,3)")
      return MemoryVector<byte>(TIGER_PKCS_ID, sizeof(TIGER_PKCS_ID));

   throw Invalid_Argument("No PKCS #1 identifier for " + name);
   }

/*
* HashID as specified by IEEE 1363/X9.31
*/
byte ieee1363_hash_id(const std::string& name)
   {
   if(name == "SHA-160")    return 0x33;

   if(name == "SHA-224")    return 0x38;
   if(name == "SHA-256")    return 0x34;
   if(name == "SHA-384")    return 0x36;
   if(name == "SHA-512")    return 0x35;

   if(name == "RIPEMD-160") return 0x31;
   if(name == "RIPEMD-128") return 0x32;

   if(name == "Whirlpool")  return 0x37;

   return 0;
   }

}
/*
* Blinding for public key operations
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Blinder Constructor
*/
Blinder::Blinder(const BigInt& e, const BigInt& d, const BigInt& n)
   {
   if(e < 1 || d < 1 || n < 1)
      throw Invalid_Argument("Blinder: Arguments too small");

   reducer = Modular_Reducer(n);
   this->e = e;
   this->d = d;
   }

/*
* Blind a number
*/
BigInt Blinder::blind(const BigInt& i) const
   {
   if(!reducer.initialized())
      return i;

   e = reducer.square(e);
   d = reducer.square(d);
   return reducer.multiply(i, e);
   }

/*
* Unblind a number
*/
BigInt Blinder::unblind(const BigInt& i) const
   {
   if(!reducer.initialized())
      return i;
   return reducer.multiply(i, d);
   }

}
/*
* Diffie-Hellman
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* DH_PublicKey Constructor
*/
DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1)
   {
   group = grp;
   y = y1;
   }

/*
* Return the public value for key agreement
*/
MemoryVector<byte> DH_PublicKey::public_value() const
   {
   return BigInt::encode_1363(y, group_p().bytes());
   }

/*
* Create a DH private key
*/
DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
                             const DL_Group& grp,
                             const BigInt& x_arg)
   {
   group = grp;
   x = x_arg;

   if(x == 0)
      {
      const BigInt& p = group_p();
      x.randomize(rng, 2 * dl_work_factor(p.bits()));
      }

   if(y == 0)
      y = power_mod(group_g(), x, group_p());

   if(x == 0)
      gen_check(rng);
   else
      load_check(rng);
   }

/*
* Load a DH private key
*/
DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id,
                             const MemoryRegion<byte>& key_bits,
                             RandomNumberGenerator& rng) :
   DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42)
   {
   if(y == 0)
      y = power_mod(group_g(), x, group_p());

   load_check(rng);
   }

/*
* Return the public value for key agreement
*/
MemoryVector<byte> DH_PrivateKey::public_value() const
   {
   return DH_PublicKey::public_value();
   }

DH_KA_Operation::DH_KA_Operation(const DH_PrivateKey& dh) :
   p(dh.group_p()), powermod_x_p(dh.get_x(), p)
   {
   BigInt k(global_state().global_rng(), p.bits() - 1);
   blinder = Blinder(k, powermod_x_p(inverse_mod(k, p)), p);
   }

SecureVector<byte> DH_KA_Operation::agree(const byte w[], size_t w_len)
   {
   BigInt input = BigInt::decode(w, w_len);

   BigInt r = blinder.unblind(powermod_x_p(blinder.blind(input)));

   return BigInt::encode_1363(r, p.bytes());
   }

}
/*
* DL Scheme
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const
   {
   return AlgorithmIdentifier(get_oid(),
                              group.DER_encode(group_format()));
   }

MemoryVector<byte> DL_Scheme_PublicKey::x509_subject_public_key() const
   {
   return DER_Encoder().encode(y).get_contents();
   }

DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id,
                                         const MemoryRegion<byte>& key_bits,
                                         DL_Group::Format format)
   {
   DataSource_Memory source(alg_id.parameters);
   group.BER_decode(source, format);

   BER_Decoder(key_bits).decode(y);
   }

MemoryVector<byte> DL_Scheme_PrivateKey::pkcs8_private_key() const
   {
   return DER_Encoder().encode(x).get_contents();
   }

DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id,
                                           const MemoryRegion<byte>& key_bits,
                                           DL_Group::Format format)
   {
   DataSource_Memory source(alg_id.parameters);
   group.BER_decode(source, format);

   BER_Decoder(key_bits).decode(x);
   }

/*
* Check Public DL Parameters
*/
bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng,
                                    bool strong) const
   {
   if(y < 2 || y >= group_p())
      return false;
   if(!group.verify_group(rng, strong))
      return false;
   return true;
   }

/*
* Check DL Scheme Private Parameters
*/
bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng,
                                     bool strong) const
   {
   const BigInt& p = group_p();
   const BigInt& g = group_g();

   if(y < 2 || y >= p || x < 2 || x >= p)
      return false;
   if(!group.verify_group(rng, strong))
      return false;

   if(!strong)
      return true;

   if(y != power_mod(g, x, p))
      return false;

   return true;
   }

}
/*
* Discrete Logarithm Parameters
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* DL_Group Constructor
*/
DL_Group::DL_Group()
   {
   initialized = false;
   }

/*
* DL_Group Constructor
*/
DL_Group::DL_Group(const std::string& type)
   {
   std::string grp_contents = global_state().get("dl", type);

   if(grp_contents == "")
      throw Invalid_Argument("DL_Group: Unknown group " + type);

   DataSource_Memory pem(grp_contents);
   PEM_decode(pem);
   }

/*
* DL_Group Constructor
*/
DL_Group::DL_Group(RandomNumberGenerator& rng,
                   PrimeType type, size_t pbits, size_t qbits)
   {
   if(pbits < 512)
      throw Invalid_Argument("DL_Group: prime size " + to_string(pbits) +
                             " is too small");

   if(type == Strong)
      {
      p = random_safe_prime(rng, pbits);
      q = (p - 1) / 2;
      g = 2;
      }
   else if(type == Prime_Subgroup)
      {
      if(!qbits)
         qbits = 2 * dl_work_factor(pbits);

      q = random_prime(rng, qbits);
      BigInt X;
      while(p.bits() != pbits || !check_prime(p, rng))
         {
         X.randomize(rng, pbits);
         p = X - (X % (2*q) - 1);
         }

      g = make_dsa_generator(p, q);
      }
   else if(type == DSA_Kosherizer)
      {
      qbits = qbits ? qbits : ((pbits <= 1024) ? 160 : 256);

      generate_dsa_primes(rng,
                          global_state().algorithm_factory(),
                          p, q,
                          pbits, qbits);

      g = make_dsa_generator(p, q);
      }

   initialized = true;
   }

/*
* DL_Group Constructor
*/
DL_Group::DL_Group(RandomNumberGenerator& rng,
                   const MemoryRegion<byte>& seed, size_t pbits, size_t qbits)
   {
   if(!generate_dsa_primes(rng,
                           global_state().algorithm_factory(),
                           p, q, pbits, qbits, seed))
      throw Invalid_Argument("DL_Group: The seed given does not "
                             "generate a DSA group");

   g = make_dsa_generator(p, q);

   initialized = true;
   }

/*
* DL_Group Constructor
*/
DL_Group::DL_Group(const BigInt& p1, const BigInt& g1)
   {
   initialize(p1, 0, g1);
   }

/*
* DL_Group Constructor
*/
DL_Group::DL_Group(const BigInt& p1, const BigInt& q1, const BigInt& g1)
   {
   initialize(p1, q1, g1);
   }

/*
* DL_Group Initializer
*/
void DL_Group::initialize(const BigInt& p1, const BigInt& q1, const BigInt& g1)
   {
   if(p1 < 3)
      throw Invalid_Argument("DL_Group: Prime invalid");
   if(g1 < 2 || g1 >= p1)
      throw Invalid_Argument("DL_Group: Generator invalid");
   if(q1 < 0 || q1 >= p1)
      throw Invalid_Argument("DL_Group: Subgroup invalid");

   p = p1;
   g = g1;
   q = q1;

   initialized = true;
   }

/*
* Verify that the group has been set
*/
void DL_Group::init_check() const
   {
   if(!initialized)
      throw Invalid_State("DLP group cannot be used uninitialized");
   }

/*
* Verify the parameters
*/
bool DL_Group::verify_group(RandomNumberGenerator& rng,
                            bool strong) const
   {
   init_check();

   if(g < 2 || p < 3 || q < 0)
      return false;
   if((q != 0) && ((p - 1) % q != 0))
      return false;

   if(!strong)
      return true;

   if(!check_prime(p, rng))
      return false;
   if((q > 0) && !check_prime(q, rng))
      return false;
   return true;
   }

/*
* Return the prime
*/
const BigInt& DL_Group::get_p() const
   {
   init_check();
   return p;
   }

/*
* Return the generator
*/
const BigInt& DL_Group::get_g() const
   {
   init_check();
   return g;
   }

/*
* Return the subgroup
*/
const BigInt& DL_Group::get_q() const
   {
   init_check();
   if(q == 0)
      throw Invalid_State("DLP group has no q prime specified");
   return q;
   }

/*
* DER encode the parameters
*/
SecureVector<byte> DL_Group::DER_encode(Format format) const
   {
   init_check();

   if((q == 0) && (format != PKCS_3))
      throw Encoding_Error("The ANSI DL parameter formats require a subgroup");

   if(format == ANSI_X9_57)
      {
      return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(p)
            .encode(q)
            .encode(g)
         .end_cons()
      .get_contents();
      }
   else if(format == ANSI_X9_42)
      {
      return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(p)
            .encode(g)
            .encode(q)
         .end_cons()
      .get_contents();
      }
   else if(format == PKCS_3)
      {
      return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(p)
            .encode(g)
         .end_cons()
      .get_contents();
      }

   throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));
   }

/*
* PEM encode the parameters
*/
std::string DL_Group::PEM_encode(Format format) const
   {
   SecureVector<byte> encoding = DER_encode(format);
   if(format == PKCS_3)
      return PEM_Code::encode(encoding, "DH PARAMETERS");
   else if(format == ANSI_X9_57)
      return PEM_Code::encode(encoding, "DSA PARAMETERS");
   else if(format == ANSI_X9_42)
      return PEM_Code::encode(encoding, "X942 DH PARAMETERS");
   else
      throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));
   }

/*
* Decode BER encoded parameters
*/
void DL_Group::BER_decode(DataSource& source, Format format)
   {
   BigInt new_p, new_q, new_g;

   BER_Decoder decoder(source);
   BER_Decoder ber = decoder.start_cons(SEQUENCE);

   if(format == ANSI_X9_57)
      {
      ber.decode(new_p)
         .decode(new_q)
         .decode(new_g)
         .verify_end();
      }
   else if(format == ANSI_X9_42)
      {
      ber.decode(new_p)
         .decode(new_g)
         .decode(new_q)
         .discard_remaining();
      }
   else if(format == PKCS_3)
      {
      ber.decode(new_p)
         .decode(new_g)
         .discard_remaining();
      }
   else
      throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));

   initialize(new_p, new_q, new_g);
   }

/*
* Decode PEM encoded parameters
*/
void DL_Group::PEM_decode(DataSource& source)
   {
   std::string label;
   DataSource_Memory ber(PEM_Code::decode(source, label));

   if(label == "DH PARAMETERS")
      BER_decode(ber, PKCS_3);
   else if(label == "DSA PARAMETERS")
      BER_decode(ber, ANSI_X9_57);
   else if(label == "X942 DH PARAMETERS")
      BER_decode(ber, ANSI_X9_42);
   else
      throw Decoding_Error("DL_Group: Invalid PEM label " + label);
   }

/*
* Create generator of the q-sized subgroup (DSA style generator)
*/
BigInt DL_Group::make_dsa_generator(const BigInt& p, const BigInt& q)
   {
   BigInt g, e = (p - 1) / q;

   BOTAN_ASSERT(e > 0, "q does not divide p, invalid group");

   for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i)
      {
      g = power_mod(PRIMES[i], e, p);
      if(g > 1)
         return g;
      }

   throw Internal_Error("DL_Group: Couldn't create a suitable generator");
   }

}
/*
* DLIES
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* DLIES_Encryptor Constructor
*/
DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& key,
                                 KDF* kdf_obj,
                                 MessageAuthenticationCode* mac_obj,
                                 size_t mac_kl) :
   ka(key, "Raw"),
   kdf(kdf_obj),
   mac(mac_obj),
   mac_keylen(mac_kl)
   {
   my_key = key.public_value();
   }

DLIES_Encryptor::~DLIES_Encryptor()
   {
   delete kdf;
   delete mac;
   }

/*
* DLIES Encryption
*/
SecureVector<byte> DLIES_Encryptor::enc(const byte in[], size_t length,
                                        RandomNumberGenerator&) const
   {
   if(length > maximum_input_size())
      throw Invalid_Argument("DLIES: Plaintext too large");
   if(other_key.empty())
      throw Invalid_State("DLIES: The other key was never set");

   SecureVector<byte> out(my_key.size() + length + mac->output_length());
   out.copy(&my_key[0], my_key.size());
   out.copy(my_key.size(), in, length);

   SecureVector<byte> vz = my_key;
   vz += ka.derive_key(0, other_key).bits_of();

   const size_t K_LENGTH = length + mac_keylen;
   OctetString K = kdf->derive_key(K_LENGTH, vz);

   if(K.length() != K_LENGTH)
      throw Encoding_Error("DLIES: KDF did not provide sufficient output");
   byte* C = &out[my_key.size()];

   xor_buf(C, K.begin() + mac_keylen, length);
   mac->set_key(K.begin(), mac_keylen);

   mac->update(C, length);
   for(size_t j = 0; j != 8; ++j)
      mac->update(0);

   mac->final(C + length);

   return out;
   }

/*
* Set the other parties public key
*/
void DLIES_Encryptor::set_other_key(const MemoryRegion<byte>& ok)
   {
   other_key = ok;
   }

/*
* Return the max size, in bytes, of a message
*/
size_t DLIES_Encryptor::maximum_input_size() const
   {
   return 32;
   }

/*
* DLIES_Decryptor Constructor
*/
DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& key,
                                 KDF* kdf_obj,
                                 MessageAuthenticationCode* mac_obj,
                                 size_t mac_kl) :
   ka(key, "Raw"),
   kdf(kdf_obj),
   mac(mac_obj),
   mac_keylen(mac_kl)
   {
   my_key = key.public_value();
   }

DLIES_Decryptor::~DLIES_Decryptor()
   {
   delete kdf;
   delete mac;
   }

/*
* DLIES Decryption
*/
SecureVector<byte> DLIES_Decryptor::dec(const byte msg[], size_t length) const
   {
   if(length < my_key.size() + mac->output_length())
      throw Decoding_Error("DLIES decryption: ciphertext is too short");

   const size_t CIPHER_LEN = length - my_key.size() - mac->output_length();

   SecureVector<byte> v(msg, my_key.size());
   SecureVector<byte> C(msg + my_key.size(), CIPHER_LEN);
   SecureVector<byte> T(msg + my_key.size() + CIPHER_LEN, mac->output_length());

   SecureVector<byte> vz(msg, my_key.size());
   vz += ka.derive_key(0, v).bits_of();

   const size_t K_LENGTH = C.size() + mac_keylen;
   OctetString K = kdf->derive_key(K_LENGTH, vz);
   if(K.length() != K_LENGTH)
      throw Encoding_Error("DLIES: KDF did not provide sufficient output");

   mac->set_key(K.begin(), mac_keylen);
   mac->update(C);
   for(size_t j = 0; j != 8; ++j)
      mac->update(0);
   SecureVector<byte> T2 = mac->final();
   if(T != T2)
      throw Decoding_Error("DLIES: message authentication failed");

   xor_buf(C, K.begin() + mac_keylen, C.size());

   return C;
   }

}
/*
* DSA
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* DSA_PublicKey Constructor
*/
DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1)
   {
   group = grp;
   y = y1;
   }

/*
* Create a DSA private key
*/
DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng,
                               const DL_Group& grp,
                               const BigInt& x_arg)
   {
   group = grp;
   x = x_arg;

   if(x == 0)
      x = BigInt::random_integer(rng, 2, group_q() - 1);

   y = power_mod(group_g(), x, group_p());

   if(x_arg == 0)
      gen_check(rng);
   else
      load_check(rng);
   }

DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id,
                               const MemoryRegion<byte>& key_bits,
                               RandomNumberGenerator& rng) :
   DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57)
   {
   y = power_mod(group_g(), x, group_p());

   load_check(rng);
   }

/*
* Check Private DSA Parameters
*/
bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
   {
   if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q())
      return false;

   if(!strong)
      return true;

   return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
   }

DSA_Signature_Operation::DSA_Signature_Operation(const DSA_PrivateKey& dsa) :
   q(dsa.group_q()),
   x(dsa.get_x()),
   powermod_g_p(dsa.group_g(), dsa.group_p()),
   mod_q(dsa.group_q())
   {
   }

SecureVector<byte>
DSA_Signature_Operation::sign(const byte msg[], size_t msg_len,
                              RandomNumberGenerator& rng)
   {
   rng.add_entropy(msg, msg_len);

   BigInt i(msg, msg_len);
   BigInt r = 0, s = 0;

   while(r == 0 || s == 0)
      {
      BigInt k;
      do
         k.randomize(rng, q.bits());
      while(k >= q);

      r = mod_q.reduce(powermod_g_p(k));
      s = mod_q.multiply(inverse_mod(k, q), mul_add(x, r, i));
      }

   SecureVector<byte> output(2*q.bytes());
   r.binary_encode(&output[output.size() / 2 - r.bytes()]);
   s.binary_encode(&output[output.size() - s.bytes()]);
   return output;
   }

DSA_Verification_Operation::DSA_Verification_Operation(const DSA_PublicKey& dsa) :
   q(dsa.group_q()), y(dsa.get_y())
   {
   powermod_g_p = Fixed_Base_Power_Mod(dsa.group_g(), dsa.group_p());
   powermod_y_p = Fixed_Base_Power_Mod(y, dsa.group_p());
   mod_p = Modular_Reducer(dsa.group_p());
   mod_q = Modular_Reducer(dsa.group_q());
   }

bool DSA_Verification_Operation::verify(const byte msg[], size_t msg_len,
                                        const byte sig[], size_t sig_len)
   {
   const BigInt& q = mod_q.get_modulus();

   if(sig_len != 2*q.bytes() || msg_len > q.bytes())
      return false;

   BigInt r(sig, q.bytes());
   BigInt s(sig + q.bytes(), q.bytes());
   BigInt i(msg, msg_len);

   if(r <= 0 || r >= q || s <= 0 || s >= q)
      return false;

   s = inverse_mod(s, q);
   s = mod_p.multiply(powermod_g_p(mod_q.multiply(s, i)),
                      powermod_y_p(mod_q.multiply(s, r)));

   return (mod_q.reduce(s) == r);
   }

}
/*
* ECC Domain Parameters
*
* (C) 2007 Falko Strenzke, FlexSecure GmbH
*     2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

EC_Group::EC_Group(const OID& domain_oid)
   {
   std::string pem =
      global_state().get("ec", OIDS::lookup(domain_oid));

   if(pem == "")
      throw Lookup_Error("No ECC domain data for " + domain_oid.as_string());

   *this = EC_Group(pem);
   oid = domain_oid.as_string();
   }

EC_Group::EC_Group(const std::string& str)
   {
   if(str == "")
      return; // no initialization / uninitialized

   try
      {
      DataSource_Memory input(str);

      SecureVector<byte> ber =
         PEM_Code::decode_check_label(input, "EC PARAMETERS");

      *this = EC_Group(ber);
      }
   catch(Decoding_Error) // hmm, not PEM?
      {
      *this = EC_Group(OIDS::lookup(str));
      }
   }

EC_Group::EC_Group(const MemoryRegion<byte>& ber_data)
   {
   BER_Decoder ber(ber_data);
   BER_Object obj = ber.get_next_object();

   if(obj.type_tag == NULL_TAG)
      throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters");
   else if(obj.type_tag == OBJECT_ID)
      {
      OID dom_par_oid;
      BER_Decoder(ber_data).decode(dom_par_oid);
      *this = EC_Group(dom_par_oid);
      }
   else if(obj.type_tag == SEQUENCE)
      {
      BigInt p, a, b;
      SecureVector<byte> sv_base_point;

      BER_Decoder(ber_data)
         .start_cons(SEQUENCE)
           .decode_and_check<size_t>(1, "Unknown ECC param version code")
           .start_cons(SEQUENCE)
            .decode_and_check(OID("1.2.840.10045.1.1"),
                              "Only prime ECC fields supported")
             .decode(p)
           .end_cons()
           .start_cons(SEQUENCE)
             .decode_octet_string_bigint(a)
             .decode_octet_string_bigint(b)
           .end_cons()
           .decode(sv_base_point, OCTET_STRING)
           .decode(order)
           .decode(cofactor)
         .end_cons()
         .verify_end();

      curve = CurveGFp(p, a, b);
      base_point = OS2ECP(sv_base_point, curve);
      }
   else
      throw Decoding_Error("Unexpected tag while decoding ECC domain params");
   }

SecureVector<byte>
EC_Group::DER_encode(EC_Group_Encoding form) const
   {
   if(form == EC_DOMPAR_ENC_EXPLICIT)
      {
      const size_t ecpVers1 = 1;
      OID curve_type("1.2.840.10045.1.1");

      const size_t p_bytes = curve.get_p().bytes();

      return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(ecpVers1)
            .start_cons(SEQUENCE)
               .encode(curve_type)
               .encode(curve.get_p())
            .end_cons()
            .start_cons(SEQUENCE)
               .encode(BigInt::encode_1363(curve.get_a(), p_bytes),
                       OCTET_STRING)
               .encode(BigInt::encode_1363(curve.get_b(), p_bytes),
                       OCTET_STRING)
            .end_cons()
            .encode(EC2OSP(base_point, PointGFp::UNCOMPRESSED), OCTET_STRING)
            .encode(order)
            .encode(cofactor)
         .end_cons()
         .get_contents();
      }
   else if(form == EC_DOMPAR_ENC_OID)
      return DER_Encoder().encode(get_oid()).get_contents();
   else if(form == EC_DOMPAR_ENC_IMPLICITCA)
      return DER_Encoder().encode_null().get_contents();
   else
      throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
   }

std::string EC_Group::PEM_encode() const
   {
   SecureVector<byte> der = DER_encode(EC_DOMPAR_ENC_EXPLICIT);
   return PEM_Code::encode(der, "EC PARAMETERS");
   }

}
/*
* ECC Key implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
*          Falko Strenzke, FlexSecure GmbH
*     2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

EC_PublicKey::EC_PublicKey(const EC_Group& dom_par,
                           const PointGFp& pub_point) :
   domain_params(dom_par), public_key(pub_point),
   domain_encoding(EC_DOMPAR_ENC_EXPLICIT)
   {
   if(domain().get_curve() != public_point().get_curve())
      throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor");
   }

EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id,
                           const MemoryRegion<byte>& key_bits)
   {
   domain_params = EC_Group(alg_id.parameters);
   domain_encoding = EC_DOMPAR_ENC_EXPLICIT;

   public_key = OS2ECP(key_bits, domain().get_curve());
   }

bool EC_PublicKey::check_key(RandomNumberGenerator&,
                             bool) const
   {
   return public_point().on_the_curve();
   }

AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const
   {
   return AlgorithmIdentifier(get_oid(), DER_domain());
   }

MemoryVector<byte> EC_PublicKey::x509_subject_public_key() const
   {
   return EC2OSP(public_point(), PointGFp::COMPRESSED);
   }

void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form)
   {
   if(form != EC_DOMPAR_ENC_EXPLICIT &&
      form != EC_DOMPAR_ENC_IMPLICITCA &&
      form != EC_DOMPAR_ENC_OID)
      throw Invalid_Argument("Invalid encoding form for EC-key object specified");

   if((form == EC_DOMPAR_ENC_OID) && (domain_params.get_oid() == ""))
      throw Invalid_Argument("Invalid encoding form OID specified for "
                             "EC-key object whose corresponding domain "
                             "parameters are without oid");

   domain_encoding = form;
   }

const BigInt& EC_PrivateKey::private_value() const
   {
   if(private_key == 0)
      throw Invalid_State("EC_PrivateKey::private_value - uninitialized");

   return private_key;
   }

/**
* EC_PrivateKey constructor
*/
EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng,
                             const EC_Group& ec_group,
                             const BigInt& x)
   {
   domain_params = ec_group;
   domain_encoding = EC_DOMPAR_ENC_EXPLICIT;

   if(x == 0)
      private_key = BigInt::random_integer(rng, 1, domain().get_order());
   else
      private_key = x;

   public_key = domain().get_base_point() * private_key;

   BOTAN_ASSERT(public_key.on_the_curve(),
                "ECC private key was not on the curve");
   }

MemoryVector<byte> EC_PrivateKey::pkcs8_private_key() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode(static_cast<size_t>(1))
         .encode(BigInt::encode_1363(private_key, private_key.bytes()),
                 OCTET_STRING)
      .end_cons()
      .get_contents();
   }

EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id,
                             const MemoryRegion<byte>& key_bits)
   {
   domain_params = EC_Group(alg_id.parameters);
   domain_encoding = EC_DOMPAR_ENC_EXPLICIT;

   BER_Decoder(key_bits)
      .start_cons(SEQUENCE)
         .decode_and_check<size_t>(1, "Unknown version code for ECC key")
         .decode_octet_string_bigint(private_key)
      .verify_end()
      .end_cons();

   public_key = domain().get_base_point() * private_key;

   BOTAN_ASSERT(public_key.on_the_curve(),
                "Loaded ECC private key not on the curve");
   }

}
/*
* ECDH implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
*     2007 Falko Strenzke, FlexSecure GmbH
*     2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

ECDH_KA_Operation::ECDH_KA_Operation(const ECDH_PrivateKey& key) :
   curve(key.domain().get_curve()),
   cofactor(key.domain().get_cofactor())
   {
   l_times_priv = inverse_mod(cofactor, key.domain().get_order()) *
                  key.private_value();
   }

SecureVector<byte> ECDH_KA_Operation::agree(const byte w[], size_t w_len)
   {
   PointGFp point = OS2ECP(w, w_len, curve);

   PointGFp S = (cofactor * point) * l_times_priv;

   BOTAN_ASSERT(S.on_the_curve(),
                "ECDH agreed value not on the curve");

   return BigInt::encode_1363(S.get_affine_x(),
                              curve.get_p().bytes());
   }

}
/*
* ECDSA implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
*     2007 Falko Strenzke, FlexSecure GmbH
*     2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
                                 bool strong) const
   {
   if(!public_point().on_the_curve())
      return false;

   if(!strong)
      return true;

   return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
   }

ECDSA_Signature_Operation::ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa) :
   base_point(ecdsa.domain().get_base_point()),
   order(ecdsa.domain().get_order()),
   x(ecdsa.private_value()),
   mod_order(order)
   {
   }

SecureVector<byte>
ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len,
                                RandomNumberGenerator& rng)
   {
   rng.add_entropy(msg, msg_len);

   BigInt m(msg, msg_len);

   BigInt r = 0, s = 0;

   while(r == 0 || s == 0)
      {
      // This contortion is necessary for the tests
      BigInt k;
      k.randomize(rng, order.bits());

      while(k >= order)
         k.randomize(rng, order.bits() - 1);

      PointGFp k_times_P = base_point * k;
      r = mod_order.reduce(k_times_P.get_affine_x());
      s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m));
      }

   SecureVector<byte> output(2*order.bytes());
   r.binary_encode(&output[output.size() / 2 - r.bytes()]);
   s.binary_encode(&output[output.size() - s.bytes()]);
   return output;
   }

ECDSA_Verification_Operation::ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa) :
   base_point(ecdsa.domain().get_base_point()),
   public_point(ecdsa.public_point()),
   order(ecdsa.domain().get_order())
   {
   }

bool ECDSA_Verification_Operation::verify(const byte msg[], size_t msg_len,
                                          const byte sig[], size_t sig_len)
   {
   if(sig_len != order.bytes()*2)
      return false;

   BigInt e(msg, msg_len);

   BigInt r(sig, sig_len / 2);
   BigInt s(sig + sig_len / 2, sig_len / 2);

   if(r <= 0 || r >= order || s <= 0 || s >= order)
      return false;

   BigInt w = inverse_mod(s, order);

   PointGFp R = w * multi_exponentiate(base_point, e,
                                       public_point, r);

   if(R.is_zero())
      return false;

   return (R.get_affine_x() % order == r);
   }

}
/*
* ElGamal
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* ElGamal_PublicKey Constructor
*/
ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& grp, const BigInt& y1)
   {
   group = grp;
   y = y1;
   }

/*
* ElGamal_PrivateKey Constructor
*/
ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng,
                                       const DL_Group& grp,
                                       const BigInt& x_arg)
   {
   group = grp;
   x = x_arg;

   if(x == 0)
      x.randomize(rng, 2 * dl_work_factor(group_p().bits()));

   y = power_mod(group_g(), x, group_p());

   if(x_arg == 0)
      gen_check(rng);
   else
      load_check(rng);
   }

ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id,
                                       const MemoryRegion<byte>& key_bits,
                                       RandomNumberGenerator& rng) :
   DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42)
   {
   y = power_mod(group_g(), x, group_p());
   load_check(rng);
   }

/*
* Check Private ElGamal Parameters
*/
bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng,
                                   bool strong) const
   {
   if(!DL_Scheme_PrivateKey::check_key(rng, strong))
      return false;

   if(!strong)
      return true;

   return KeyPair::encryption_consistency_check(rng, *this, "EME1(SHA-1)");
   }

ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key)
   {
   const BigInt& p = key.group_p();

   powermod_g_p = Fixed_Base_Power_Mod(key.group_g(), p);
   powermod_y_p = Fixed_Base_Power_Mod(key.get_y(), p);
   mod_p = Modular_Reducer(p);
   }

SecureVector<byte>
ElGamal_Encryption_Operation::encrypt(const byte msg[], size_t msg_len,
                                      RandomNumberGenerator& rng)
   {
   const BigInt& p = mod_p.get_modulus();

   BigInt m(msg, msg_len);

   if(m >= p)
      throw Invalid_Argument("ElGamal encryption: Input is too large");

   BigInt k(rng, 2 * dl_work_factor(p.bits()));

   BigInt a = powermod_g_p(k);
   BigInt b = mod_p.multiply(m, powermod_y_p(k));

   SecureVector<byte> output(2*p.bytes());
   a.binary_encode(&output[p.bytes() - a.bytes()]);
   b.binary_encode(&output[output.size() / 2 + (p.bytes() - b.bytes())]);
   return output;
   }

ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key)
   {
   const BigInt& p = key.group_p();

   powermod_x_p = Fixed_Exponent_Power_Mod(key.get_x(), p);
   mod_p = Modular_Reducer(p);

   BigInt k(global_state().global_rng(), p.bits() - 1);
   blinder = Blinder(k, powermod_x_p(k), p);
   }

SecureVector<byte>
ElGamal_Decryption_Operation::decrypt(const byte msg[], size_t msg_len)
   {
   const BigInt& p = mod_p.get_modulus();

   const size_t p_bytes = p.bytes();

   if(msg_len != 2 * p_bytes)
      throw Invalid_Argument("ElGamal decryption: Invalid message");

   BigInt a(msg, p_bytes);
   BigInt b(msg + p_bytes, p_bytes);

   if(a >= p || b >= p)
      throw Invalid_Argument("ElGamal decryption: Invalid message");

   a = blinder.blind(a);

   BigInt r = mod_p.multiply(b, inverse_mod(powermod_x_p(a), p));

   return BigInt::encode(blinder.unblind(r));
   }

}
/*
* GOST 34.10-2001 implemenation
* (C) 2007 Falko Strenzke, FlexSecure GmbH
*          Manuel Hartl, FlexSecure GmbH
* (C) 2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

MemoryVector<byte> GOST_3410_PublicKey::x509_subject_public_key() const
   {
   // Trust CryptoPro to come up with something obnoxious
   const BigInt x = public_point().get_affine_x();
   const BigInt y = public_point().get_affine_y();

   size_t part_size = std::max(x.bytes(), y.bytes());

   MemoryVector<byte> bits(2*part_size);

   x.binary_encode(&bits[part_size - x.bytes()]);
   y.binary_encode(&bits[2*part_size - y.bytes()]);

   // Keys are stored in little endian format (WTF)
   for(size_t i = 0; i != part_size / 2; ++i)
      {
      std::swap(bits[i], bits[part_size-1-i]);
      std::swap(bits[part_size+i], bits[2*part_size-1-i]);
      }

   return DER_Encoder().encode(bits, OCTET_STRING).get_contents();
   }

AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const
   {
   MemoryVector<byte> params =
      DER_Encoder().start_cons(SEQUENCE)
         .encode(OID(domain().get_oid()))
         .end_cons()
      .get_contents();

   return AlgorithmIdentifier(get_oid(), params);
   }

GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id,
                                         const MemoryRegion<byte>& key_bits)
   {
   OID ecc_param_id;

   // Also includes hash and cipher OIDs... brilliant design guys
   BER_Decoder(alg_id.parameters).start_cons(SEQUENCE).decode(ecc_param_id);

   domain_params = EC_Group(ecc_param_id);

   SecureVector<byte> bits;
   BER_Decoder(key_bits).decode(bits, OCTET_STRING);

   const size_t part_size = bits.size() / 2;

   // Keys are stored in little endian format (WTF)
   for(size_t i = 0; i != part_size / 2; ++i)
      {
      std::swap(bits[i], bits[part_size-1-i]);
      std::swap(bits[part_size+i], bits[2*part_size-1-i]);
      }

   BigInt x(&bits[0], part_size);
   BigInt y(&bits[part_size], part_size);

   public_key = PointGFp(domain().get_curve(), x, y);

   BOTAN_ASSERT(public_key.on_the_curve(),
                "Loaded GOST 34.10 public key not on the curve");
   }

namespace {

BigInt decode_le(const byte msg[], size_t msg_len)
   {
   SecureVector<byte> msg_le(msg, msg_len);

   for(size_t i = 0; i != msg_le.size() / 2; ++i)
      std::swap(msg_le[i], msg_le[msg_le.size()-1-i]);

   return BigInt(&msg_le[0], msg_le.size());
   }

}

GOST_3410_Signature_Operation::GOST_3410_Signature_Operation(
   const GOST_3410_PrivateKey& gost_3410) :

   base_point(gost_3410.domain().get_base_point()),
   order(gost_3410.domain().get_order()),
   x(gost_3410.private_value())
   {
   }

SecureVector<byte>
GOST_3410_Signature_Operation::sign(const byte msg[], size_t msg_len,
                                    RandomNumberGenerator& rng)
   {
   BigInt k;
   do
      k.randomize(rng, order.bits()-1);
   while(k >= order);

   BigInt e = decode_le(msg, msg_len);

   e %= order;
   if(e == 0)
      e = 1;

   PointGFp k_times_P = base_point * k;

   BOTAN_ASSERT(k_times_P.on_the_curve(),
                "GOST 34.10 k*g not on the curve");

   BigInt r = k_times_P.get_affine_x() % order;

   BigInt s = (r*x + k*e) % order;

   if(r == 0 || s == 0)
      throw Invalid_State("GOST 34.10: r == 0 || s == 0");

   SecureVector<byte> output(2*order.bytes());
   s.binary_encode(&output[output.size() / 2 - s.bytes()]);
   r.binary_encode(&output[output.size() - r.bytes()]);
   return output;
   }

GOST_3410_Verification_Operation::GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost) :
   base_point(gost.domain().get_base_point()),
   public_point(gost.public_point()),
   order(gost.domain().get_order())
   {
   }

bool GOST_3410_Verification_Operation::verify(const byte msg[], size_t msg_len,
                                              const byte sig[], size_t sig_len)
   {
   if(sig_len != order.bytes()*2)
      return false;

   BigInt e = decode_le(msg, msg_len);

   BigInt s(sig, sig_len / 2);
   BigInt r(sig + sig_len / 2, sig_len / 2);

   if(r <= 0 || r >= order || s <= 0 || s >= order)
      return false;

   e %= order;
   if(e == 0)
      e = 1;

   BigInt v = inverse_mod(e, order);

   BigInt z1 = (s*v) % order;
   BigInt z2 = (-r*v) % order;

   PointGFp R = multi_exponentiate(base_point, z1,
                                   public_point, z2);

   if(R.is_zero())
     return false;

   return (R.get_affine_x() == r);
   }

}
/*
* IF Scheme
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

AlgorithmIdentifier IF_Scheme_PublicKey::algorithm_identifier() const
   {
   return AlgorithmIdentifier(get_oid(),
                              AlgorithmIdentifier::USE_NULL_PARAM);
   }

MemoryVector<byte> IF_Scheme_PublicKey::x509_subject_public_key() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode(n)
         .encode(e)
      .end_cons()
      .get_contents();
   }

IF_Scheme_PublicKey::IF_Scheme_PublicKey(const AlgorithmIdentifier&,
                                         const MemoryRegion<byte>& key_bits)
   {
   BER_Decoder(key_bits)
      .start_cons(SEQUENCE)
        .decode(n)
        .decode(e)
      .verify_end()
      .end_cons();
   }

/*
* Check IF Scheme Public Parameters
*/
bool IF_Scheme_PublicKey::check_key(RandomNumberGenerator&, bool) const
   {
   if(n < 35 || n.is_even() || e < 2)
      return false;
   return true;
   }

MemoryVector<byte> IF_Scheme_PrivateKey::pkcs8_private_key() const
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .encode(static_cast<size_t>(0))
         .encode(n)
         .encode(e)
         .encode(d)
         .encode(p)
         .encode(q)
         .encode(d1)
         .encode(d2)
         .encode(c)
      .end_cons()
   .get_contents();
   }

IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng,
                                           const AlgorithmIdentifier&,
                                           const MemoryRegion<byte>& key_bits)
   {
   BER_Decoder(key_bits)
      .start_cons(SEQUENCE)
         .decode_and_check<size_t>(0, "Unknown PKCS #1 key format version")
         .decode(n)
         .decode(e)
         .decode(d)
         .decode(p)
         .decode(q)
         .decode(d1)
         .decode(d2)
         .decode(c)
      .end_cons();

   load_check(rng);
   }

IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng,
                                           const BigInt& prime1,
                                           const BigInt& prime2,
                                           const BigInt& exp,
                                           const BigInt& d_exp,
                                           const BigInt& mod)
   {
   p = prime1;
   q = prime2;
   e = exp;
   d = d_exp;
   n = mod.is_nonzero() ? mod : p * q;

   if(d == 0)
      {
      BigInt inv_for_d = lcm(p - 1, q - 1);
      if(e.is_even())
         inv_for_d >>= 1;

      d = inverse_mod(e, inv_for_d);
      }

   d1 = d % (p - 1);
   d2 = d % (q - 1);
   c = inverse_mod(q, p);

   load_check(rng);
   }

/*
* Check IF Scheme Private Parameters
*/
bool IF_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng,
                                     bool strong) const
   {
   if(n < 35 || n.is_even() || e < 2 || d < 2 || p < 3 || q < 3 || p*q != n)
      return false;

   if(!strong)
      return true;

   if(d1 != d % (p - 1) || d2 != d % (q - 1) || c != inverse_mod(q, p))
      return false;
   if(!check_prime(p, rng) || !check_prime(q, rng))
      return false;
   return true;
   }

}
/*
* Keypair Checks
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace KeyPair {

/*
* Check an encryption key pair for consistency
*/
bool encryption_consistency_check(RandomNumberGenerator& rng,
                                  const Private_Key& key,
                                  const std::string& padding)
   {
   PK_Encryptor_EME encryptor(key, padding);
   PK_Decryptor_EME decryptor(key, padding);

   /*
   Weird corner case, if the key is too small to encrypt anything at
   all. This can happen with very small RSA keys with PSS
   */
   if(encryptor.maximum_input_size() == 0)
      return true;

   SecureVector<byte> plaintext =
      rng.random_vec(encryptor.maximum_input_size() - 1);

   SecureVector<byte> ciphertext = encryptor.encrypt(plaintext, rng);
   if(ciphertext == plaintext)
      return false;

   SecureVector<byte> decrypted = decryptor.decrypt(ciphertext);

   return (plaintext == decrypted);
   }

/*
* Check a signature key pair for consistency
*/
bool signature_consistency_check(RandomNumberGenerator& rng,
                                 const Private_Key& key,
                                 const std::string& padding)
   {
   PK_Signer signer(key, padding);
   PK_Verifier verifier(key, padding);

   SecureVector<byte> message = rng.random_vec(16);

   SecureVector<byte> signature;

   try
      {
      signature = signer.sign_message(message, rng);
      }
   catch(Encoding_Error)
      {
      return false;
      }

   if(!verifier.verify_message(message, signature))
      return false;

   // Now try to check a corrupt signature, ensure it does not succeed
   ++message[0];

   if(verifier.verify_message(message, signature))
      return false;

   return true;
   }

}

}
/*
* Nyberg-Rueppel
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

NR_PublicKey::NR_PublicKey(const AlgorithmIdentifier& alg_id,
                           const MemoryRegion<byte>& key_bits) :
   DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57)
   {
   }

/*
* NR_PublicKey Constructor
*/
NR_PublicKey::NR_PublicKey(const DL_Group& grp, const BigInt& y1)
   {
   group = grp;
   y = y1;
   }

/*
* Create a NR private key
*/
NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng,
                             const DL_Group& grp,
                             const BigInt& x_arg)
   {
   group = grp;
   x = x_arg;

   if(x == 0)
      x = BigInt::random_integer(rng, 2, group_q() - 1);

   y = power_mod(group_g(), x, group_p());

   if(x_arg == 0)
      gen_check(rng);
   else
      load_check(rng);
   }

NR_PrivateKey::NR_PrivateKey(const AlgorithmIdentifier& alg_id,
                             const MemoryRegion<byte>& key_bits,
                             RandomNumberGenerator& rng) :
   DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57)
   {
   y = power_mod(group_g(), x, group_p());

   load_check(rng);
   }

/*
* Check Private Nyberg-Rueppel Parameters
*/
bool NR_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
   {
   if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q())
      return false;

   if(!strong)
      return true;

   return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
   }

NR_Signature_Operation::NR_Signature_Operation(const NR_PrivateKey& nr) :
   q(nr.group_q()),
   x(nr.get_x()),
   powermod_g_p(nr.group_g(), nr.group_p()),
   mod_q(nr.group_q())
   {
   }

SecureVector<byte>
NR_Signature_Operation::sign(const byte msg[], size_t msg_len,
                             RandomNumberGenerator& rng)
   {
   rng.add_entropy(msg, msg_len);

   BigInt f(msg, msg_len);

   if(f >= q)
      throw Invalid_Argument("NR_Signature_Operation: Input is out of range");

   BigInt c, d;

   while(c == 0)
      {
      BigInt k;
      do
         k.randomize(rng, q.bits());
      while(k >= q);

      c = mod_q.reduce(powermod_g_p(k) + f);
      d = mod_q.reduce(k - x * c);
      }

   SecureVector<byte> output(2*q.bytes());
   c.binary_encode(&output[output.size() / 2 - c.bytes()]);
   d.binary_encode(&output[output.size() - d.bytes()]);
   return output;
   }

NR_Verification_Operation::NR_Verification_Operation(const NR_PublicKey& nr) :
   q(nr.group_q()), y(nr.get_y())
   {
   powermod_g_p = Fixed_Base_Power_Mod(nr.group_g(), nr.group_p());
   powermod_y_p = Fixed_Base_Power_Mod(y, nr.group_p());
   mod_p = Modular_Reducer(nr.group_p());
   mod_q = Modular_Reducer(nr.group_q());
   }

SecureVector<byte>
NR_Verification_Operation::verify_mr(const byte msg[], size_t msg_len)
   {
   const BigInt& q = mod_q.get_modulus();

   if(msg_len != 2*q.bytes())
      throw Invalid_Argument("NR verification: Invalid signature");

   BigInt c(msg, q.bytes());
   BigInt d(msg + q.bytes(), q.bytes());

   if(c.is_zero() || c >= q || d >= q)
      throw Invalid_Argument("NR verification: Invalid signature");

   BigInt i = mod_p.multiply(powermod_g_p(d), powermod_y_p(c));
   return BigInt::encode(mod_q.reduce(c - i));
   }

}
/*
* PK Key
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_RSA)
#endif

#if defined(BOTAN_HAS_DSA)
#endif

#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
#endif

#if defined(BOTAN_HAS_ECDSA)
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
#endif

#if defined(BOTAN_HAS_RW)
#endif

#if defined(BOTAN_HAS_ELGAMAL)
#endif

#if defined(BOTAN_HAS_ECDH)
#endif

namespace Botan {

Public_Key* make_public_key(const AlgorithmIdentifier& alg_id,
                            const MemoryRegion<byte>& key_bits)
   {
   const std::string alg_name = OIDS::lookup(alg_id.oid);
   if(alg_name == "")
      throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string());

#if defined(BOTAN_HAS_RSA)
   if(alg_name == "RSA")
      return new RSA_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_RW)
   if(alg_name == "RW")
      return new RW_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_DSA)
   if(alg_name == "DSA")
      return new DSA_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
   if(alg_name == "DH")
      return new DH_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
   if(alg_name == "NR")
      return new NR_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_ELGAMAL)
   if(alg_name == "ElGamal")
      return new ElGamal_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_ECDSA)
   if(alg_name == "ECDSA")
      return new ECDSA_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
   if(alg_name == "GOST-34.10")
      return new GOST_3410_PublicKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_ECDH)
   if(alg_name == "ECDH")
      return new ECDH_PublicKey(alg_id, key_bits);
#endif

   return 0;
   }

Private_Key* make_private_key(const AlgorithmIdentifier& alg_id,
                              const MemoryRegion<byte>& key_bits,
                              RandomNumberGenerator& rng)
   {
   const std::string alg_name = OIDS::lookup(alg_id.oid);
   if(alg_name == "")
      throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string());

#if defined(BOTAN_HAS_RSA)
   if(alg_name == "RSA")
      return new RSA_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_RW)
   if(alg_name == "RW")
      return new RW_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_DSA)
   if(alg_name == "DSA")
      return new DSA_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
   if(alg_name == "DH")
      return new DH_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
   if(alg_name == "NR")
      return new NR_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_ELGAMAL)
   if(alg_name == "ElGamal")
      return new ElGamal_PrivateKey(alg_id, key_bits, rng);
#endif

#if defined(BOTAN_HAS_ECDSA)
   if(alg_name == "ECDSA")
      return new ECDSA_PrivateKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
   if(alg_name == "GOST-34.10")
      return new GOST_3410_PrivateKey(alg_id, key_bits);
#endif

#if defined(BOTAN_HAS_ECDH)
   if(alg_name == "ECDH")
      return new ECDH_PrivateKey(alg_id, key_bits);
#endif

   return 0;
   }

}
/*
* PK Key Types
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Default OID access
*/
OID Public_Key::get_oid() const
   {
   try {
      return OIDS::lookup(algo_name());
      }
   catch(Lookup_Error)
      {
      throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs");
      }
   }

/*
* Run checks on a loaded public key
*/
void Public_Key::load_check(RandomNumberGenerator& rng) const
   {
   if(!check_key(rng, BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD))
      throw Invalid_Argument(algo_name() + ": Invalid public key");
   }

/*
* Run checks on a loaded private key
*/
void Private_Key::load_check(RandomNumberGenerator& rng) const
   {
   if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD))
      throw Invalid_Argument(algo_name() + ": Invalid private key");
   }

/*
* Run checks on a generated private key
*/
void Private_Key::gen_check(RandomNumberGenerator& rng) const
   {
   if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE))
      throw Self_Test_Failure(algo_name() + " private key generation failed");
   }

}
/*
* PKCS #8
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace PKCS8 {

namespace {

/*
* Get info from an EncryptedPrivateKeyInfo
*/
SecureVector<byte> PKCS8_extract(DataSource& source,
                                 AlgorithmIdentifier& pbe_alg_id)
   {
   SecureVector<byte> key_data;

   BER_Decoder(source)
      .start_cons(SEQUENCE)
         .decode(pbe_alg_id)
         .decode(key_data, OCTET_STRING)
      .verify_end();

   return key_data;
   }

/*
* PEM decode and/or decrypt a private key
*/
SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui,
                                AlgorithmIdentifier& pk_alg_id)
   {
   AlgorithmIdentifier pbe_alg_id;
   SecureVector<byte> key_data, key;
   bool is_encrypted = true;

   try {
      if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
         key_data = PKCS8_extract(source, pbe_alg_id);
      else
         {
         std::string label;
         key_data = PEM_Code::decode(source, label);
         if(label == "PRIVATE KEY")
            is_encrypted = false;
         else if(label == "ENCRYPTED PRIVATE KEY")
            {
            DataSource_Memory key_source(key_data);
            key_data = PKCS8_extract(key_source, pbe_alg_id);
            }
         else
            throw PKCS8_Exception("Unknown PEM label " + label);
         }

      if(key_data.empty())
         throw PKCS8_Exception("No key data found");
      }
   catch(Decoding_Error)
      {
      throw Decoding_Error("PKCS #8 private key decoding failed");
      }

   if(!is_encrypted)
      key = key_data;

   const size_t MAX_TRIES = 3;

   size_t tries = 0;
   while(true)
      {
      try {
         if(MAX_TRIES && tries >= MAX_TRIES)
            break;

         if(is_encrypted)
            {
            DataSource_Memory params(pbe_alg_id.parameters);
            std::auto_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));

            User_Interface::UI_Result result = User_Interface::OK;
            const std::string passphrase =
               ui.get_passphrase("PKCS #8 private key", source.id(), result);

            if(result == User_Interface::CANCEL_ACTION)
               break;

            pbe->set_key(passphrase);
            Pipe decryptor(pbe.release());

            decryptor.process_msg(key_data);
            key = decryptor.read_all();
            }

         BER_Decoder(key)
            .start_cons(SEQUENCE)
               .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
               .decode(pk_alg_id)
               .decode(key, OCTET_STRING)
               .discard_remaining()
            .end_cons();

         break;
         }
      catch(Decoding_Error)
         {
         ++tries;
         }
      }

   if(key.empty())
      throw Decoding_Error("PKCS #8 private key decoding failed");
   return key;
   }

}

/*
* BER encode a PKCS #8 private key, unencrypted
*/
SecureVector<byte> BER_encode(const Private_Key& key)
   {
   const size_t PKCS8_VERSION = 0;

   return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(PKCS8_VERSION)
            .encode(key.pkcs8_algorithm_identifier())
            .encode(key.pkcs8_private_key(), OCTET_STRING)
         .end_cons()
      .get_contents();
   }

/*
* PEM encode a PKCS #8 private key, unencrypted
*/
std::string PEM_encode(const Private_Key& key)
   {
   return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY");
   }

/*
* BER encode a PKCS #8 private key, encrypted
*/
SecureVector<byte> BER_encode(const Private_Key& key,
                              RandomNumberGenerator& rng,
                              const std::string& pass,
                              const std::string& pbe_algo)
   {
   const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)";

   std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));

   pbe->new_params(rng);
   pbe->set_key(pass);

   AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params());

   Pipe key_encrytor(pbe.release());
   key_encrytor.process_msg(PKCS8::BER_encode(key));

   return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(pbe_algid)
            .encode(key_encrytor.read_all(), OCTET_STRING)
         .end_cons()
      .get_contents();
   }

/*
* PEM encode a PKCS #8 private key, encrypted
*/
std::string PEM_encode(const Private_Key& key,
                       RandomNumberGenerator& rng,
                       const std::string& pass,
                       const std::string& pbe_algo)
   {
   if(pass == "")
      return PEM_encode(key);

   return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, pbe_algo),
                           "ENCRYPTED PRIVATE KEY");
   }

/*
* Extract a private key and return it
*/
Private_Key* load_key(DataSource& source,
                      RandomNumberGenerator& rng,
                      const User_Interface& ui)
   {
   AlgorithmIdentifier alg_id;
   SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id);

   const std::string alg_name = OIDS::lookup(alg_id.oid);
   if(alg_name == "" || alg_name == alg_id.oid.as_string())
      throw PKCS8_Exception("Unknown algorithm OID: " +
                            alg_id.oid.as_string());

   return make_private_key(alg_id, pkcs8_key, rng);
   }

/*
* Extract a private key and return it
*/
Private_Key* load_key(const std::string& fsname,
                      RandomNumberGenerator& rng,
                      const User_Interface& ui)
   {
   DataSource_Stream source(fsname, true);
   return PKCS8::load_key(source, rng, ui);
   }

/*
* Extract a private key and return it
*/
Private_Key* load_key(DataSource& source,
                      RandomNumberGenerator& rng,
                      const std::string& pass)
   {
   return PKCS8::load_key(source, rng, User_Interface(pass));
   }

/*
* Extract a private key and return it
*/
Private_Key* load_key(const std::string& fsname,
                      RandomNumberGenerator& rng,
                      const std::string& pass)
   {
   return PKCS8::load_key(fsname, rng, User_Interface(pass));
   }

/*
* Make a copy of this private key
*/
Private_Key* copy_key(const Private_Key& key,
                      RandomNumberGenerator& rng)
   {
   DataSource_Memory source(PEM_encode(key));
   return PKCS8::load_key(source, rng);
   }

}

}
/*
* Public Key Base
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

/*
* PK_Encryptor_EME Constructor
*/
PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key,
                                   const std::string& eme_name)
   {
   Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

   while(const Engine* engine = i.next())
      {
      op = engine->get_encryption_op(key);
      if(op)
         break;
      }

   if(!op)
      throw Lookup_Error("PK_Encryptor_EME: No working engine for " +
                         key.algo_name());

   eme = (eme_name == "Raw") ? 0 : get_eme(eme_name);
   }

/*
* Encrypt a message
*/
SecureVector<byte>
PK_Encryptor_EME::enc(const byte in[],
                      size_t length,
                      RandomNumberGenerator& rng) const
   {
   if(eme)
      {
      SecureVector<byte> encoded =
         eme->encode(in, length, op->max_input_bits(), rng);

      if(8*(encoded.size() - 1) + high_bit(encoded[0]) > op->max_input_bits())
         throw Invalid_Argument("PK_Encryptor_EME: Input is too large");

      return op->encrypt(&encoded[0], encoded.size(), rng);
      }
   else
      {
      if(8*(length - 1) + high_bit(in[0]) > op->max_input_bits())
         throw Invalid_Argument("PK_Encryptor_EME: Input is too large");

      return op->encrypt(&in[0], length, rng);
      }
   }

/*
* Return the max size, in bytes, of a message
*/
size_t PK_Encryptor_EME::maximum_input_size() const
   {
   if(!eme)
      return (op->max_input_bits() / 8);
   else
      return eme->maximum_input_size(op->max_input_bits());
   }

/*
* PK_Decryptor_EME Constructor
*/
PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key,
                                   const std::string& eme_name)
   {
   Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

   while(const Engine* engine = i.next())
      {
      op = engine->get_decryption_op(key);
      if(op)
         break;
      }

   if(!op)
      throw Lookup_Error("PK_Decryptor_EME: No working engine for " +
                         key.algo_name());

   eme = (eme_name == "Raw") ? 0 : get_eme(eme_name);
   }

/*
* Decrypt a message
*/
SecureVector<byte> PK_Decryptor_EME::dec(const byte msg[],
                                         size_t length) const
   {
   try {
      SecureVector<byte> decrypted = op->decrypt(msg, length);
      if(eme)
         return eme->decode(decrypted, op->max_input_bits());
      else
         return decrypted;
      }
   catch(Invalid_Argument)
      {
      throw Decoding_Error("PK_Decryptor_EME: Input is invalid");
      }
   }

/*
* PK_Signer Constructor
*/
PK_Signer::PK_Signer(const Private_Key& key,
                     const std::string& emsa_name,
                     Signature_Format format,
                     Fault_Protection prot)
   {
   Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

   op = 0;
   verify_op = 0;

   while(const Engine* engine = i.next())
      {
      if(!op)
         op = engine->get_signature_op(key);

      if(!verify_op && prot == ENABLE_FAULT_PROTECTION)
         verify_op = engine->get_verify_op(key);

      if(op && (verify_op || prot == DISABLE_FAULT_PROTECTION))
         break;
      }

   if(!op || (!verify_op && prot == ENABLE_FAULT_PROTECTION))
      throw Lookup_Error("PK_Signer: No working engine for " +
                         key.algo_name());

   emsa = get_emsa(emsa_name);
   sig_format = format;
   }

/*
* Sign a message
*/
SecureVector<byte> PK_Signer::sign_message(const byte msg[], size_t length,
                                           RandomNumberGenerator& rng)
   {
   update(msg, length);
   return signature(rng);
   }

/*
* Add more to the message to be signed
*/
void PK_Signer::update(const byte in[], size_t length)
   {
   emsa->update(in, length);
   }

/*
* Check the signature we just created, to help prevent fault attacks
*/
bool PK_Signer::self_test_signature(const MemoryRegion<byte>& msg,
                                    const MemoryRegion<byte>& sig) const
   {
   if(!verify_op)
      return true; // checking disabled, assume ok

   if(verify_op->with_recovery())
      {
      SecureVector<byte> recovered =
         verify_op->verify_mr(&sig[0], sig.size());

      if(msg.size() > recovered.size())
         {
         size_t extra_0s = msg.size() - recovered.size();

         for(size_t i = 0; i != extra_0s; ++i)
            if(msg[i] != 0)
               return false;

         return same_mem(&msg[extra_0s], &recovered[0], recovered.size());
         }

      return (recovered == msg);
      }
   else
      return verify_op->verify(&msg[0], msg.size(),
                               &sig[0], sig.size());
   }

/*
* Create a signature
*/
SecureVector<byte> PK_Signer::signature(RandomNumberGenerator& rng)
   {
   SecureVector<byte> encoded = emsa->encoding_of(emsa->raw_data(),
                                                  op->max_input_bits(),
                                                  rng);

   SecureVector<byte> plain_sig = op->sign(&encoded[0], encoded.size(), rng);

   BOTAN_ASSERT(self_test_signature(encoded, plain_sig),
                "PK_Signer consistency check failed");

   if(op->message_parts() == 1 || sig_format == IEEE_1363)
      return plain_sig;

   if(sig_format == DER_SEQUENCE)
      {
      if(plain_sig.size() % op->message_parts())
         throw Encoding_Error("PK_Signer: strange signature size found");
      const size_t SIZE_OF_PART = plain_sig.size() / op->message_parts();

      std::vector<BigInt> sig_parts(op->message_parts());
      for(size_t j = 0; j != sig_parts.size(); ++j)
         sig_parts[j].binary_decode(&plain_sig[SIZE_OF_PART*j], SIZE_OF_PART);

      return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode_list(sig_parts)
         .end_cons()
      .get_contents();
      }
   else
      throw Encoding_Error("PK_Signer: Unknown signature format " +
                           to_string(sig_format));
   }

/*
* PK_Verifier Constructor
*/
PK_Verifier::PK_Verifier(const Public_Key& key,
                         const std::string& emsa_name,
                         Signature_Format format)
   {
   Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

   while(const Engine* engine = i.next())
      {
      op = engine->get_verify_op(key);
      if(op)
         break;
      }

   if(!op)
      throw Lookup_Error("PK_Verifier: No working engine for " +
                         key.algo_name());

   emsa = get_emsa(emsa_name);
   sig_format = format;
   }

/*
* Set the signature format
*/
void PK_Verifier::set_input_format(Signature_Format format)
   {
   if(op->message_parts() == 1 && format != IEEE_1363)
      throw Invalid_State("PK_Verifier: This algorithm always uses IEEE 1363");
   sig_format = format;
   }

/*
* Verify a message
*/
bool PK_Verifier::verify_message(const byte msg[], size_t msg_length,
                                 const byte sig[], size_t sig_length)
   {
   update(msg, msg_length);
   return check_signature(sig, sig_length);
   }

/*
* Append to the message
*/
void PK_Verifier::update(const byte in[], size_t length)
   {
   emsa->update(in, length);
   }

/*
* Check a signature
*/
bool PK_Verifier::check_signature(const byte sig[], size_t length)
   {
   try {
      if(sig_format == IEEE_1363)
         return validate_signature(emsa->raw_data(), sig, length);
      else if(sig_format == DER_SEQUENCE)
         {
         BER_Decoder decoder(sig, length);
         BER_Decoder ber_sig = decoder.start_cons(SEQUENCE);

         size_t count = 0;
         SecureVector<byte> real_sig;
         while(ber_sig.more_items())
            {
            BigInt sig_part;
            ber_sig.decode(sig_part);
            real_sig += BigInt::encode_1363(sig_part, op->message_part_size());
            ++count;
            }

         if(count != op->message_parts())
            throw Decoding_Error("PK_Verifier: signature size invalid");

         return validate_signature(emsa->raw_data(),
                                   &real_sig[0], real_sig.size());
         }
      else
         throw Decoding_Error("PK_Verifier: Unknown signature format " +
                              to_string(sig_format));
      }
   catch(Invalid_Argument) { return false; }
   }

/*
* Verify a signature
*/
bool PK_Verifier::validate_signature(const MemoryRegion<byte>& msg,
                                     const byte sig[], size_t sig_len)
   {
   if(op->with_recovery())
      {
      SecureVector<byte> output_of_key = op->verify_mr(sig, sig_len);
      return emsa->verify(output_of_key, msg, op->max_input_bits());
      }
   else
      {
      Null_RNG rng;

      SecureVector<byte> encoded =
         emsa->encoding_of(msg, op->max_input_bits(), rng);

      return op->verify(&encoded[0], encoded.size(), sig, sig_len);
      }
   }

/*
* PK_Key_Agreement Constructor
*/
PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& key,
                                   const std::string& kdf_name)
   {
   Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());

   while(const Engine* engine = i.next())
      {
      op = engine->get_key_agreement_op(key);
      if(op)
         break;
      }

   if(!op)
      throw Lookup_Error("PK_Key_Agreement: No working engine for " +
                         key.algo_name());

   kdf = (kdf_name == "Raw") ? 0 : get_kdf(kdf_name);
   }

SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, const byte in[],
                                          size_t in_len, const byte params[],
                                          size_t params_len) const
   {
   SecureVector<byte> z = op->agree(in, in_len);

   if(!kdf)
      return z;

   return kdf->derive_key(key_len, z, params, params_len);
   }

}
/*
* KeyUsage
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace BER {

/*
* Decode a BER encoded KeyUsage
*/
void decode(BER_Decoder& source, Key_Constraints& key_usage)
   {
   BER_Object obj = source.get_next_object();

   if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
      throw BER_Bad_Tag("Bad tag for usage constraint",
                        obj.type_tag, obj.class_tag);
   if(obj.value.size() != 2 && obj.value.size() != 3)
      throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
   if(obj.value[0] >= 8)
      throw BER_Decoding_Error("Invalid unused bits in usage constraint");

   const byte mask = (0xFF << obj.value[0]);
   obj.value[obj.value.size()-1] &= mask;

   u16bit usage = 0;
   for(size_t j = 1; j != obj.value.size(); ++j)
      usage = (obj.value[j] << 8) | usage;

   key_usage = Key_Constraints(usage);
   }

}

}
/*
* RSA
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Create a RSA private key
*/
RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng,
                               size_t bits, size_t exp)
   {
   if(bits < 512)
      throw Invalid_Argument(algo_name() + ": Can't make a key that is only " +
                             to_string(bits) + " bits long");
   if(exp < 3 || exp % 2 == 0)
      throw Invalid_Argument(algo_name() + ": Invalid encryption exponent");

   e = exp;

   do
      {
      p = random_prime(rng, (bits + 1) / 2, e);
      q = random_prime(rng, bits - p.bits(), e);
      n = p * q;
      } while(n.bits() != bits);

   d = inverse_mod(e, lcm(p - 1, q - 1));
   d1 = d % (p - 1);
   d2 = d % (q - 1);
   c = inverse_mod(q, p);

   gen_check(rng);
   }

/*
* Check Private RSA Parameters
*/
bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
   {
   if(!IF_Scheme_PrivateKey::check_key(rng, strong))
      return false;

   if(!strong)
      return true;

   if((e * d) % lcm(p - 1, q - 1) != 1)
      return false;

   return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-1)");
   }

RSA_Private_Operation::RSA_Private_Operation(const RSA_PrivateKey& rsa) :
   n(rsa.get_n()),
   q(rsa.get_q()),
   c(rsa.get_c()),
   powermod_e_n(rsa.get_e(), rsa.get_n()),
   powermod_d1_p(rsa.get_d1(), rsa.get_p()),
   powermod_d2_q(rsa.get_d2(), rsa.get_q()),
   mod_p(rsa.get_p())
   {
   BigInt k(global_state().global_rng(), n.bits() - 1);
   blinder = Blinder(powermod_e_n(k), inverse_mod(k, n), n);
   }

BigInt RSA_Private_Operation::private_op(const BigInt& m) const
   {
   if(m >= n)
      throw Invalid_Argument("RSA private op - input is too large");

   BigInt j1 = powermod_d1_p(m);
   BigInt j2 = powermod_d2_q(m);

   j1 = mod_p.reduce(sub_mul(j1, j2, c));

   return mul_add(j1, q, j2);
   }

SecureVector<byte>
RSA_Private_Operation::sign(const byte msg[], size_t msg_len,
                            RandomNumberGenerator&)
   {
   /* We don't check signatures against powermod_e_n here because
      PK_Signer checks verification consistency for all signature
      algorithms.
   */

   BigInt m(msg, msg_len);
   BigInt x = blinder.unblind(private_op(blinder.blind(m)));
   return BigInt::encode_1363(x, n.bytes());
   }

/*
* RSA Decryption Operation
*/
SecureVector<byte>
RSA_Private_Operation::decrypt(const byte msg[], size_t msg_len)
   {
   BigInt m(msg, msg_len);
   BigInt x = blinder.unblind(private_op(blinder.blind(m)));

   BOTAN_ASSERT(m == powermod_e_n(x),
                "RSA private op failed consistency check");

   return BigInt::encode(x);
   }

}
/*
* Rabin-Williams
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Create a Rabin-Williams private key
*/
RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng,
                             size_t bits, size_t exp)
   {
   if(bits < 512)
      throw Invalid_Argument(algo_name() + ": Can't make a key that is only " +
                             to_string(bits) + " bits long");
   if(exp < 2 || exp % 2 == 1)
      throw Invalid_Argument(algo_name() + ": Invalid encryption exponent");

   e = exp;

   do
      {
      p = random_prime(rng, (bits + 1) / 2, e / 2, 3, 4);
      q = random_prime(rng, bits - p.bits(), e / 2, ((p % 8 == 3) ? 7 : 3), 8);
      n = p * q;
      } while(n.bits() != bits);

   d = inverse_mod(e, lcm(p - 1, q - 1) >> 1);
   d1 = d % (p - 1);
   d2 = d % (q - 1);
   c = inverse_mod(q, p);

   gen_check(rng);
   }

/*
* Check Private Rabin-Williams Parameters
*/
bool RW_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
   {
   if(!IF_Scheme_PrivateKey::check_key(rng, strong))
      return false;

   if(!strong)
      return true;

   if((e * d) % (lcm(p - 1, q - 1) / 2) != 1)
      return false;

   return KeyPair::signature_consistency_check(rng, *this, "EMSA2(SHA-1)");
   }

RW_Signature_Operation::RW_Signature_Operation(const RW_PrivateKey& rw) :
   n(rw.get_n()),
   e(rw.get_e()),
   q(rw.get_q()),
   c(rw.get_c()),
   powermod_d1_p(rw.get_d1(), rw.get_p()),
   powermod_d2_q(rw.get_d2(), rw.get_q()),
   mod_p(rw.get_p())
   {
   }

SecureVector<byte>
RW_Signature_Operation::sign(const byte msg[], size_t msg_len,
                             RandomNumberGenerator& rng)
   {
   if(!blinder.initialized())
      {
      BigInt k(rng, n.bits() / 2);
      blinder = Blinder(power_mod(k, e, n), inverse_mod(k, n), n);
      }

   BigInt i(msg, msg_len);

   if(i >= n || i % 16 != 12)
      throw Invalid_Argument("Rabin-Williams: invalid input");

   if(jacobi(i, n) != 1)
      i >>= 1;

   i = blinder.blind(i);

   BigInt j1 = powermod_d1_p(i);
   BigInt j2 = powermod_d2_q(i);
   j1 = mod_p.reduce(sub_mul(j1, j2, c));

   BigInt r = blinder.unblind(mul_add(j1, q, j2));

   r = std::min(r, n - r);

   return BigInt::encode_1363(r, n.bytes());
   }

SecureVector<byte>
RW_Verification_Operation::verify_mr(const byte msg[], size_t msg_len)
   {
   BigInt m(msg, msg_len);

   if((m > (n >> 1)) || m.is_negative())
      throw Invalid_Argument("RW signature verification: m > n / 2 || m < 0");

   BigInt r = powermod_e_n(m);
   if(r % 16 == 12)
      return BigInt::encode(r);
   if(r % 8 == 6)
      return BigInt::encode(2*r);

   r = n - r;
   if(r % 16 == 12)
      return BigInt::encode(r);
   if(r % 8 == 6)
      return BigInt::encode(2*r);

   throw Invalid_Argument("RW signature verification: Invalid signature");
   }

}
/*
* Public Key Work Factor Functions
* (C) 1999-2007,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>
#include <cmath>

namespace Botan {

size_t dl_work_factor(size_t bits)
   {
   /*
   Based on GNFS work factors. Constant is 1.43 times the asymptotic
   value; I'm not sure but I believe that came from a paper on 'real
   world' runtimes, but I don't remember where now.

   Sample return values:
      |512|  -> 64
      |1024| -> 86
      |1536| -> 102
      |2048| -> 116
      |3072| -> 138
      |4096| -> 155
      |8192| -> 206

   For DL algos, we use an exponent of twice the size of the result;
   the assumption is that an arbitrary discrete log on a group of size
   bits would take about 2^n effort, and thus using an exponent of
   size 2^(2*n) implies that all available attacks are about as easy
   (as e.g Pollard's kangaroo algorithm can compute the DL in sqrt(x)
   operations) while minimizing the exponent size for performance
   reasons.
   */

   const size_t MIN_WORKFACTOR = 64;

   // approximates natural logarithm of p
   const double log_p = bits / 1.4426;

   const double strength =
      2.76 * std::pow(log_p, 1.0/3.0) * std::pow(std::log(log_p), 2.0/3.0);

   return std::max(static_cast<size_t>(strength), MIN_WORKFACTOR);
   }

}
/*
* X.509 Public Key
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <memory>

namespace Botan {

namespace X509 {

MemoryVector<byte> BER_encode(const Public_Key& key)
   {
   return DER_Encoder()
         .start_cons(SEQUENCE)
            .encode(key.algorithm_identifier())
            .encode(key.x509_subject_public_key(), BIT_STRING)
         .end_cons()
      .get_contents();
   }

/*
* PEM encode a X.509 public key
*/
std::string PEM_encode(const Public_Key& key)
   {
   return PEM_Code::encode(X509::BER_encode(key),
                           "PUBLIC KEY");
   }

/*
* Extract a public key and return it
*/
Public_Key* load_key(DataSource& source)
   {
   try {
      AlgorithmIdentifier alg_id;
      MemoryVector<byte> key_bits;

      if(ASN1::maybe_BER(source) && !PEM_Code::matches(source))
         {
         BER_Decoder(source)
            .start_cons(SEQUENCE)
            .decode(alg_id)
            .decode(key_bits, BIT_STRING)
            .verify_end()
         .end_cons();
         }
      else
         {
         DataSource_Memory ber(
            PEM_Code::decode_check_label(source, "PUBLIC KEY")
            );

         BER_Decoder(ber)
            .start_cons(SEQUENCE)
            .decode(alg_id)
            .decode(key_bits, BIT_STRING)
            .verify_end()
         .end_cons();
         }

      if(key_bits.empty())
         throw Decoding_Error("X.509 public key decoding failed");

      return make_public_key(alg_id, key_bits);
      }
   catch(Decoding_Error)
      {
      throw Decoding_Error("X.509 public key decoding failed");
      }
   }

/*
* Extract a public key and return it
*/
Public_Key* load_key(const std::string& fsname)
   {
   DataSource_Stream source(fsname, true);
   return X509::load_key(source);
   }

/*
* Extract a public key and return it
*/
Public_Key* load_key(const MemoryRegion<byte>& mem)
   {
   DataSource_Memory source(mem);
   return X509::load_key(source);
   }

/*
* Make a copy of this public key
*/
Public_Key* copy_key(const Public_Key& key)
   {
   DataSource_Memory source(PEM_encode(key));
   return X509::load_key(source);
   }

/*
* Find the allowable key constraints
*/
Key_Constraints find_constraints(const Public_Key& pub_key,
                                 Key_Constraints limits)
   {
   const std::string name = pub_key.algo_name();

   size_t constraints = 0;

   if(name == "DH" || name == "ECDH")
      constraints |= KEY_AGREEMENT;

   if(name == "RSA" || name == "ElGamal")
      constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;

   if(name == "RSA" || name == "RW" || name == "NR" ||
      name == "DSA" || name == "ECDSA")
      constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION;

   if(limits)
      constraints &= limits;

   return Key_Constraints(constraints);
   }

}

}
/*
* HMAC_RNG
* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode* prf,
              MemoryRegion<byte>& K,
              u32bit& counter,
              const std::string& label)
   {
   prf->update(K);
   prf->update(label);
   prf->update_be(counter);
   prf->final(&K[0]);

   ++counter;
   }

}

/*
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], size_t length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(prf, K, counter, "rng");

      const size_t copied = std::min<size_t>(K.size(), length);

      copy_mem(out, &K[0], copied);
      out += copied;
      length -= copied;
      }
   }

/*
* Poll for entropy and reset the internal keys
*/
void HMAC_RNG::reseed(size_t poll_bits)
   {
   /*
   Using the terminology of E-t-E, XTR is the MAC function (normally
   HMAC) seeded with XTS (below) and we form SKM, the key material, by
   fast polling each source, and then slow polling as many as we think
   we need (in the following loop), and feeding all of the poll
   results, along with any optional user input, along with, finally,
   feedback of the current PRK value, into the extractor function.
   */

   Entropy_Accumulator_BufferedComputation accum(*extractor, poll_bits);

   if(!entropy_sources.empty())
      {
      size_t poll_attempt = 0;

      while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
         {
         const size_t src_idx = poll_attempt % entropy_sources.size();
         entropy_sources[src_idx]->poll(accum);
         ++poll_attempt;
         }
      }

   /*
   * It is necessary to feed forward poll data. Otherwise, a good poll
   * (collecting a large amount of conditional entropy) followed by a
   * bad one (collecting little) would be unsafe. Do this by
   * generating new PRF outputs using the previous key and feeding
   * them into the extractor function.
   *
   * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF
   * output using the CTXinfo "reseed". Provide these values as input
   * to the extractor function.
   */
   hmac_prf(prf, K, counter, "rng");
   extractor->update(K); // K is the CTXinfo=rng PRF output

   hmac_prf(prf, K, counter, "reseed");
   extractor->update(K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   prf->set_key(extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(prf, K, counter, "xts");
   extractor->set_key(K);

   // Reset state
   zeroise(K);
   counter = 0;
   user_input_len = 0;

   /*
   Consider ourselves seeded once we've collected an estimated 128 bits of
   entropy in a single poll.
   */
   if(seeded == false && accum.bits_collected() >= 128)
      seeded = true;
   }

/*
* Add user-supplied entropy to the extractor input
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
   {
   const size_t USER_ENTROPY_WATERSHED = 64;

   extractor->update(input, length);
   user_input_len += length;

   /*
   * After we've accumulated at least USER_ENTROPY_WATERSHED bytes of
   * user input, reseed.  This input will automatically have been
   * included if reseed was called already, as it's just included in
   * the extractor input.
   */
   if(user_input_len >= USER_ENTROPY_WATERSHED)
      reseed(0);
   }

/*
* Add another entropy source to the list
*/
void HMAC_RNG::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*
* Clear memory of sensitive data
*/
void HMAC_RNG::clear()
   {
   extractor->clear();
   prf->clear();
   zeroise(K);
   counter = 0;
   user_input_len = 0;
   seeded = false;
   }

/*
* Return the name of this type
*/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
   }

/*
* HMAC_RNG Constructor
*/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
                   MessageAuthenticationCode* prf_mac) :
   extractor(extractor_mac), prf(prf_mac)
   {
   if(!prf->valid_keylength(extractor->output_length()) ||
      !extractor->valid_keylength(prf->output_length()))
      throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
                             extractor->name() + " and " +
                             prf->name());

   // First PRF inputs are all zero, as specified in section 2
   K.resize(prf->output_length());

   counter = 0;
   user_input_len = 0;
   seeded = false;

   /*
   Normally we want to feedback PRF output into the input to the
   extractor function to ensure a single bad poll does not damage the
   RNG, but obviously that is meaningless to do on the first poll.

   We will want to use the PRF before we set the first key (in
   reseed), and it is a pain to keep track if it is set or
   not. Since the first time it doesn't matter anyway, just set the
   PRF key to constant zero: randomize() will not produce output
   unless is_seeded() returns true, and that will only be the case if
   the estimated entropy counter is high enough. That variable is only
   set when a reseeding is performed.
   */
   MemoryVector<byte> prf_key(extractor->output_length());
   prf->set_key(prf_key);

   /*
   Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.

   This will be used during the first extraction sequence; XTS values
   after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
   }

/*
* HMAC_RNG Destructor
*/
HMAC_RNG::~HMAC_RNG()
   {
   delete extractor;
   delete prf;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());

   counter = 0;
   }

}
/*
* Randpool
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

namespace {

/*
* PRF based on a MAC
*/
enum RANDPOOL_PRF_TAG {
   CIPHER_KEY = 0,
   MAC_KEY    = 1,
   GEN_OUTPUT = 2
};

}

/*
* Generate a buffer of random bytes
*/
void Randpool::randomize(byte out[], size_t length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   update_buffer();
   while(length)
      {
      const size_t copied = std::min<size_t>(length, buffer.size());
      copy_mem(out, &buffer[0], copied);
      out += copied;
      length -= copied;
      update_buffer();
      }
   }

/*
* Refill the output buffer
*/
void Randpool::update_buffer()
   {
   for(size_t i = 0; i != counter.size(); ++i)
      if(++counter[i])
         break;

   mac->update(static_cast<byte>(GEN_OUTPUT));
   mac->update(counter);
   SecureVector<byte> mac_val = mac->final();

   for(size_t i = 0; i != mac_val.size(); ++i)
      buffer[i % buffer.size()] ^= mac_val[i];
   cipher->encrypt(buffer);

   if(counter[0] % ITERATIONS_BEFORE_RESEED == 0)
      mix_pool();
   }

/*
* Mix the entropy pool
*/
void Randpool::mix_pool()
   {
   const size_t BLOCK_SIZE = cipher->block_size();

   mac->update(static_cast<byte>(MAC_KEY));
   mac->update(pool);
   mac->set_key(mac->final());

   mac->update(static_cast<byte>(CIPHER_KEY));
   mac->update(pool);
   cipher->set_key(mac->final());

   xor_buf(pool, buffer, BLOCK_SIZE);
   cipher->encrypt(pool);
   for(size_t i = 1; i != POOL_BLOCKS; ++i)
      {
      const byte* previous_block = &pool[BLOCK_SIZE*(i-1)];
      byte* this_block = &pool[BLOCK_SIZE*i];
      xor_buf(this_block, previous_block, BLOCK_SIZE);
      cipher->encrypt(this_block);
      }

   update_buffer();
   }

/*
* Reseed the internal state
*/
void Randpool::reseed(size_t poll_bits)
   {
   Entropy_Accumulator_BufferedComputation accum(*mac, poll_bits);

   if(!entropy_sources.empty())
      {
      size_t poll_attempt = 0;

      while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
         {
         entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum);
         ++poll_attempt;
         }
      }

   SecureVector<byte> mac_val = mac->final();

   xor_buf(pool, mac_val, mac_val.size());
   mix_pool();

   if(accum.bits_collected() >= poll_bits)
      seeded = true;
   }

/*
* Add user-supplied entropy
*/
void Randpool::add_entropy(const byte input[], size_t length)
   {
   SecureVector<byte> mac_val = mac->process(input, length);
   xor_buf(pool, mac_val, mac_val.size());
   mix_pool();

   if(length)
      seeded = true;
   }

/*
* Add another entropy source to the list
*/
void Randpool::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*
* Clear memory of sensitive data
*/
void Randpool::clear()
   {
   cipher->clear();
   mac->clear();
   zeroise(pool);
   zeroise(buffer);
   zeroise(counter);
   seeded = false;
   }

/*
* Return the name of this type
*/
std::string Randpool::name() const
   {
   return "Randpool(" + cipher->name() + "," + mac->name() + ")";
   }

/*
* Randpool Constructor
*/
Randpool::Randpool(BlockCipher* cipher_in,
                   MessageAuthenticationCode* mac_in,
                   size_t pool_blocks,
                   size_t iter_before_reseed) :
   ITERATIONS_BEFORE_RESEED(iter_before_reseed),
   POOL_BLOCKS(pool_blocks),
   cipher(cipher_in),
   mac(mac_in)
   {
   const size_t BLOCK_SIZE = cipher->block_size();
   const size_t OUTPUT_LENGTH = mac->output_length();

   if(OUTPUT_LENGTH < BLOCK_SIZE ||
      !cipher->valid_keylength(OUTPUT_LENGTH) ||
      !mac->valid_keylength(OUTPUT_LENGTH))
      {
      delete cipher;
      delete mac;
      throw Internal_Error("Randpool: Invalid algorithm combination " +
                           cipher->name() + "/" + mac->name());
      }

   buffer.resize(BLOCK_SIZE);
   pool.resize(POOL_BLOCKS * BLOCK_SIZE);
   counter.resize(12);
   seeded = false;
   }

/*
* Randpool Destructor
*/
Randpool::~Randpool()
   {
   delete cipher;
   delete mac;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());
   }

}
/*
* Random Number Generator Base
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
#endif

namespace Botan {

/*
* Get a single random byte
*/
byte RandomNumberGenerator::next_byte()
   {
   byte out;
   this->randomize(&out, 1);
   return out;
   }

/*
* Create and seed a new RNG object
*/
RandomNumberGenerator* RandomNumberGenerator::make_rng()
   {
#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
   return new AutoSeeded_RNG;
#endif

   throw Algorithm_Not_Found("RandomNumberGenerator::make_rng - no RNG found");
   }

}
/*
* ANSI X9.31 RNG
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* Generate a buffer of random bytes
*/
void ANSI_X931_RNG::randomize(byte out[], size_t length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   while(length)
      {
      if(position == R.size())
         update_buffer();

      const size_t copied = std::min<size_t>(length, R.size() - position);

      copy_mem(out, &R[position], copied);
      out += copied;
      length -= copied;
      position += copied;
      }
   }

/*
* Refill the internal state
*/
void ANSI_X931_RNG::update_buffer()
   {
   const size_t BLOCK_SIZE = cipher->block_size();

   SecureVector<byte> DT = prng->random_vec(BLOCK_SIZE);
   cipher->encrypt(DT);

   xor_buf(&R[0], &V[0], &DT[0], BLOCK_SIZE);
   cipher->encrypt(R);

   xor_buf(&V[0], &R[0], &DT[0], BLOCK_SIZE);
   cipher->encrypt(V);

   position = 0;
   }

/*
* Reset V and the cipher key with new values
*/
void ANSI_X931_RNG::rekey()
   {
   const size_t BLOCK_SIZE = cipher->block_size();

   if(prng->is_seeded())
      {
      cipher->set_key(prng->random_vec(cipher->maximum_keylength()));

      if(V.size() != BLOCK_SIZE)
         V.resize(BLOCK_SIZE);
      prng->randomize(&V[0], V.size());

      update_buffer();
      }
   }

/*
* Reseed the internal state
*/
void ANSI_X931_RNG::reseed(size_t poll_bits)
   {
   prng->reseed(poll_bits);
   rekey();
   }

/*
* Add a entropy source to the underlying PRNG
*/
void ANSI_X931_RNG::add_entropy_source(EntropySource* src)
   {
   prng->add_entropy_source(src);
   }

/*
* Add some entropy to the underlying PRNG
*/
void ANSI_X931_RNG::add_entropy(const byte input[], size_t length)
   {
   prng->add_entropy(input, length);
   rekey();
   }

/*
* Check if the the PRNG is seeded
*/
bool ANSI_X931_RNG::is_seeded() const
   {
   return (V.size() > 0);
   }

/*
* Clear memory of sensitive data
*/
void ANSI_X931_RNG::clear()
   {
   cipher->clear();
   prng->clear();
   zeroise(R);
   V.clear();

   position = 0;
   }

/*
* Return the name of this type
*/
std::string ANSI_X931_RNG::name() const
   {
   return "X9.31(" + cipher->name() + ")";
   }

/*
* ANSI X931 RNG Constructor
*/
ANSI_X931_RNG::ANSI_X931_RNG(BlockCipher* cipher_in,
                             RandomNumberGenerator* prng_in)
   {
   if(!prng_in || !cipher_in)
      throw Invalid_Argument("ANSI_X931_RNG constructor: NULL arguments");

   cipher = cipher_in;
   prng = prng_in;

   R.resize(cipher->block_size());
   position = 0;
   }

/*
* ANSI X931 RNG Destructor
*/
ANSI_X931_RNG::~ANSI_X931_RNG()
   {
   delete cipher;
   delete prng;
   }

}
/*
* Startup Self Tests
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Perform a Known Answer Test
*/
bool test_filter_kat(Filter* filter,
                     const std::string& input,
                     const std::string& expected_output)
   {
   Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder);
   pipe.process_msg(input);

   const std::string output = pipe.read_all_as_string();

   return (output == expected_output);
   }

}

/*
* Run a set of KATs
*/
std::map<std::string, bool>
algorithm_kat(const SCAN_Name& algo_name,
              const std::map<std::string, std::string>& vars,
              Algorithm_Factory& af)
   {
   const std::string& algo = algo_name.algo_name_and_args();

   std::vector<std::string> providers = af.providers_of(algo);
   std::map<std::string, bool> all_results;

   if(providers.empty()) // no providers, nothing to do
      return all_results;

   const std::string input = search_map(vars, std::string("input"));
   const std::string output = search_map(vars, std::string("output"));

   SymmetricKey key(search_map(vars, std::string("key")));
   InitializationVector iv(search_map(vars, std::string("iv")));

   for(size_t i = 0; i != providers.size(); ++i)
      {
      const std::string provider = providers[i];

      if(const HashFunction* proto =
            af.prototype_hash_function(algo, provider))
         {
         Filter* filt = new Hash_Filter(proto->clone());
         all_results[provider] = test_filter_kat(filt, input, output);
         }
      else if(const MessageAuthenticationCode* proto =
                 af.prototype_mac(algo, provider))
         {
         Keyed_Filter* filt = new MAC_Filter(proto->clone(), key);
         all_results[provider] = test_filter_kat(filt, input, output);
         }
      else if(const StreamCipher* proto =
                 af.prototype_stream_cipher(algo, provider))
         {
         Keyed_Filter* filt = new StreamCipher_Filter(proto->clone());
         filt->set_key(key);
         filt->set_iv(iv);

         all_results[provider] = test_filter_kat(filt, input, output);
         }
      else if(const BlockCipher* proto =
                 af.prototype_block_cipher(algo, provider))
         {
         Keyed_Filter* enc = get_cipher_mode(proto, ENCRYPTION,
                                             algo_name.cipher_mode(),
                                             algo_name.cipher_mode_pad());

         Keyed_Filter* dec = get_cipher_mode(proto, DECRYPTION,
                                             algo_name.cipher_mode(),
                                             algo_name.cipher_mode_pad());

         if(!enc || !dec)
            {
            delete enc;
            delete dec;
            continue;
            }

         enc->set_key(key);

         if(enc->valid_iv_length(iv.length()))
            enc->set_iv(iv);
         else if(!enc->valid_iv_length(0))
            throw Invalid_IV_Length(algo, iv.length());

         dec->set_key(key);

         if(dec->valid_iv_length(iv.length()))
            dec->set_iv(iv);
         else if(!dec->valid_iv_length(0))
            throw Invalid_IV_Length(algo, iv.length());

         bool enc_ok = test_filter_kat(enc, input, output);
         bool dec_ok = test_filter_kat(dec, output, input);

         all_results[provider] = enc_ok && dec_ok;
         }
      }

   return all_results;
   }

namespace {

void verify_results(const std::string& algo,
                    const std::map<std::string, bool>& results)
   {
   for(std::map<std::string, bool>::const_iterator i = results.begin();
       i != results.end(); ++i)
      {
      if(!i->second)
         throw Self_Test_Failure(algo + " self-test failed, provider "+
                                 i->first);
      }
   }

void hash_test(Algorithm_Factory& af,
               const std::string& name,
               const std::string& in,
               const std::string& out)
   {
   std::map<std::string, std::string> vars;
   vars["input"] = in;
   vars["output"] = out;

   verify_results(name, algorithm_kat(name, vars, af));
   }

void mac_test(Algorithm_Factory& af,
              const std::string& name,
              const std::string& in,
              const std::string& out,
              const std::string& key)
   {
   std::map<std::string, std::string> vars;
   vars["input"] = in;
   vars["output"] = out;
   vars["key"] = key;

   verify_results(name, algorithm_kat(name, vars, af));
   }

/*
* Perform a KAT for a cipher
*/
void cipher_kat(Algorithm_Factory& af,
                const std::string& algo,
                const std::string& key_str,
                const std::string& iv_str,
                const std::string& in,
                const std::string& ecb_out,
                const std::string& cbc_out,
                const std::string& cfb_out,
                const std::string& ofb_out,
                const std::string& ctr_out)
   {
   SymmetricKey key(key_str);
   InitializationVector iv(iv_str);

   std::map<std::string, std::string> vars;
   vars["key"] = key_str;
   vars["iv"] = iv_str;
   vars["input"] = in;

   std::map<std::string, bool> results;

   vars["output"] = ecb_out;
   verify_results(algo + "/ECB", algorithm_kat(algo + "/ECB", vars, af));

   vars["output"] = cbc_out;
   verify_results(algo + "/CBC",
                  algorithm_kat(algo + "/CBC/NoPadding", vars, af));

   vars["output"] = cfb_out;
   verify_results(algo + "/CFB", algorithm_kat(algo + "/CFB", vars, af));

   vars["output"] = ofb_out;
   verify_results(algo + "/OFB", algorithm_kat(algo + "/OFB", vars, af));

   vars["output"] = ctr_out;
   verify_results(algo + "/CTR", algorithm_kat(algo + "/CTR-BE", vars, af));
   }

}

/*
* Perform Self Tests
*/
bool passes_self_tests(Algorithm_Factory& af)
   {
   try
      {
      confirm_startup_self_tests(af);
      }
   catch(Self_Test_Failure)
      {
      return false;
      }

   return true;
   }

/*
* Perform Self Tests
*/
void confirm_startup_self_tests(Algorithm_Factory& af)
  {
  cipher_kat(af, "DES",
             "0123456789ABCDEF", "1234567890ABCDEF",
             "4E6F77206973207468652074696D6520666F7220616C6C20",
             "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53",
             "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6",
             "F3096249C7F46E51A69E839B1A92F78403467133898EA622",
             "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3",
             "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75");

  cipher_kat(af, "TripleDES",
             "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E",
             "C141B5FCCD28DC8A",
             "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68",
             "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4",
             "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9",
             "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B",
             "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62",
             "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371");

  cipher_kat(af, "AES-128",
             "2B7E151628AED2A6ABF7158809CF4F3C",
             "000102030405060708090A0B0C0D0E0F",
             "6BC1BEE22E409F96E93D7E117393172A"
             "AE2D8A571E03AC9C9EB76FAC45AF8E51",
             "3AD77BB40D7A3660A89ECAF32466EF97"
             "F5D3D58503B9699DE785895A96FDBAAF",
             "7649ABAC8119B246CEE98E9B12E9197D"
             "5086CB9B507219EE95DB113A917678B2",
             "3B3FD92EB72DAD20333449F8E83CFB4A"
             "C8A64537A0B3A93FCDE3CDAD9F1CE58B",
             "3B3FD92EB72DAD20333449F8E83CFB4A"
             "7789508D16918F03F53C52DAC54ED825",
             "3B3FD92EB72DAD20333449F8E83CFB4A"
             "010C041999E03F36448624483E582D0E");

  hash_test(af, "SHA-1",
            "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709");

  hash_test(af, "SHA-1",
            "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D");

  hash_test(af, "SHA-1",
            "6162636462636465636465666465666765666768666768696768696A"
            "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
            "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");

  mac_test(af, "HMAC(SHA-1)",
           "4869205468657265",
           "B617318655057264E28BC0B6FB378C8EF146BE00",
           "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");

  hash_test(af, "SHA-256",
            "",
            "E3B0C44298FC1C149AFBF4C8996FB924"
            "27AE41E4649B934CA495991B7852B855");

  hash_test(af, "SHA-256",
            "616263",
            "BA7816BF8F01CFEA414140DE5DAE2223"
            "B00361A396177A9CB410FF61F20015AD");

  hash_test(af, "SHA-256",
            "6162636462636465636465666465666765666768666768696768696A"
            "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
            "248D6A61D20638B8E5C026930C3E6039"
            "A33CE45964FF2167F6ECEDD419DB06C1");

  mac_test(af, "HMAC(SHA-256)",
           "4869205468657265",
           "198A607EB44BFBC69903A0F1CF2BBDC5"
           "BA0AA3F3D9AE3C1C7A3B1696A0B68CF7",
           "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"
           "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
  }

}
/*
* ARC4
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Combine cipher stream with message
*/
void ARC4::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      generate();
      }
   xor_buf(out, in, &buffer[position], length);
   position += length;
   }

/*
* Generate cipher stream
*/
void ARC4::generate()
   {
   byte SX, SY;
   for(size_t i = 0; i != buffer.size(); i += 4)
      {
      SX = state[X+1]; Y = (Y + SX) % 256; SY = state[Y];
      state[X+1] = SY; state[Y] = SX;
      buffer[i] = state[(SX + SY) % 256];

      SX = state[X+2]; Y = (Y + SX) % 256; SY = state[Y];
      state[X+2] = SY; state[Y] = SX;
      buffer[i+1] = state[(SX + SY) % 256];

      SX = state[X+3]; Y = (Y + SX) % 256; SY = state[Y];
      state[X+3] = SY; state[Y] = SX;
      buffer[i+2] = state[(SX + SY) % 256];

      X = (X + 4) % 256;
      SX = state[X]; Y = (Y + SX) % 256; SY = state[Y];
      state[X] = SY; state[Y] = SX;
      buffer[i+3] = state[(SX + SY) % 256];
      }
   position = 0;
   }

/*
* ARC4 Key Schedule
*/
void ARC4::key_schedule(const byte key[], size_t length)
   {
   clear();

   for(size_t i = 0; i != 256; ++i)
      state[i] = static_cast<byte>(i);

   for(size_t i = 0, state_index = 0; i != 256; ++i)
      {
      state_index = (state_index + key[i % length] + state[i]) % 256;
      std::swap(state[i], state[state_index]);
      }

   for(size_t i = 0; i <= SKIP; i += buffer.size())
      generate();

   position += (SKIP % buffer.size());
   }

/*
* Return the name of this type
*/
std::string ARC4::name() const
   {
   if(SKIP == 0)   return "ARC4";
   if(SKIP == 256) return "MARK-4";
   else            return "RC4_skip(" + to_string(SKIP) + ")";
   }

/*
* Clear memory of sensitive data
*/
void ARC4::clear()
   {
   zeroise(state);
   zeroise(buffer);
   position = X = Y = 0;
   }

/*
* ARC4 Constructor
*/
ARC4::ARC4(size_t s) : SKIP(s),
                       state(256),
                       buffer(DEFAULT_BUFFERSIZE)
   {
   clear();
   }

}
/*
* Counter mode
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* CTR-BE Constructor
*/

CTR_BE::CTR_BE(BlockCipher* ciph) :
   permutation(ciph),
   counter(256 * permutation->block_size()),
   buffer(counter.size()),
   position(0)
   {
   }

/*
* CTR_BE Destructor
*/
CTR_BE::~CTR_BE()
   {
   delete permutation;
   }

/*
* Zeroize
*/
void CTR_BE::clear()
   {
   permutation->clear();
   zeroise(buffer);
   zeroise(counter);
   position = 0;
   }

/*
* Set the key
*/
void CTR_BE::key_schedule(const byte key[], size_t key_len)
   {
   permutation->set_key(key, key_len);

   // Set a default all-zeros IV
   set_iv(0, 0);
   }

/*
* Return the name of this type
*/
std::string CTR_BE::name() const
   {
   return ("CTR-BE(" + permutation->name() + ")");
   }

/*
* CTR-BE Encryption/Decryption
*/
void CTR_BE::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      increment_counter();
      }
   xor_buf(out, in, &buffer[position], length);
   position += length;
   }

/*
* Set CTR-BE IV
*/
void CTR_BE::set_iv(const byte iv[], size_t iv_len)
   {
   if(!valid_iv_length(iv_len))
      throw Invalid_IV_Length(name(), iv_len);

   const size_t bs = permutation->block_size();

   zeroise(counter);

   counter.copy(0, iv, iv_len);

   /*
   * Set counter blocks to IV, IV + 1, ... IV + 255
   */
   for(size_t i = 1; i != 256; ++i)
      {
      counter.copy(i*bs, &counter[(i-1)*bs], bs);

      for(size_t j = 0; j != bs; ++j)
         if(++counter[i*bs + (bs - 1 - j)])
            break;
      }

   permutation->encrypt_n(&counter[0], &buffer[0], 256);
   position = 0;
   }

/*
* Increment the counter and update the buffer
*/
void CTR_BE::increment_counter()
   {
   const size_t bs = permutation->block_size();

   /*
   * Each counter value always needs to be incremented by 256,
   * so we don't touch the lowest byte and instead treat it as
   * an increment of one starting with the next byte.
   */
   for(size_t i = 0; i != 256; ++i)
      {
      for(size_t j = 1; j != bs; ++j)
         if(++counter[i*bs + (bs - 1 - j)])
            break;
      }

   permutation->encrypt_n(&counter[0], &buffer[0], 256);

   position = 0;
   }

}
/*
* OFB Mode
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <algorithm>

namespace Botan {

/*
* OFB Constructor
*/
OFB::OFB(BlockCipher* ciph) : permutation(ciph)
   {
   position = 0;
   buffer.resize(permutation->block_size());
   }

/*
* OFB Destructor
*/
OFB::~OFB()
   {
   delete permutation;
   }

/*
* Zeroize
*/
void OFB::clear()
   {
   permutation->clear();
   zeroise(buffer);
   position = 0;
   }

/*
* Set the key
*/
void OFB::key_schedule(const byte key[], size_t key_len)
   {
   permutation->set_key(key, key_len);

   // Set a default all-zeros IV
   set_iv(0, 0);
   }

/*
* Return the name of this type
*/
std::string OFB::name() const
   {
   return ("OFB(" + permutation->name() + ")");
   }

/*
* CTR-BE Encryption/Decryption
*/
void OFB::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      permutation->encrypt(buffer);
      position = 0;
      }
   xor_buf(out, in, &buffer[position], length);
   position += length;
   }

/*
* Set CTR-BE IV
*/
void OFB::set_iv(const byte iv[], size_t iv_len)
   {
   if(!valid_iv_length(iv_len))
      throw Invalid_IV_Length(name(), iv_len);

   zeroise(buffer);
   buffer.copy(0, iv, iv_len);

   permutation->encrypt(buffer);
   position = 0;
   }

}
/*
* Salsa20 / XSalsa20
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4)    \
   do {                                          \
      x2 ^= rotate_left(x1 + x4,  7);            \
      x3 ^= rotate_left(x2 + x1,  9);            \
      x4 ^= rotate_left(x3 + x2, 13);            \
      x1 ^= rotate_left(x4 + x3, 18);            \
   } while(0)

/*
* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
*/
void hsalsa20(u32bit output[8], const u32bit input[16])
   {
   u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
          x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
          x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
          x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];

   for(size_t i = 0; i != 10; ++i)
      {
      SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
      SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
      SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
      SALSA20_QUARTER_ROUND(x15, x03, x07, x11);

      SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
      SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
      SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
      SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
      }

   output[0] = x00;
   output[1] = x05;
   output[2] = x10;
   output[3] = x15;
   output[4] = x06;
   output[5] = x07;
   output[6] = x08;
   output[7] = x09;
   }

/*
* Generate Salsa20 cipher stream
*/
void salsa20(byte output[64], const u32bit input[16])
   {
   u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
          x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
          x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
          x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];

   for(size_t i = 0; i != 10; ++i)
      {
      SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
      SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
      SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
      SALSA20_QUARTER_ROUND(x15, x03, x07, x11);

      SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
      SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
      SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
      SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
      }

   store_le(x00 + input[ 0], output + 4 *  0);
   store_le(x01 + input[ 1], output + 4 *  1);
   store_le(x02 + input[ 2], output + 4 *  2);
   store_le(x03 + input[ 3], output + 4 *  3);
   store_le(x04 + input[ 4], output + 4 *  4);
   store_le(x05 + input[ 5], output + 4 *  5);
   store_le(x06 + input[ 6], output + 4 *  6);
   store_le(x07 + input[ 7], output + 4 *  7);
   store_le(x08 + input[ 8], output + 4 *  8);
   store_le(x09 + input[ 9], output + 4 *  9);
   store_le(x10 + input[10], output + 4 * 10);
   store_le(x11 + input[11], output + 4 * 11);
   store_le(x12 + input[12], output + 4 * 12);
   store_le(x13 + input[13], output + 4 * 13);
   store_le(x14 + input[14], output + 4 * 14);
   store_le(x15 + input[15], output + 4 * 15);
   }

}

/*
* Combine cipher stream with message
*/
void Salsa20::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      salsa20(&buffer[0], &state[0]);

      ++state[8];
      if(!state[8]) // if overflow in state[8]
         ++state[9]; // carry to state[9]

      position = 0;
      }

   xor_buf(out, in, &buffer[position], length);

   position += length;
   }

/*
* Salsa20 Key Schedule
*/
void Salsa20::key_schedule(const byte key[], size_t length)
   {
   static const u32bit TAU[] =
      { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };

   static const u32bit SIGMA[] =
      { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };

   clear();

   if(length == 16)
      {
      state[0] = TAU[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = TAU[1];
      state[10] = TAU[2];
      state[11] = load_le<u32bit>(key, 0);
      state[12] = load_le<u32bit>(key, 1);
      state[13] = load_le<u32bit>(key, 2);
      state[14] = load_le<u32bit>(key, 3);
      state[15] = TAU[3];
      }
   else if(length == 32)
      {
      state[0] = SIGMA[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = SIGMA[1];
      state[10] = SIGMA[2];
      state[11] = load_le<u32bit>(key, 4);
      state[12] = load_le<u32bit>(key, 5);
      state[13] = load_le<u32bit>(key, 6);
      state[14] = load_le<u32bit>(key, 7);
      state[15] = SIGMA[3];
      }

   const byte ZERO[8] = { 0 };
   set_iv(ZERO, sizeof(ZERO));
   }

/*
* Return the name of this type
*/
void Salsa20::set_iv(const byte iv[], size_t length)
   {
   if(!valid_iv_length(length))
      throw Invalid_IV_Length(name(), length);

   if(length == 8)
      {
      // Salsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      }
   else
      {
      // XSalsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      state[8] = load_le<u32bit>(iv, 2);
      state[9] = load_le<u32bit>(iv, 3);

      SecureVector<u32bit> hsalsa(8);
      hsalsa20(&hsalsa[0], &state[0]);

      state[ 1] = hsalsa[0];
      state[ 2] = hsalsa[1];
      state[ 3] = hsalsa[2];
      state[ 4] = hsalsa[3];
      state[ 6] = load_le<u32bit>(iv, 4);
      state[ 7] = load_le<u32bit>(iv, 5);
      state[11] = hsalsa[4];
      state[12] = hsalsa[5];
      state[13] = hsalsa[6];
      state[14] = hsalsa[7];
      }

   state[8] = 0;
   state[9] = 0;

   salsa20(&buffer[0], &state[0]);
   ++state[8];
   if(!state[8]) // if overflow in state[8]
      ++state[9]; // carry to state[9]

   position = 0;
   }

/*
* Return the name of this type
*/
std::string Salsa20::name() const
   {
   return "Salsa20";
   }

/*
* Clear memory of sensitive data
*/
void Salsa20::clear()
   {
   zeroise(state);
   zeroise(buffer);
   position = 0;
   }

}
/*
* Stream Cipher
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

void StreamCipher::set_iv(const byte[], size_t iv_len)
   {
   if(iv_len)
      throw Invalid_Argument("The stream cipher " + name() +
                             " does not support resyncronization");
   }

bool StreamCipher::valid_iv_length(size_t iv_len) const
   {
   return (iv_len == 0);
   }

}
/*
* Tables for Turing
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

const byte Turing::SBOX[256] = {
   0x61, 0x51, 0xEB, 0x19, 0xB9, 0x5D, 0x60, 0x38, 0x7C, 0xB2, 0x06, 0x12,
   0xC4, 0x5B, 0x16, 0x3B, 0x2B, 0x18, 0x83, 0xB0, 0x7F, 0x75, 0xFA, 0xA0,
   0xE9, 0xDD, 0x6D, 0x7A, 0x6B, 0x68, 0x2D, 0x49, 0xB5, 0x1C, 0x90, 0xF7,
   0xED, 0x9F, 0xE8, 0xCE, 0xAE, 0x77, 0xC2, 0x13, 0xFD, 0xCD, 0x3E, 0xCF,
   0x37, 0x6A, 0xD4, 0xDB, 0x8E, 0x65, 0x1F, 0x1A, 0x87, 0xCB, 0x40, 0x15,
   0x88, 0x0D, 0x35, 0xB3, 0x11, 0x0F, 0xD0, 0x30, 0x48, 0xF9, 0xA8, 0xAC,
   0x85, 0x27, 0x0E, 0x8A, 0xE0, 0x50, 0x64, 0xA7, 0xCC, 0xE4, 0xF1, 0x98,
   0xFF, 0xA1, 0x04, 0xDA, 0xD5, 0xBC, 0x1B, 0xBB, 0xD1, 0xFE, 0x31, 0xCA,
   0xBA, 0xD9, 0x2E, 0xF3, 0x1D, 0x47, 0x4A, 0x3D, 0x71, 0x4C, 0xAB, 0x7D,
   0x8D, 0xC7, 0x59, 0xB8, 0xC1, 0x96, 0x1E, 0xFC, 0x44, 0xC8, 0x7B, 0xDC,
   0x5C, 0x78, 0x2A, 0x9D, 0xA5, 0xF0, 0x73, 0x22, 0x89, 0x05, 0xF4, 0x07,
   0x21, 0x52, 0xA6, 0x28, 0x9A, 0x92, 0x69, 0x8F, 0xC5, 0xC3, 0xF5, 0xE1,
   0xDE, 0xEC, 0x09, 0xF2, 0xD3, 0xAF, 0x34, 0x23, 0xAA, 0xDF, 0x7E, 0x82,
   0x29, 0xC0, 0x24, 0x14, 0x03, 0x32, 0x4E, 0x39, 0x6F, 0xC6, 0xB1, 0x9B,
   0xEA, 0x72, 0x79, 0x41, 0xD8, 0x26, 0x6C, 0x5E, 0x2C, 0xB4, 0xA2, 0x53,
   0x57, 0xE2, 0x9C, 0x86, 0x54, 0x95, 0xB6, 0x80, 0x8C, 0x36, 0x67, 0xBD,
   0x08, 0x93, 0x2F, 0x99, 0x5A, 0xF8, 0x3A, 0xD7, 0x56, 0x84, 0xD2, 0x01,
   0xF6, 0x66, 0x4D, 0x55, 0x8B, 0x0C, 0x0B, 0x46, 0xB7, 0x3C, 0x45, 0x91,
   0xA4, 0xE3, 0x70, 0xD6, 0xFB, 0xE6, 0x10, 0xA9, 0xC9, 0x00, 0x9E, 0xE7,
   0x4F, 0x76, 0x25, 0x3F, 0x5F, 0xA3, 0x33, 0x20, 0x02, 0xEF, 0x62, 0x74,
   0xEE, 0x17, 0x81, 0x42, 0x58, 0x0A, 0x4B, 0x63, 0xE5, 0xBE, 0x6E, 0xAD,
   0xBF, 0x43, 0x94, 0x97 };

const u32bit Turing::Q_BOX[256] = {
   0x1FAA1887, 0x4E5E435C, 0x9165C042, 0x250E6EF4, 0x5957EE20, 0xD484FED3,
   0xA666C502, 0x7E54E8AE, 0xD12EE9D9, 0xFC1F38D4, 0x49829B5D, 0x1B5CDF3C,
   0x74864249, 0xDA2E3963, 0x28F4429F, 0xC8432C35, 0x4AF40325, 0x9FC0DD70,
   0xD8973DED, 0x1A02DC5E, 0xCD175B42, 0xF10012BF, 0x6694D78C, 0xACAAB26B,
   0x4EC11B9A, 0x3F168146, 0xC0EA8EC5, 0xB38AC28F, 0x1FED5C0F, 0xAAB4101C,
   0xEA2DB082, 0x470929E1, 0xE71843DE, 0x508299FC, 0xE72FBC4B, 0x2E3915DD,
   0x9FA803FA, 0x9546B2DE, 0x3C233342, 0x0FCEE7C3, 0x24D607EF, 0x8F97EBAB,
   0xF37F859B, 0xCD1F2E2F, 0xC25B71DA, 0x75E2269A, 0x1E39C3D1, 0xEDA56B36,
   0xF8C9DEF2, 0x46C9FC5F, 0x1827B3A3, 0x70A56DDF, 0x0D25B510, 0x000F85A7,
   0xB2E82E71, 0x68CB8816, 0x8F951E2A, 0x72F5F6AF, 0xE4CBC2B3, 0xD34FF55D,
   0x2E6B6214, 0x220B83E3, 0xD39EA6F5, 0x6FE041AF, 0x6B2F1F17, 0xAD3B99EE,
   0x16A65EC0, 0x757016C6, 0xBA7709A4, 0xB0326E01, 0xF4B280D9, 0x4BFB1418,
   0xD6AFF227, 0xFD548203, 0xF56B9D96, 0x6717A8C0, 0x00D5BF6E, 0x10EE7888,
   0xEDFCFE64, 0x1BA193CD, 0x4B0D0184, 0x89AE4930, 0x1C014F36, 0x82A87088,
   0x5EAD6C2A, 0xEF22C678, 0x31204DE7, 0xC9C2E759, 0xD200248E, 0x303B446B,
   0xB00D9FC2, 0x9914A895, 0x906CC3A1, 0x54FEF170, 0x34C19155, 0xE27B8A66,
   0x131B5E69, 0xC3A8623E, 0x27BDFA35, 0x97F068CC, 0xCA3A6ACD, 0x4B55E936,
   0x86602DB9, 0x51DF13C1, 0x390BB16D, 0x5A80B83C, 0x22B23763, 0x39D8A911,
   0x2CB6BC13, 0xBF5579D7, 0x6C5C2FA8, 0xA8F4196E, 0xBCDB5476, 0x6864A866,
   0x416E16AD, 0x897FC515, 0x956FEB3C, 0xF6C8A306, 0x216799D9, 0x171A9133,
   0x6C2466DD, 0x75EB5DCD, 0xDF118F50, 0xE4AFB226, 0x26B9CEF3, 0xADB36189,
   0x8A7A19B1, 0xE2C73084, 0xF77DED5C, 0x8B8BC58F, 0x06DDE421, 0xB41E47FB,
   0xB1CC715E, 0x68C0FF99, 0x5D122F0F, 0xA4D25184, 0x097A5E6C, 0x0CBF18BC,
   0xC2D7C6E0, 0x8BB7E420, 0xA11F523F, 0x35D9B8A2, 0x03DA1A6B, 0x06888C02,
   0x7DD1E354, 0x6BBA7D79, 0x32CC7753, 0xE52D9655, 0xA9829DA1, 0x301590A7,
   0x9BC1C149, 0x13537F1C, 0xD3779B69, 0x2D71F2B7, 0x183C58FA, 0xACDC4418,
   0x8D8C8C76, 0x2620D9F0, 0x71A80D4D, 0x7A74C473, 0x449410E9, 0xA20E4211,
   0xF9C8082B, 0x0A6B334A, 0xB5F68ED2, 0x8243CC1B, 0x453C0FF3, 0x9BE564A0,
   0x4FF55A4F, 0x8740F8E7, 0xCCA7F15F, 0xE300FE21, 0x786D37D6, 0xDFD506F1,
   0x8EE00973, 0x17BBDE36, 0x7A670FA8, 0x5C31AB9E, 0xD4DAB618, 0xCC1F52F5,
   0xE358EB4F, 0x19B9E343, 0x3A8D77DD, 0xCDB93DA6, 0x140FD52D, 0x395412F8,
   0x2BA63360, 0x37E53AD0, 0x80700F1C, 0x7624ED0B, 0x703DC1EC, 0xB7366795,
   0xD6549D15, 0x66CE46D7, 0xD17ABE76, 0xA448E0A0, 0x28F07C02, 0xC31249B7,
   0x6E9ED6BA, 0xEAA47F78, 0xBBCFFFBD, 0xC507CA84, 0xE965F4DA, 0x8E9F35DA,
   0x6AD2AA44, 0x577452AC, 0xB5D674A7, 0x5461A46A, 0x6763152A, 0x9C12B7AA,
   0x12615927, 0x7B4FB118, 0xC351758D, 0x7E81687B, 0x5F52F0B3, 0x2D4254ED,
   0xD4C77271, 0x0431ACAB, 0xBEF94AEC, 0xFEE994CD, 0x9C4D9E81, 0xED623730,
   0xCF8A21E8, 0x51917F0B, 0xA7A9B5D6, 0xB297ADF8, 0xEED30431, 0x68CAC921,
   0xF1B35D46, 0x7A430A36, 0x51194022, 0x9ABCA65E, 0x85EC70BA, 0x39AEA8CC,
   0x737BAE8B, 0x582924D5, 0x03098A5A, 0x92396B81, 0x18DE2522, 0x745C1CB8,
   0xA1B8FE1D, 0x5DB3C697, 0x29164F83, 0x97C16376, 0x8419224C, 0x21203B35,
   0x833AC0FE, 0xD966A19A, 0xAAF0B24F, 0x40FDA998, 0xE7D52D71, 0x390896A8,
   0xCEE6053F, 0xD0B0D300, 0xFF99CBCC, 0x065E3D40 };

}
/*
* Turing
* (C) 1999-2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

namespace {

/*
* Perform an N-way PHT
*/
inline void PHT(MemoryRegion<u32bit>& B)
   {
   u32bit sum = 0;
   for(size_t i = 0; i < B.size() - 1; ++i)
      sum += B[i];

   B[B.size()-1] += sum;

   sum = B[B.size()-1];
   for(size_t i = 0; i < B.size() - 1; ++i)
      B[i] += sum;
   }

}

/*
* Combine cipher stream with message
*/
void Turing::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      generate();
      }
   xor_buf(out, in, &buffer[position], length);
   position += length;
   }

/*
* Generate cipher stream
*/
void Turing::generate()
   {
   // Table for Turing's polynomial multiplication
   static const u32bit MULT_TAB[256] = {
      0x00000000, 0xD02B4367, 0xED5686CE, 0x3D7DC5A9, 0x97AC41D1, 0x478702B6,
      0x7AFAC71F, 0xAAD18478, 0x631582EF, 0xB33EC188, 0x8E430421, 0x5E684746,
      0xF4B9C33E, 0x24928059, 0x19EF45F0, 0xC9C40697, 0xC62A4993, 0x16010AF4,
      0x2B7CCF5D, 0xFB578C3A, 0x51860842, 0x81AD4B25, 0xBCD08E8C, 0x6CFBCDEB,
      0xA53FCB7C, 0x7514881B, 0x48694DB2, 0x98420ED5, 0x32938AAD, 0xE2B8C9CA,
      0xDFC50C63, 0x0FEE4F04, 0xC154926B, 0x117FD10C, 0x2C0214A5, 0xFC2957C2,
      0x56F8D3BA, 0x86D390DD, 0xBBAE5574, 0x6B851613, 0xA2411084, 0x726A53E3,
      0x4F17964A, 0x9F3CD52D, 0x35ED5155, 0xE5C61232, 0xD8BBD79B, 0x089094FC,
      0x077EDBF8, 0xD755989F, 0xEA285D36, 0x3A031E51, 0x90D29A29, 0x40F9D94E,
      0x7D841CE7, 0xADAF5F80, 0x646B5917, 0xB4401A70, 0x893DDFD9, 0x59169CBE,
      0xF3C718C6, 0x23EC5BA1, 0x1E919E08, 0xCEBADD6F, 0xCFA869D6, 0x1F832AB1,
      0x22FEEF18, 0xF2D5AC7F, 0x58042807, 0x882F6B60, 0xB552AEC9, 0x6579EDAE,
      0xACBDEB39, 0x7C96A85E, 0x41EB6DF7, 0x91C02E90, 0x3B11AAE8, 0xEB3AE98F,
      0xD6472C26, 0x066C6F41, 0x09822045, 0xD9A96322, 0xE4D4A68B, 0x34FFE5EC,
      0x9E2E6194, 0x4E0522F3, 0x7378E75A, 0xA353A43D, 0x6A97A2AA, 0xBABCE1CD,
      0x87C12464, 0x57EA6703, 0xFD3BE37B, 0x2D10A01C, 0x106D65B5, 0xC04626D2,
      0x0EFCFBBD, 0xDED7B8DA, 0xE3AA7D73, 0x33813E14, 0x9950BA6C, 0x497BF90B,
      0x74063CA2, 0xA42D7FC5, 0x6DE97952, 0xBDC23A35, 0x80BFFF9C, 0x5094BCFB,
      0xFA453883, 0x2A6E7BE4, 0x1713BE4D, 0xC738FD2A, 0xC8D6B22E, 0x18FDF149,
      0x258034E0, 0xF5AB7787, 0x5F7AF3FF, 0x8F51B098, 0xB22C7531, 0x62073656,
      0xABC330C1, 0x7BE873A6, 0x4695B60F, 0x96BEF568, 0x3C6F7110, 0xEC443277,
      0xD139F7DE, 0x0112B4B9, 0xD31DD2E1, 0x03369186, 0x3E4B542F, 0xEE601748,
      0x44B19330, 0x949AD057, 0xA9E715FE, 0x79CC5699, 0xB008500E, 0x60231369,
      0x5D5ED6C0, 0x8D7595A7, 0x27A411DF, 0xF78F52B8, 0xCAF29711, 0x1AD9D476,
      0x15379B72, 0xC51CD815, 0xF8611DBC, 0x284A5EDB, 0x829BDAA3, 0x52B099C4,
      0x6FCD5C6D, 0xBFE61F0A, 0x7622199D, 0xA6095AFA, 0x9B749F53, 0x4B5FDC34,
      0xE18E584C, 0x31A51B2B, 0x0CD8DE82, 0xDCF39DE5, 0x1249408A, 0xC26203ED,
      0xFF1FC644, 0x2F348523, 0x85E5015B, 0x55CE423C, 0x68B38795, 0xB898C4F2,
      0x715CC265, 0xA1778102, 0x9C0A44AB, 0x4C2107CC, 0xE6F083B4, 0x36DBC0D3,
      0x0BA6057A, 0xDB8D461D, 0xD4630919, 0x04484A7E, 0x39358FD7, 0xE91ECCB0,
      0x43CF48C8, 0x93E40BAF, 0xAE99CE06, 0x7EB28D61, 0xB7768BF6, 0x675DC891,
      0x5A200D38, 0x8A0B4E5F, 0x20DACA27, 0xF0F18940, 0xCD8C4CE9, 0x1DA70F8E,
      0x1CB5BB37, 0xCC9EF850, 0xF1E33DF9, 0x21C87E9E, 0x8B19FAE6, 0x5B32B981,
      0x664F7C28, 0xB6643F4F, 0x7FA039D8, 0xAF8B7ABF, 0x92F6BF16, 0x42DDFC71,
      0xE80C7809, 0x38273B6E, 0x055AFEC7, 0xD571BDA0, 0xDA9FF2A4, 0x0AB4B1C3,
      0x37C9746A, 0xE7E2370D, 0x4D33B375, 0x9D18F012, 0xA06535BB, 0x704E76DC,
      0xB98A704B, 0x69A1332C, 0x54DCF685, 0x84F7B5E2, 0x2E26319A, 0xFE0D72FD,
      0xC370B754, 0x135BF433, 0xDDE1295C, 0x0DCA6A3B, 0x30B7AF92, 0xE09CECF5,
      0x4A4D688D, 0x9A662BEA, 0xA71BEE43, 0x7730AD24, 0xBEF4ABB3, 0x6EDFE8D4,
      0x53A22D7D, 0x83896E1A, 0x2958EA62, 0xF973A905, 0xC40E6CAC, 0x14252FCB,
      0x1BCB60CF, 0xCBE023A8, 0xF69DE601, 0x26B6A566, 0x8C67211E, 0x5C4C6279,
      0x6131A7D0, 0xB11AE4B7, 0x78DEE220, 0xA8F5A147, 0x958864EE, 0x45A32789,
      0xEF72A3F1, 0x3F59E096, 0x0224253F, 0xD20F6658 };

   /*
    I tried an implementation without precomputed LFSR offsets, since
    I thought that might allow (especially on x86-64) the use of leal to
    compute all the offsets.. However on my Core2 with GCC 4.3 it
    turned out significantly slower (238 Mib/s, versus 300 Mib/s
    with precomputed offsets)

    I also tried using byte vs u32bit for the offset variable (since
    x86 memory addressing modes can be odd), but it made things even
    slower (186 Mib/s)
   */
   static const byte OFFSETS[221] = {
      0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 14, 15, 16,
      5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 2, 3, 4,
      10, 11, 12, 13, 14, 15, 16, 0, 1, 5, 7, 8, 9,
      15, 16, 0, 1, 2, 3, 4, 5, 6, 10, 12, 13, 14,
      3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 0, 1, 2,
      8, 9, 10, 11, 12, 13, 14, 15, 16, 3, 5, 6, 7,
      13, 14, 15, 16, 0, 1, 2, 3, 4, 8, 10, 11, 12,
      1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 15, 16, 0,
      6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 3, 4, 5,
      11, 12, 13, 14, 15, 16, 0, 1, 2, 6, 8, 9, 10,
      16, 0, 1, 2, 3, 4, 5, 6, 7, 11, 13, 14, 15,
      4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 1, 2, 3,
      9, 10, 11, 12, 13, 14, 15, 16, 0, 4, 6, 7, 8,
      14, 15, 16, 0, 1, 2, 3, 4, 5, 9, 11, 12, 13,
      2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 16, 0, 1,
      7, 8, 9, 10, 11, 12, 13, 14, 15, 2, 4, 5, 6,
      12, 13, 14, 15, 16, 0, 1, 2, 3, 7, 9, 10, 11 };

   for(size_t i = 0; i != 17; ++i)
      {
      const byte* R_off = OFFSETS + 13*i;

      u32bit R0 = R[R_off[0]];
      u32bit R1 = R[R_off[1]];
      u32bit R2 = R[R_off[2]];
      u32bit R3 = R[R_off[3]];
      u32bit R4 = R[R_off[4]];

      const u32bit R5 = R[R_off[5]];
      const u32bit R6 = R[R_off[6]];
      const u32bit R7 = R[R_off[7]];
      const u32bit R8 = R[R_off[8]];
      const u32bit R9 = R[R_off[9]];
      const u32bit R10 = R[R_off[10]];
      const u32bit R11 = R[R_off[11]];
      const u32bit R12 = R[R_off[12]];

      R[R_off[0]] = R0 = ((R0 << 8) ^ MULT_TAB[(R0 >> 24) & 0xFF]) ^ R11 ^ R4;

      u32bit A = R0;
      u32bit B = R10;
      u32bit C = R7;
      u32bit D = R2;
      u32bit E = R1;

      E += A + B + C + D;

      A += E;
      B += E;
      C += E;
      D += E;

      A = S0[get_byte(0, A)] ^ S1[get_byte(1, A)] ^
          S2[get_byte(2, A)] ^ S3[get_byte(3, A)];
      B = S0[get_byte(1, B)] ^ S1[get_byte(2, B)] ^
          S2[get_byte(3, B)] ^ S3[get_byte(0, B)];
      C = S0[get_byte(2, C)] ^ S1[get_byte(3, C)] ^
          S2[get_byte(0, C)] ^ S3[get_byte(1, C)];
      D = S0[get_byte(3, D)] ^ S1[get_byte(0, D)] ^
          S2[get_byte(1, D)] ^ S3[get_byte(2, D)];
      E = S0[get_byte(0, E)] ^ S1[get_byte(1, E)] ^
          S2[get_byte(2, E)] ^ S3[get_byte(3, E)];

      E += A + B + C + D;

      A += E;
      B += E;
      C += E;
      D += E;

      R[R_off[1]] = R1 = ((R1 << 8) ^ MULT_TAB[(R1 >> 24) & 0xFF]) ^ R12 ^ R5;
      R[R_off[2]] = R2 = ((R2 << 8) ^ MULT_TAB[(R2 >> 24) & 0xFF]) ^ R0 ^ R6;
      R[R_off[3]] = ((R3 << 8) ^ MULT_TAB[(R3 >> 24) & 0xFF]) ^ R1 ^ R7;

      E += R4;

      R[R_off[4]] = ((R4 << 8) ^ MULT_TAB[(R4 >> 24) & 0xFF]) ^ R2 ^ R8;

      A += R1;
      B += R12;
      C += R9;
      D += R5;

      store_be(A, &buffer[20*i + 0]);
      store_be(B, &buffer[20*i + 4]);
      store_be(C, &buffer[20*i + 8]);
      store_be(D, &buffer[20*i + 12]);
      store_be(E, &buffer[20*i + 16]);
      }

   position = 0;
   }

/*
* Turing's byte mixing step
*/
u32bit Turing::fixedS(u32bit W)
   {
   byte B = SBOX[get_byte(0, W)];
   W ^= Q_BOX[B];
   W &= 0x00FFFFFF;
   W |= B << 24;

   B = SBOX[get_byte(1, W)];
   W ^= rotate_left(Q_BOX[B], 8);
   W &= 0xFF00FFFF;
   W |= B << 16;

   B = SBOX[get_byte(2, W)];
   W ^= rotate_left(Q_BOX[B], 16);
   W &= 0xFFFF00FF;
   W |= B << 8;

   B = SBOX[get_byte(3, W)];
   W ^= rotate_left(Q_BOX[B], 24);
   W &= 0xFFFFFF00;
   W |= B;

   return W;
   }

/*
* Turing Key Schedule
*/
void Turing::key_schedule(const byte key[], size_t length)
   {
   K.resize(length / 4);
   for(size_t i = 0; i != length; ++i)
      K[i/4] = (K[i/4] << 8) + key[i];

   for(size_t i = 0; i != K.size(); ++i)
      K[i] = fixedS(K[i]);

   PHT(K);

   for(u32bit i = 0; i != 256; ++i)
      {
      u32bit W0 = 0, C0 = i;
      u32bit W1 = 0, C1 = i;
      u32bit W2 = 0, C2 = i;
      u32bit W3 = 0, C3 = i;

      for(size_t j = 0; j < K.size(); ++j)
         {
         C0 = SBOX[get_byte(0, K[j]) ^ C0];
         C1 = SBOX[get_byte(1, K[j]) ^ C1];
         C2 = SBOX[get_byte(2, K[j]) ^ C2];
         C3 = SBOX[get_byte(3, K[j]) ^ C3];

         W0 ^= rotate_left(Q_BOX[C0], j);
         W1 ^= rotate_left(Q_BOX[C1], j + 8);
         W2 ^= rotate_left(Q_BOX[C2], j + 16);
         W3 ^= rotate_left(Q_BOX[C3], j + 24);
         }

      S0[i] = (W0 & 0x00FFFFFF) | (C0 << 24);
      S1[i] = (W1 & 0xFF00FFFF) | (C1 << 16);
      S2[i] = (W2 & 0xFFFF00FF) | (C2 << 8);
      S3[i] = (W3 & 0xFFFFFF00) | C3;
      }

   set_iv(0, 0);
   }

/*
* Resynchronization
*/
void Turing::set_iv(const byte iv[], size_t length)
   {
   if(!valid_iv_length(length))
      throw Invalid_IV_Length(name(), length);

   SecureVector<u32bit> IV(length / 4);
   for(size_t i = 0; i != length; ++i)
      IV[i/4] = (IV[i/4] << 8) + iv[i];

   for(size_t i = 0; i != IV.size(); ++i)
      R[i] = IV[i] = fixedS(IV[i]);

   for(size_t i = 0; i != K.size(); ++i)
      R[i+IV.size()] = K[i];

   R[K.size() + IV.size()] = (0x010203 << 8) | (K.size() << 4) | IV.size();

   for(size_t i = K.size() + IV.size() + 1; i != 17; ++i)
      {
      const u32bit W = R[i-K.size()-IV.size()-1] + R[i-1];
      R[i] = S0[get_byte(0, W)] ^ S1[get_byte(1, W)] ^
             S2[get_byte(2, W)] ^ S3[get_byte(3, W)];
      }

   PHT(R);

   generate();
   }

/*
* Clear memory of sensitive data
*/
void Turing::clear()
   {
   zeroise(S0);
   zeroise(S1);
   zeroise(S2);
   zeroise(S3);

   zeroise(buffer);
   position = 0;
   }

}
/*
* WiderWake
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Combine cipher stream with message
*/
void WiderWake_41_BE::cipher(const byte in[], byte out[], size_t length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      generate(buffer.size());
      }
   xor_buf(out, in, &buffer[position], length);
   position += length;
   }

/*
* Generate cipher stream
*/
void WiderWake_41_BE::generate(size_t length)
   {
   u32bit R0 = state[0], R1 = state[1],
          R2 = state[2], R3 = state[3],
          R4 = state[4];

   for(size_t i = 0; i != length; i += 8)
      {
      u32bit R0a;

      store_be(R3, &buffer[i]);

      R0a = R4 + R3; R3 += R2; R2 += R1; R1 += R0;
      R0a = (R0a >> 8) ^ T[(R0a & 0xFF)];
      R1  = (R1  >> 8) ^ T[(R1  & 0xFF)];
      R2  = (R2  >> 8) ^ T[(R2  & 0xFF)];
      R3  = (R3  >> 8) ^ T[(R3  & 0xFF)];
      R4 = R0; R0 = R0a;

      store_be(R3, &buffer[i + 4]);

      R0a = R4 + R3; R3 += R2; R2 += R1; R1 += R0;
      R0a = (R0a >> 8) ^ T[(R0a & 0xFF)];
      R1  = (R1  >> 8) ^ T[(R1  & 0xFF)];
      R2  = (R2  >> 8) ^ T[(R2  & 0xFF)];
      R3  = (R3  >> 8) ^ T[(R3  & 0xFF)];
      R4 = R0; R0 = R0a;
      }

   state[0] = R0;
   state[1] = R1;
   state[2] = R2;
   state[3] = R3;
   state[4] = R4;

   position = 0;
   }

/*
* WiderWake Key Schedule
*/
void WiderWake_41_BE::key_schedule(const byte key[], size_t)
   {
   for(size_t i = 0; i != 4; ++i)
      t_key[i] = load_be<u32bit>(key, i);

   static const u32bit MAGIC[8] = {
      0x726A8F3B, 0xE69A3B5C, 0xD3C71FE5, 0xAB3C73D2,
      0x4D3A8EB3, 0x0396D6E8, 0x3D4C2F7A, 0x9EE27CF3 };

   for(size_t i = 0; i != 4; ++i)
      T[i] = t_key[i];

   for(size_t i = 4; i != 256; ++i)
      {
      u32bit X = T[i-1] + T[i-4];
      T[i] = (X >> 3) ^ MAGIC[X % 8];
      }

   for(size_t i = 0; i != 23; ++i)
      T[i] += T[i+89];

   u32bit X = T[33];
   u32bit Z = (T[59] | 0x01000001) & 0xFF7FFFFF;
   for(size_t i = 0; i != 256; ++i)
      {
      X = (X & 0xFF7FFFFF) + Z;
      T[i] = (T[i] & 0x00FFFFFF) ^ X;
      }

   X = (T[X & 0xFF] ^ X) & 0xFF;
   Z = T[0];
   T[0] = T[X];
   for(size_t i = 1; i != 256; ++i)
      {
      T[X] = T[i];
      X = (T[i ^ X] ^ X) & 0xFF;
      T[i] = T[X];
      }
   T[X] = Z;

   position = 0;

   const byte ZEROS[8] = { 0 };
   set_iv(ZEROS, sizeof(ZEROS));
   }

/*
* Resynchronization
*/
void WiderWake_41_BE::set_iv(const byte iv[], size_t length)
   {
   if(!valid_iv_length(length))
      throw Invalid_IV_Length(name(), length);

   for(size_t i = 0; i != 4; ++i)
      state[i] = t_key[i];

   state[4] = load_be<u32bit>(iv, 0);
   state[0] ^= state[4];
   state[2] ^= load_be<u32bit>(iv, 1);

   generate(8*4);
   generate(buffer.size());
   }

/*
* Clear memory of sensitive data
*/
void WiderWake_41_BE::clear()
   {
   position = 0;
   zeroise(t_key);
   zeroise(state);
   zeroise(T);
   zeroise(buffer);
   }

}
/*
* Runtime assertion checking
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <sstream>

namespace Botan {

void assertion_failure(const char* expr_str,
                       const char* msg,
                       const char* func,
                       const char* file,
                       int line)
   {
   std::ostringstream format;

   format << "Assertion " << expr_str << " failed ";

   if(msg)
      format << "(" << msg << ") ";

   if(func)
      format << "in " << func << " ";

   format << "@" << file << ":" << line;

   throw Internal_Error(format.str());
   }

}
/*
* Character Set Handling
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <cctype>

namespace Botan {

namespace Charset {

namespace {

/*
* Convert from UCS-2 to ISO 8859-1
*/
std::string ucs2_to_latin1(const std::string& ucs2)
   {
   if(ucs2.size() % 2 == 1)
      throw Decoding_Error("UCS-2 string has an odd number of bytes");

   std::string latin1;

   for(size_t i = 0; i != ucs2.size(); i += 2)
      {
      const byte c1 = ucs2[i];
      const byte c2 = ucs2[i+1];

      if(c1 != 0)
         throw Decoding_Error("UCS-2 has non-Latin1 characters");

      latin1 += static_cast<char>(c2);
      }

   return latin1;
   }

/*
* Convert from UTF-8 to ISO 8859-1
*/
std::string utf8_to_latin1(const std::string& utf8)
   {
   std::string iso8859;

   size_t position = 0;
   while(position != utf8.size())
      {
      const byte c1 = static_cast<byte>(utf8[position++]);

      if(c1 <= 0x7F)
         iso8859 += static_cast<char>(c1);
      else if(c1 >= 0xC0 && c1 <= 0xC7)
         {
         if(position == utf8.size())
            throw Decoding_Error("UTF-8: sequence truncated");

         const byte c2 = static_cast<byte>(utf8[position++]);
         const byte iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F);

         if(iso_char <= 0x7F)
            throw Decoding_Error("UTF-8: sequence longer than needed");

         iso8859 += static_cast<char>(iso_char);
         }
      else
         throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used");
      }

   return iso8859;
   }

/*
* Convert from ISO 8859-1 to UTF-8
*/
std::string latin1_to_utf8(const std::string& iso8859)
   {
   std::string utf8;
   for(size_t i = 0; i != iso8859.size(); ++i)
      {
      const byte c = static_cast<byte>(iso8859[i]);

      if(c <= 0x7F)
         utf8 += static_cast<char>(c);
      else
         {
         utf8 += static_cast<char>((0xC0 | (c >> 6)));
         utf8 += static_cast<char>((0x80 | (c & 0x3F)));
         }
      }
   return utf8;
   }

}

/*
* Perform character set transcoding
*/
std::string transcode(const std::string& str,
                      Character_Set to, Character_Set from)
   {
   if(to == LOCAL_CHARSET)
      to = LATIN1_CHARSET;
   if(from == LOCAL_CHARSET)
      from = LATIN1_CHARSET;

   if(to == from)
      return str;

   if(from == LATIN1_CHARSET && to == UTF8_CHARSET)
      return latin1_to_utf8(str);
   if(from == UTF8_CHARSET && to == LATIN1_CHARSET)
      return utf8_to_latin1(str);
   if(from == UCS2_CHARSET && to == LATIN1_CHARSET)
      return ucs2_to_latin1(str);

   throw Invalid_Argument("Unknown transcoding operation from " +
                          to_string(from) + " to " + to_string(to));
   }

/*
* Check if a character represents a digit
*/
bool is_digit(char c)
   {
   if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' ||
      c == '5' || c == '6' || c == '7' || c == '8' || c == '9')
      return true;
   return false;
   }

/*
* Check if a character represents whitespace
*/
bool is_space(char c)
   {
   if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
      return true;
   return false;
   }

/*
* Convert a character to a digit
*/
byte char2digit(char c)
   {
   switch(c)
      {
      case '0': return 0;
      case '1': return 1;
      case '2': return 2;
      case '3': return 3;
      case '4': return 4;
      case '5': return 5;
      case '6': return 6;
      case '7': return 7;
      case '8': return 8;
      case '9': return 9;
      }

   throw Invalid_Argument("char2digit: Input is not a digit character");
   }

/*
* Convert a digit to a character
*/
char digit2char(byte b)
   {
   switch(b)
      {
      case 0: return '0';
      case 1: return '1';
      case 2: return '2';
      case 3: return '3';
      case 4: return '4';
      case 5: return '5';
      case 6: return '6';
      case 7: return '7';
      case 8: return '8';
      case 9: return '9';
      }

   throw Invalid_Argument("digit2char: Input is not a digit");
   }

/*
* Case-insensitive character comparison
*/
bool caseless_cmp(char a, char b)
   {
   return (std::tolower(static_cast<unsigned char>(a)) ==
           std::tolower(static_cast<unsigned char>(b)));
   }

}

}
/*
* Runtime CPU detection
* (C) 2009-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

#if defined(BOTAN_TARGET_OS_IS_DARWIN)
  #include <sys/sysctl.h>
#endif

#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
  #include <sys/param.h>
  #include <sys/sysctl.h>
  #include <machine/cpu.h>
#endif

#endif

#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)

#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)

  #include <intrin.h>
  #define CALL_CPUID(type, out) do { __cpuid((int*)out, type); } while(0)

#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)

  #include <ia32intrin.h>
  #define CALL_CPUID(type, out) do { __cpuid(out, type); } while(0)

#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) && (BOTAN_GCC_VERSION >= 430)

  // Only available starting in GCC 4.3
  #include <cpuid.h>

namespace {

  /*
  * Prevent inlining to work around GCC bug 44174
  */
  void __attribute__((__noinline__)) call_gcc_cpuid(Botan::u32bit type,
                                                    Botan::u32bit out[4])
     {
     __get_cpuid(type, out, out+1, out+2, out+3);
     }

  #define CALL_CPUID call_gcc_cpuid

}

#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && \
    (defined(BOTAN_BUILD_COMPILER_IS_CLANG) || defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_INTEL))

  /*
  * We can't safely use this on x86-32 as some 32-bit ABIs use ebx as
  * a PIC register, and in theory there are some x86-32s still out
  * there that don't support cpuid at all; it requires strange
  * contortions to detect them.
  */

  #define CALL_CPUID(type, out) \
    asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \
        : "0" (type))

#else
  #warning "No method of calling CPUID for this compiler"
#endif

#endif

#ifndef CALL_CPUID
  // In all other cases, just zeroize the supposed cpuid output
  #define CALL_CPUID(type, out) \
    do { out[0] = out[1] = out[2] = out[3] = 0; } while(0);
#endif

namespace Botan {

u64bit CPUID::x86_processor_flags = 0;
size_t CPUID::cache_line = 32;
bool CPUID::altivec_capable = false;

namespace {

u32bit get_x86_cache_line_size()
   {
   const u32bit INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 };
   const u32bit AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 };

   u32bit cpuid[4] = { 0 };
   CALL_CPUID(0, cpuid);

   if(same_mem(cpuid + 1, INTEL_CPUID, 3))
      {
      CALL_CPUID(1, cpuid);
      return 8 * get_byte(2, cpuid[1]);
      }
   else if(same_mem(cpuid + 1, AMD_CPUID, 3))
      {
      CALL_CPUID(0x80000005, cpuid);
      return get_byte(3, cpuid[2]);
      }
   else
      return 32; // default cache line guess
   }

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

bool altivec_check_sysctl()
   {
#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD)

#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
   int sels[2] = { CTL_MACHDEP, CPU_ALTIVEC };
#else
   // From Apple's docs
   int sels[2] = { CTL_HW, HW_VECTORUNIT };
#endif
   int vector_type = 0;
   size_t length = sizeof(vector_type);
   int error = sysctl(sels, 2, &vector_type, &length, NULL, 0);

   if(error == 0 && vector_type > 0)
      return true;
#endif

   return false;
   }

bool altivec_check_pvr_emul()
   {
   bool altivec_capable = false;

#if defined(BOTAN_TARGET_OS_IS_LINUX) || defined(BOTAN_TARGET_OS_IS_NETBSD)

   /*
   On PowerPC, MSR 287 is PVR, the Processor Version Number
   Normally it is only accessible to ring 0, but Linux and NetBSD
   (others, too, maybe?) will trap and emulate it for us.

   PVR identifiers for various AltiVec enabled CPUs. Taken from
   PearPC and Linux sources, mostly.
   */

   const u16bit PVR_G4_7400  = 0x000C;
   const u16bit PVR_G5_970   = 0x0039;
   const u16bit PVR_G5_970FX = 0x003C;
   const u16bit PVR_G5_970MP = 0x0044;
   const u16bit PVR_G5_970GX = 0x0045;
   const u16bit PVR_POWER6   = 0x003E;
   const u16bit PVR_POWER7   = 0x003F;
   const u16bit PVR_CELL_PPU = 0x0070;

   // Motorola produced G4s with PVR 0x800[0123C] (at least)
   const u16bit PVR_G4_74xx_24  = 0x800;

   u32bit pvr = 0;

   asm volatile("mfspr %0, 287" : "=r" (pvr));

   // Top 16 bit suffice to identify model
   pvr >>= 16;

   altivec_capable |= (pvr == PVR_G4_7400);
   altivec_capable |= ((pvr >> 4) == PVR_G4_74xx_24);
   altivec_capable |= (pvr == PVR_G5_970);
   altivec_capable |= (pvr == PVR_G5_970FX);
   altivec_capable |= (pvr == PVR_G5_970MP);
   altivec_capable |= (pvr == PVR_G5_970GX);
   altivec_capable |= (pvr == PVR_POWER6);
   altivec_capable |= (pvr == PVR_POWER7);
   altivec_capable |= (pvr == PVR_CELL_PPU);
#endif

   return altivec_capable;
   }

#endif

}

void CPUID::initialize()
   {
   u32bit cpuid[4] = { 0 };
   CALL_CPUID(1, cpuid);

   x86_processor_flags = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3];

#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
   /*
   * If we don't have access to CPUID, we can still safely assume that
   * any x86-64 processor has SSE2.
   */
   if(x86_processor_flags == 0)
     x86_processor_flags |= (1 << CPUID_SSE2_BIT);
#endif

   cache_line = get_x86_cache_line_size();

   altivec_capable = false;

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
      if(altivec_check_sysctl() || altivec_check_pvr_emul())
         altivec_capable = true;
#endif
   }

}
/*
* Data Store
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Default Matcher transform operation (identity)
*/
std::pair<std::string, std::string>
Data_Store::Matcher::transform(const std::string& key,
                               const std::string& value) const
   {
   return std::make_pair(key, value);
   }

/*
* Data_Store Equality Comparison
*/
bool Data_Store::operator==(const Data_Store& other) const
   {
   return (contents == other.contents);
   }

/*
* Check if this key has at least one value
*/
bool Data_Store::has_value(const std::string& key) const
   {
   return (contents.lower_bound(key) != contents.end());
   }

/*
* Search based on an arbitrary predicate
*/
std::multimap<std::string, std::string>
Data_Store::search_with(const Matcher& matcher) const
   {
   std::multimap<std::string, std::string> out;

   std::multimap<std::string, std::string>::const_iterator i =
      contents.begin();

   while(i != contents.end())
      {
      if(matcher(i->first, i->second))
         {
         std::pair<std::string, std::string> p(
            matcher.transform(i->first, i->second));

         multimap_insert(out, p.first, p.second);
         }

      ++i;
      }

   return out;
   }

/*
* Search based on key equality
*/
std::vector<std::string> Data_Store::get(const std::string& looking_for) const
   {
   typedef std::multimap<std::string, std::string>::const_iterator iter;

   std::pair<iter, iter> range = contents.equal_range(looking_for);

   std::vector<std::string> out;
   for(iter i = range.first; i != range.second; ++i)
      out.push_back(i->second);
   return out;
   }

/*
* Get a single atom
*/
std::string Data_Store::get1(const std::string& key) const
   {
   std::vector<std::string> vals = get(key);

   if(vals.empty())
      throw Invalid_State("Data_Store::get1: Not values for " + key);
   if(vals.size() > 1)
      throw Invalid_State("Data_Store::get1: More than one value for " + key);

   return vals[0];
   }

/*
* Get a single MemoryVector atom
*/
MemoryVector<byte>
Data_Store::get1_memvec(const std::string& key) const
   {
   std::vector<std::string> vals = get(key);

   if(vals.empty())
      return MemoryVector<byte>();

   if(vals.size() > 1)
      throw Invalid_State("Data_Store::get1_memvec: Multiple values for " +
                          key);

   return hex_decode(vals[0]);
   }

/*
* Get a single u32bit atom
*/
u32bit Data_Store::get1_u32bit(const std::string& key,
                               u32bit default_val) const
   {
   std::vector<std::string> vals = get(key);

   if(vals.empty())
      return default_val;
   else if(vals.size() > 1)
      throw Invalid_State("Data_Store::get1_u32bit: Multiple values for " +
                          key);

   return to_u32bit(vals[0]);
   }

/*
* Insert a single key and value
*/
void Data_Store::add(const std::string& key, const std::string& val)
   {
   multimap_insert(contents, key, val);
   }

/*
* Insert a single key and value
*/
void Data_Store::add(const std::string& key, u32bit val)
   {
   add(key, to_string(val));
   }

/*
* Insert a single key and value
*/
void Data_Store::add(const std::string& key, const MemoryRegion<byte>& val)
   {
   add(key, hex_encode(&val[0], val.size()));
   }

/*
* Insert a mapping of key/value pairs
*/
void Data_Store::add(const std::multimap<std::string, std::string>& in)
   {
   std::multimap<std::string, std::string>::const_iterator i = in.begin();
   while(i != in.end())
      {
      contents.insert(*i);
      ++i;
      }
   }

}
/**
* Dynamically Loaded Object
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <stdexcept>

#if defined(BOTAN_TARGET_OS_HAS_DLOPEN)
  #include <dlfcn.h>
#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY)
  #include <windows.h>
#endif

namespace Botan {

namespace {

void raise_runtime_loader_exception(const std::string& lib_name,
                                    const char* msg)
   {
   throw std::runtime_error("Failed to load " + lib_name + ": " +
                            (msg ? msg : "Unknown error"));
   }

}

Dynamically_Loaded_Library::Dynamically_Loaded_Library(
   const std::string& library) :
   lib_name(library), lib(0)
   {
#if defined(BOTAN_TARGET_OS_HAS_DLOPEN)
   lib = ::dlopen(lib_name.c_str(), RTLD_LAZY);

   if(!lib)
      raise_runtime_loader_exception(lib_name, dlerror());

#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY)
   lib = ::LoadLibraryA(lib_name.c_str());

   if(!lib)
      raise_runtime_loader_exception(lib_name, "LoadLibrary failed");
#endif

   if(!lib)
      raise_runtime_loader_exception(lib_name, "Dynamic load not supported");
   }

Dynamically_Loaded_Library::~Dynamically_Loaded_Library()
   {
#if defined(BOTAN_TARGET_OS_HAS_DLOPEN)
   ::dlclose(lib);
#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY)
   ::FreeLibrary((HMODULE)lib);
#endif
   }

void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol)
   {
   void* addr = 0;

#if defined(BOTAN_TARGET_OS_HAS_DLOPEN)
   addr = ::dlsym(lib, symbol.c_str());
#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY)
   addr = reinterpret_cast<void*>(::GetProcAddress((HMODULE)lib,
                                                   symbol.c_str()));
#endif

   if(!addr)
      throw std::runtime_error("Failed to resolve symbol " + symbol +
                               " in " + lib_name);

   return addr;
   }

}
/*
* Memory Locking Functions
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
  #include <sys/types.h>
  #include <sys/mman.h>
#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK)
  #include <windows.h>
#endif

namespace Botan {

bool has_mlock()
   {
   byte buf[4096];
   if(!lock_mem(&buf, sizeof(buf)))
      return false;
   unlock_mem(&buf, sizeof(buf));
   return true;
   }

/*
* Lock an area of memory into RAM
*/
bool lock_mem(void* ptr, size_t bytes)
   {
#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
   return (::mlock(static_cast<char*>(ptr), bytes) == 0);
#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK)
   return (::VirtualLock(ptr, bytes) != 0);
#else
   return false;
#endif
   }

/*
* Unlock a previously locked region of memory
*/
void unlock_mem(void* ptr, size_t bytes)
   {
#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
   ::munlock(static_cast<char*>(ptr), bytes);
#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK)
   ::VirtualUnlock(ptr, bytes);
#endif
   }

}
/*
* Parser Functions
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Convert a string into an integer
*/
u32bit to_u32bit(const std::string& number)
   {
   u32bit n = 0;

   for(std::string::const_iterator i = number.begin(); i != number.end(); ++i)
      {
      const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10;

      if(*i == ' ')
         continue;

      byte digit = Charset::char2digit(*i);

      if((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5))
         throw Decoding_Error("to_u32bit: Integer overflow");
      n *= 10;
      n += digit;
      }
   return n;
   }

/*
* Convert an integer into a string
*/
std::string to_string(u64bit n, size_t min_len)
   {
   std::string lenstr;
   if(n)
      {
      while(n > 0)
         {
         lenstr = Charset::digit2char(n % 10) + lenstr;
         n /= 10;
         }
      }
   else
      lenstr = "0";

   while(lenstr.size() < min_len)
      lenstr = "0" + lenstr;

   return lenstr;
   }

/*
* Convert a string into a time duration
*/
u32bit timespec_to_u32bit(const std::string& timespec)
   {
   if(timespec == "")
      return 0;

   const char suffix = timespec[timespec.size()-1];
   std::string value = timespec.substr(0, timespec.size()-1);

   u32bit scale = 1;

   if(Charset::is_digit(suffix))
      value += suffix;
   else if(suffix == 's')
      scale = 1;
   else if(suffix == 'm')
      scale = 60;
   else if(suffix == 'h')
      scale = 60 * 60;
   else if(suffix == 'd')
      scale = 24 * 60 * 60;
   else if(suffix == 'y')
      scale = 365 * 24 * 60 * 60;
   else
      throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec);

   return scale * to_u32bit(value);
   }

/*
* Parse a SCAN-style algorithm name
*/
std::vector<std::string> parse_algorithm_name(const std::string& namex)
   {
   if(namex.find('(') == std::string::npos &&
      namex.find(')') == std::string::npos)
      return std::vector<std::string>(1, namex);

   std::string name = namex, substring;
   std::vector<std::string> elems;
   size_t level = 0;

   elems.push_back(name.substr(0, name.find('(')));
   name = name.substr(name.find('('));

   for(std::string::const_iterator i = name.begin(); i != name.end(); ++i)
      {
      char c = *i;

      if(c == '(')
         ++level;
      if(c == ')')
         {
         if(level == 1 && i == name.end() - 1)
            {
            if(elems.size() == 1)
               elems.push_back(substring.substr(1));
            else
               elems.push_back(substring);
            return elems;
            }

         if(level == 0 || (level == 1 && i != name.end() - 1))
            throw Invalid_Algorithm_Name(namex);
         --level;
         }

      if(c == ',' && level == 1)
         {
         if(elems.size() == 1)
            elems.push_back(substring.substr(1));
         else
            elems.push_back(substring);
         substring.clear();
         }
      else
         substring += c;
      }

   if(substring != "")
      throw Invalid_Algorithm_Name(namex);

   return elems;
   }

/*
* Split the string on slashes
*/
std::vector<std::string> split_on(const std::string& str, char delim)
   {
   std::vector<std::string> elems;
   if(str == "") return elems;

   std::string substr;
   for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
      {
      if(*i == delim)
         {
         if(substr != "")
            elems.push_back(substr);
         substr.clear();
         }
      else
         substr += *i;
      }

   if(substr == "")
      throw Invalid_Argument("Unable to split string: " + str);
   elems.push_back(substr);

   return elems;
   }

/*
* Parse an ASN.1 OID string
*/
std::vector<u32bit> parse_asn1_oid(const std::string& oid)
   {
   std::string substring;
   std::vector<u32bit> oid_elems;

   for(std::string::const_iterator i = oid.begin(); i != oid.end(); ++i)
      {
      char c = *i;

      if(c == '.')
         {
         if(substring == "")
            throw Invalid_OID(oid);
         oid_elems.push_back(to_u32bit(substring));
         substring.clear();
         }
      else
         substring += c;
      }

   if(substring == "")
      throw Invalid_OID(oid);
   oid_elems.push_back(to_u32bit(substring));

   if(oid_elems.size() < 2)
      throw Invalid_OID(oid);

   return oid_elems;
   }

/*
* X.500 String Comparison
*/
bool x500_name_cmp(const std::string& name1, const std::string& name2)
   {
   std::string::const_iterator p1 = name1.begin();
   std::string::const_iterator p2 = name2.begin();

   while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
   while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;

   while(p1 != name1.end() && p2 != name2.end())
      {
      if(Charset::is_space(*p1))
         {
         if(!Charset::is_space(*p2))
            return false;

         while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
         while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;

         if(p1 == name1.end() && p2 == name2.end())
            return true;
         }

      if(!Charset::caseless_cmp(*p1, *p2))
         return false;
      ++p1;
      ++p2;
      }

   while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
   while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;

   if((p1 != name1.end()) || (p2 != name2.end()))
      return false;
   return true;
   }

/*
* Convert a decimal-dotted string to binary IP
*/
u32bit string_to_ipv4(const std::string& str)
   {
   std::vector<std::string> parts = split_on(str, '.');

   if(parts.size() != 4)
      throw Decoding_Error("Invalid IP string " + str);

   u32bit ip = 0;

   for(size_t i = 0; i != parts.size(); ++i)
      {
      u32bit octet = to_u32bit(parts[i]);

      if(octet > 255)
         throw Decoding_Error("Invalid IP string " + str);

      ip = (ip << 8) | (octet & 0xFF);
      }

   return ip;
   }

/*
* Convert an IP address to decimal-dotted string
*/
std::string ipv4_to_string(u32bit ip)
   {
   std::string str;

   for(size_t i = 0; i != sizeof(ip); ++i)
      {
      if(i)
         str += ".";
      str += to_string(get_byte(i, ip));
      }

   return str;
   }

}
/*
* Time Functions
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <ctime>

#if defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)
  #include <windows.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
  #include <sys/time.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)

  #ifndef _POSIX_C_SOURCE
    #define _POSIX_C_SOURCE 199309
  #endif

  #include <time.h>

  #ifndef CLOCK_REALTIME
    #define CLOCK_REALTIME 0
  #endif

#endif

namespace Botan {

namespace {

/*
* Combine a two time values into a single one
*/
u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz)
   {
   static const u64bit NANOSECONDS_UNITS = 1000000000;

   u64bit res = seconds * NANOSECONDS_UNITS;
   res += parts * (NANOSECONDS_UNITS / parts_hz);
   return res;
   }

std::tm do_gmtime(time_t time_val)
   {
   std::tm tm;

#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S)
   gmtime_s(&tm, &time_val); // Windows
#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R)
   gmtime_r(&time_val, &tm); // Unix/SUSv2
#else
   std::tm* tm_p = std::gmtime(&time_val);
   if (tm_p == 0)
      throw Encoding_Error("time_t_to_tm could not convert");
   tm = *tm_p;
#endif

   return tm;
   }

}

/*
* Get the system clock
*/
u64bit system_time()
   {
   return static_cast<u64bit>(std::time(0));
   }

/*
* Convert a time_point to a calendar_point
*/
calendar_point calendar_value(u64bit a_time_t)
   {
   std::tm tm = do_gmtime(static_cast<std::time_t>(a_time_t));

   return calendar_point(tm.tm_year + 1900,
                         tm.tm_mon + 1,
                         tm.tm_mday,
                         tm.tm_hour,
                         tm.tm_min,
                         tm.tm_sec);
   }

u64bit get_nanoseconds_clock()
   {
#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)

   struct ::timespec tv;
   ::clock_gettime(CLOCK_REALTIME, &tv);
   return combine_timers(tv.tv_sec, tv.tv_nsec, 1000000000);

#elif defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)

   struct ::timeval tv;
   ::gettimeofday(&tv, 0);
   return combine_timers(tv.tv_sec, tv.tv_usec, 1000000);

#elif defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)

   // Returns time since January 1, 1601 in 100-ns increments
   ::FILETIME tv;
   ::GetSystemTimeAsFileTime(&tv);
   u64bit tstamp = (static_cast<u64bit>(tv.dwHighDateTime) << 32) |
                   tv.dwLowDateTime;

   return (tstamp * 100); // Scale to 1 nanosecond units

#else

   return combine_timers(static_cast<u32bit>(std::time(0)),
                         std::clock(), CLOCKS_PER_SEC);

#endif
   }

}
/*
* User Interface
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/


namespace Botan {

/*
* Get a passphrase from the user
*/
std::string User_Interface::get_passphrase(const std::string&,
                                           const std::string&,
                                           UI_Result& action) const
   {
   action = OK;

   if(!first_try)
      action = CANCEL_ACTION;

   return preset_passphrase;
   }

/*
* User_Interface Constructor
*/
User_Interface::User_Interface(const std::string& preset) :
   preset_passphrase(preset)
   {
   first_try = true;
   }

}
/*
* Version Information
* (C) 1999-2011 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <sstream>

namespace Botan {

/*
  These are intentionally compiled rather than inlined, so an
  application running against a shared library can test the true
  version they are running against.
*/

/*
* Return the version as a string
*/
std::string version_string()
   {
   std::ostringstream out;

   out << "Botan " << version_major() << "."
       << version_minor() << "."
       << version_patch() << " (";

   if(BOTAN_VERSION_DATESTAMP == 0)
      out << "unreleased version";
   else
      out << "released " << version_datestamp();

   out << ", revision " << BOTAN_VERSION_VC_REVISION;
   out << ", distribution " << BOTAN_DISTRIBUTION_INFO << ")";

   return out.str();
   }

u32bit version_datestamp() { return BOTAN_VERSION_DATESTAMP; }

/*
* Return parts of the version as integers
*/
u32bit version_major() { return BOTAN_VERSION_MAJOR; }
u32bit version_minor() { return BOTAN_VERSION_MINOR; }
u32bit version_patch() { return BOTAN_VERSION_PATCH; }

}

namespace Botan {
PublicKeyPtr createRsaPublicKey(const BigInt &e, const BigInt &n)
{
    return PublicKeyPtr(new RSA_PublicKey(e, n));
}

PublicKeyPtr createDsaPublicKey(const DL_Group &group, const BigInt &y)
{
    return PublicKeyPtr(new DSA_PublicKey(group, y));
}

PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator &rng, const BigInt &p, const BigInt &q,
        const BigInt &e, const BigInt &d, const BigInt &n)
{
    return PrivateKeyPtr(new RSA_PrivateKey(rng, p, q, e, d, n));
}

PrivateKeyPtr createRsaPrivateKey(RandomNumberGenerator &rng, size_t bits, size_t exp)
{
    return PrivateKeyPtr(new RSA_PrivateKey(rng, bits, exp));
}

PrivateKeyPtr createDsaPrivateKey(RandomNumberGenerator &rng, const DL_Group &group,
        const BigInt &private_key)
{
    return PrivateKeyPtr(new DSA_PrivateKey(rng, group, private_key));
}

PrivateKeyPtr loadPkcs8PrivateKey(DataSource& source, RandomNumberGenerator& rng,
        const User_Interface& ui)
{
    return PrivateKeyPtr(PKCS8::load_key(source, rng, ui));
}

DhPrivateKeyPtr createDhPrivateKey(RandomNumberGenerator &rng, const DL_Group &grp, const BigInt &x)
{
    return DhPrivateKeyPtr(new DH_PrivateKey(rng, grp, x));
}

}
