/*
* (C) 2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_mp.h>
#include <memory>

#if defined(BOTAN_HAS_FPE_FE1)
  #include <botan/fpe_fe1.h>
#endif

extern "C" {

using namespace Botan_FFI;

#if defined(BOTAN_HAS_FPE_FE1)

BOTAN_FFI_DECLARE_STRUCT(botan_fpe_struct, Botan::FPE_FE1, 0xD49FB820);

#endif

int botan_fpe_fe1_init(botan_fpe_t* fpe, botan_mp_t n,
                       const uint8_t key[], size_t key_len,
                       size_t rounds, uint32_t flags)
   {
#if defined(BOTAN_HAS_FPE_FE1)

   return ffi_guard_thunk(__func__, [=]() {

      if(fpe == nullptr || key == nullptr)
         return BOTAN_FFI_ERROR_NULL_POINTER;

      *fpe = nullptr;

      if(flags != 0 && flags != BOTAN_FPE_FLAG_FE1_COMPAT_MODE)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      const bool compat_mode = (flags & BOTAN_FPE_FLAG_FE1_COMPAT_MODE);

      std::unique_ptr<Botan::FPE_FE1> fpe_obj(
         new Botan::FPE_FE1(safe_get(n), rounds, compat_mode));

      fpe_obj->set_key(key, key_len);

      *fpe = new botan_fpe_struct(fpe_obj.release());
      return BOTAN_FFI_SUCCESS;
      });
#else
   *fpe = nullptr;
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_fpe_destroy(botan_fpe_t fpe)
   {
#if defined(BOTAN_HAS_FPE_FE1)
   return BOTAN_FFI_CHECKED_DELETE(fpe);
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_fpe_encrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len)
   {
#if defined(BOTAN_HAS_FPE_FE1)
   return ffi_guard_thunk(__func__, [=]() {
      Botan::BigInt r = safe_get(fpe).encrypt(safe_get(x), tweak, tweak_len);
      safe_get(x) = r;
      return BOTAN_FFI_SUCCESS;
      });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_fpe_decrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len)
   {
#if defined(BOTAN_HAS_FPE_FE1)
   return ffi_guard_thunk(__func__, [=]() {
      Botan::BigInt r = safe_get(fpe).decrypt(safe_get(x), tweak, tweak_len);
      safe_get(x) = r;
      return BOTAN_FFI_SUCCESS;
      });

#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

}
