51zj il y a 3 semaines
commit
4d325d962f
100 fichiers modifiés avec 25909 ajouts et 0 suppressions
  1. 903 0
      ActiveXWrapper.cpp
  2. 125 0
      ActiveXWrapper.h
  3. 329 0
      Authorization.cpp
  4. 69 0
      Authorization.h
  5. 185 0
      CommModifyService.vcxproj
  6. 25 0
      CommModifyService.vcxproj.filters
  7. 89 0
      CommWrapperBase.h
  8. 347 0
      DllWrapper.cpp
  9. 84 0
      DllWrapper.h
  10. 89 0
      Logger.cpp
  11. 46 0
      Logger.h
  12. 54 0
      Utils.cpp
  13. 16 0
      Utils.h
  14. 343 0
      WebServer.cpp
  15. 87 0
      WebServer.h
  16. 368 0
      WebSocketHandler.cpp
  17. 70 0
      WebSocketHandler.h
  18. 160 0
      WebSocketSession.cpp
  19. 66 0
      WebSocketSession.h
  20. 63 0
      cryptopp/3way.h
  21. BIN
      cryptopp/Win32/Debug/cryptlib.lib
  22. BIN
      cryptopp/Win32/Debug/cryptlib.pdb
  23. BIN
      cryptopp/Win32/Release/cryptlib.lib
  24. BIN
      cryptopp/Win32/Release/cryptlib.pdb
  25. 33 0
      cryptopp/adler32.h
  26. 1281 0
      cryptopp/adv_simd.h
  27. 30 0
      cryptopp/aes.h
  28. 30 0
      cryptopp/aes_armv4.h
  29. 453 0
      cryptopp/algebra.h
  30. 520 0
      cryptopp/algparam.h
  31. 74 0
      cryptopp/allocate.h
  32. 89 0
      cryptopp/arc4.h
  33. 99 0
      cryptopp/argnames.h
  34. 71 0
      cryptopp/aria.h
  35. 427 0
      cryptopp/arm_simd.h
  36. 974 0
      cryptopp/asn.h
  37. 87 0
      cryptopp/authenc.h
  38. 158 0
      cryptopp/base32.h
  39. 158 0
      cryptopp/base64.h
  40. 146 0
      cryptopp/basecode.h
  41. 105 0
      cryptopp/bench.h
  42. 444 0
      cryptopp/blake2.h
  43. 54 0
      cryptopp/blowfish.h
  44. 70 0
      cryptopp/blumshub.h
  45. 49 0
      cryptopp/camellia.h
  46. 109 0
      cryptopp/cast.h
  47. 63 0
      cryptopp/cbcmac.h
  48. 123 0
      cryptopp/ccm.h
  49. 223 0
      cryptopp/chacha.h
  50. 322 0
      cryptopp/chachapoly.h
  51. 179 0
      cryptopp/cham.h
  52. 142 0
      cryptopp/channels.h
  53. 76 0
      cryptopp/cmac.h
  54. 33 0
      cryptopp/config.h
  55. 72 0
      cryptopp/config_align.h
  56. 492 0
      cryptopp/config_asm.h
  57. 212 0
      cryptopp/config_cpu.h
  58. 250 0
      cryptopp/config_cxx.h
  59. 178 0
      cryptopp/config_dll.h
  60. 268 0
      cryptopp/config_int.h
  61. 199 0
      cryptopp/config_misc.h
  62. 76 0
      cryptopp/config_ns.h
  63. 168 0
      cryptopp/config_os.h
  64. 98 0
      cryptopp/config_ver.h
  65. 1089 0
      cryptopp/cpu.h
  66. 90 0
      cryptopp/crc.h
  67. 3384 0
      cryptopp/cryptlib.h
  68. 95 0
      cryptopp/darn.h
  69. 310 0
      cryptopp/default.h
  70. 163 0
      cryptopp/des.h
  71. 275 0
      cryptopp/dh.h
  72. 70 0
      cryptopp/dh2.h
  73. 71 0
      cryptopp/dll.h
  74. 114 0
      cryptopp/dmac.h
  75. 179 0
      cryptopp/donna.h
  76. 411 0
      cryptopp/donna_32.h
  77. 457 0
      cryptopp/donna_64.h
  78. 86 0
      cryptopp/donna_sse.h
  79. 718 0
      cryptopp/drbg.h
  80. 53 0
      cryptopp/dsa.h
  81. 112 0
      cryptopp/eax.h
  82. 136 0
      cryptopp/ec2n.h
  83. 686 0
      cryptopp/eccrypto.h
  84. 167 0
      cryptopp/ecp.h
  85. 146 0
      cryptopp/ecpoint.h
  86. 308 0
      cryptopp/elgamal.h
  87. 101 0
      cryptopp/emsa2.h
  88. 162 0
      cryptopp/eprecomp.h
  89. 169 0
      cryptopp/esign.h
  90. 179 0
      cryptopp/factory.h
  91. 408 0
      cryptopp/fhmqv.h
  92. 181 0
      cryptopp/files.h
  93. 1529 0
      cryptopp/filters.h
  94. 112 0
      cryptopp/fips140.h
  95. 69 0
      cryptopp/fltrimpl.h
  96. 139 0
      cryptopp/gcm.h
  97. 72 0
      cryptopp/gf256.h
  98. 73 0
      cryptopp/gf2_32.h
  99. 406 0
      cryptopp/gf2n.h
  100. 1036 0
      cryptopp/gfpcrypt.h

+ 903 - 0
ActiveXWrapper.cpp

@@ -0,0 +1,903 @@
+#include "ActiveXWrapper.h"
+#include "Logger.h"
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+#include <comutil.h> // 添加这个包含以使用_com_util::ConvertBSTRToString
+
+// ActiveXEventSink 实现
+ActiveXEventSink::ActiveXEventSink(CommEventCallback callback)
+    : ref_count_(1), callback_(callback)
+{
+}
+
+ActiveXEventSink::~ActiveXEventSink()
+{
+}
+
+// 修复QueryInterface函数 - 支持ICommModifyKitEvents接口
+STDMETHODIMP ActiveXEventSink::QueryInterface(REFIID riid, void **ppvObject)
+{
+    if (!ppvObject)
+    {
+        return E_POINTER;
+    }
+
+    *ppvObject = nullptr;
+
+    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch))
+    {
+        *ppvObject = static_cast<IDispatch *>(this);
+        AddRef();
+        return S_OK;
+    }
+
+    // 支持事件接口
+    if (IsEqualIID(riid, IID_ICommModifyKitEvents))
+    {
+        *ppvObject = static_cast<IDispatch *>(this);
+        AddRef();
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG)
+ActiveXEventSink::AddRef()
+{
+    return InterlockedIncrement(&ref_count_);
+}
+
+STDMETHODIMP_(ULONG)
+ActiveXEventSink::Release()
+{
+    ULONG count = InterlockedDecrement(&ref_count_);
+    if (count == 0)
+    {
+        delete this;
+    }
+    return count;
+}
+
+STDMETHODIMP ActiveXEventSink::GetTypeInfoCount(UINT *pctinfo)
+{
+    *pctinfo = 0;
+    return S_OK;
+}
+
+STDMETHODIMP ActiveXEventSink::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP ActiveXEventSink::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP ActiveXEventSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
+                                      DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    // 清空并重写函数,只处理6个参数的情况
+    // 6个参数从DISPPARAMS *pDispParams中解析出来
+
+    // 检查参数是否有效
+    if (!pDispParams)
+    {
+        LOG_ERROR("Invalid DISPPARAMS");
+        return E_INVALIDARG;
+    }
+
+    // 检查参数数量是否为6
+    if (pDispParams->cArgs != 6)
+    {
+        LOG_ERROR("Expected 6 parameters, but got " + std::to_string(pDispParams->cArgs));
+        return E_INVALIDARG;
+    }
+
+    try
+    {
+        // 从pDispParams中解析6个参数
+        VARIANT *args = pDispParams->rgvarg;
+
+        // 解析参数(注意:VARIANT参数是逆序的)
+        // 参数6: lpData (char*)
+        char *lpData = nullptr;
+        if (args[0].vt == VT_BYREF || args[0].vt == (VT_ARRAY | VT_UI1))
+        {
+            // 处理数组数据
+            if (args[0].vt == (VT_ARRAY | VT_UI1) && args[0].parray)
+            {
+                SAFEARRAY *data = args[0].parray;
+                BYTE *data_ptr;
+                SafeArrayAccessData(data, reinterpret_cast<void **>(&data_ptr));
+                lpData = reinterpret_cast<char *>(data_ptr);
+            }
+        }
+        else if (args[0].vt == VT_BSTR)
+        {
+            // 处理字符串数据
+            lpData = _com_util::ConvertBSTRToString(args[0].bstrVal);
+        }
+
+        // 参数5: dwSize (DWORD)
+        DWORD dwSize = 0;
+        if (args[1].vt == VT_I4 || args[1].vt == VT_UI4)
+        {
+            dwSize = static_cast<DWORD>(args[1].lVal);
+        }
+
+        // 参数4: Irp (DWORD)
+        DWORD Irp = 0;
+        if (args[2].vt == VT_I4 || args[2].vt == VT_UI4)
+        {
+            Irp = static_cast<DWORD>(args[2].lVal);
+        }
+
+        // 参数3: ComNumber (DWORD)
+        DWORD ComNumber = 0;
+        if (args[3].vt == VT_I4 || args[3].vt == VT_UI4)
+        {
+            ComNumber = static_cast<DWORD>(args[3].lVal);
+        }
+
+        // 参数2: dTime (TDateTime/double)
+        // TDateTime dTime = 0.0;
+        // if (args[4].vt == VT_R8)
+        //{
+        //    dTime = static_cast<TDateTime>(args[4].dblVal);
+        //}
+
+        // 参数1: Sequence (int)
+        int Sequence = 0;
+        if (args[5].vt == VT_I4)
+        {
+            Sequence = args[5].lVal;
+        }
+
+        // 打印6个参数值的日志
+        LOG_DEBUG("ActiveX event parameters:");
+        // LOG_DEBUG("  Sequence: " + std::to_string(Sequence));
+        // LOG_DEBUG("  dTime: " + std::to_string(dTime));
+        LOG_DEBUG("  ComNumber: " + std::to_string(ComNumber));
+        LOG_DEBUG("  Irp: " + std::to_string(Irp));
+        LOG_DEBUG("  dwSize: " + std::to_string(dwSize));
+        LOG_DEBUG("  lpData: " + std::to_string(reinterpret_cast<uintptr_t>(lpData)));
+
+        // 调用回调函数
+        if (callback_)
+        {
+            try
+            {
+                // 创建CommEventData结构以传递给回调函数
+                CommEventData event_data;
+                event_data.event_type = static_cast<CommEventType>(Irp);
+                event_data.port = static_cast<int>(ComNumber);
+
+                if (lpData && dwSize > 0)
+                {
+                    event_data.data.assign(reinterpret_cast<BYTE *>(lpData), reinterpret_cast<BYTE *>(lpData) + dwSize);
+                }
+                event_data.data_size = dwSize;
+
+                callback_(event_data);
+                LOG_DEBUG("ActiveX event processed successfully");
+            }
+            catch (const std::exception &e)
+            {
+                LOG_ERROR("Error in ActiveX event callback: " + std::string(e.what()));
+                // 释放分配的内存
+                if (args[0].vt == VT_BSTR && lpData)
+                {
+                    delete[] lpData;
+                }
+                else if (args[0].vt == (VT_ARRAY | VT_UI1) && args[0].parray)
+                {
+                    SafeArrayUnaccessData(args[0].parray);
+                }
+                return E_FAIL;
+            }
+        }
+
+        // 释放分配的内存
+        if (args[0].vt == VT_BSTR && lpData)
+        {
+            delete[] lpData;
+        }
+        else if (args[0].vt == (VT_ARRAY | VT_UI1) && args[0].parray)
+        {
+            SafeArrayUnaccessData(args[0].parray);
+        }
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error processing ActiveX event: " + std::string(e.what()));
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+// ActiveXWrapper 实现
+ActiveXWrapper::ActiveXWrapper()
+    : activex_control_(nullptr), connection_point_(nullptr), connection_cookie_(0),
+      event_sink_(nullptr), event_connected_(false)
+{
+}
+
+ActiveXWrapper::~ActiveXWrapper()
+{
+    Cleanup();
+}
+
+bool ActiveXWrapper::Initialize()
+{
+    if (initialized_)
+    {
+        return true;
+    }
+
+    // 初始化COM
+    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    if (FAILED(hr) && hr != S_FALSE)
+    {
+        LOG_ERROR("Failed to initialize COM, HRESULT: " + std::to_string(hr));
+        return false;
+    }
+
+    // 使用正确的CLSID创建ActiveX控件
+    hr = CoCreateInstance(CLSID_CommModifyKit, nullptr, CLSCTX_INPROC_SERVER,
+                                  IID_IDispatch, reinterpret_cast<void **>(&activex_control_));
+    if (FAILED(hr))
+    {
+        LOG_ERROR("Failed to create ActiveX control, HRESULT: " + std::to_string(hr));
+
+        // 尝试使用ProgID创建
+        CLSID clsid;
+        hr = CLSIDFromProgID(L"PCommMKit.CommModifyKit", &clsid);
+        if (SUCCEEDED(hr))
+        {
+            hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER,
+                                  IID_IDispatch, reinterpret_cast<void **>(&activex_control_));
+        }
+
+        if (FAILED(hr))
+        {
+            LOG_ERROR("Failed to create ActiveX control using ProgID, HRESULT: " + std::to_string(hr));
+            return false;
+        }
+    }
+
+    if (!InitializeMethodIds())
+    {
+        LOG_ERROR("Failed to initialize method IDs");
+        return false;
+    }
+
+    // 连接事件
+    if (!ConnectEvents())
+    {
+        LOG_ERROR("Failed to connect events");
+        return false;
+    }
+
+    initialized_ = true;
+    LOG_INFO("ActiveX control initialized successfully");
+    return true;
+}
+
+bool ActiveXWrapper::ConnectEvents()
+{
+    if (!activex_control_)
+    {
+        return false;
+    }
+
+    // 获取连接点容器
+    IConnectionPointContainer *cpc = nullptr;
+    HRESULT hr = activex_control_->QueryInterface(IID_IConnectionPointContainer,
+                                                  reinterpret_cast<void **>(&cpc));
+    if (FAILED(hr))
+    {
+        LOG_ERROR("Failed to get connection point container, HRESULT: " + std::to_string(hr));
+        return false;
+    }
+
+    // 首先尝试直接查找事件接口的连接点
+    hr = cpc->FindConnectionPoint(IID_ICommModifyKitEvents, &connection_point_);
+    if (SUCCEEDED(hr))
+    {
+        LOG_INFO("Found connection point for ICommModifyKitEvents directly");
+    }
+    else
+    {
+        LOG_WARNING("Direct connection point lookup failed, HRESULT: " + std::to_string(hr) + ", trying enumeration");
+
+        // 如果直接查找失败,枚举所有连接点
+        IEnumConnectionPoints *enum_cp = nullptr;
+        hr = cpc->EnumConnectionPoints(&enum_cp);
+        if (SUCCEEDED(hr))
+        {
+            IConnectionPoint *cp = nullptr;
+            ULONG fetched = 0;
+
+            // 枚举所有连接点,查找正确的事件接口
+            while (enum_cp->Next(1, &cp, &fetched) == S_OK && fetched > 0)
+            {
+                IID iid;
+                if (SUCCEEDED(cp->GetConnectionInterface(&iid)))
+                {
+                    // 记录找到的接口ID用于调试
+                    char iid_str[64];
+                    sprintf_s(iid_str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+                              iid.Data1, iid.Data2, iid.Data3,
+                              iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3],
+                              iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
+                    LOG_DEBUG("Found connection point with IID: " + std::string(iid_str));
+
+                    // 检查是否是我们需要的事件接口
+                    if (IsEqualIID(iid, IID_ICommModifyKitEvents))
+                    {
+                        connection_point_ = cp;
+                        connection_point_->AddRef();
+                        cp->Release(); // 释放枚举得到的引用
+                        LOG_INFO("Found ICommModifyKitEvents connection point through enumeration");
+                        break;
+                    }
+                }
+                cp->Release();
+            }
+            enum_cp->Release();
+        }
+    }
+
+    cpc->Release();
+
+    if (!connection_point_)
+    {
+        LOG_ERROR("Failed to find any connection point for ICommModifyKitEvents");
+        return false;
+    }
+
+    // 创建事件接收器
+    event_sink_ = new ActiveXEventSink([this](const CommEventData &event_data)
+                                       { 
+                                           // 直接使用通用事件数据调用通用回调
+                                           if (event_callback_) {
+                                               event_callback_(event_data);
+                                           } });
+
+    // 连接事件接收器
+    hr = connection_point_->Advise(event_sink_, &connection_cookie_);
+    if (FAILED(hr))
+    {
+        LOG_ERROR("Failed to advise connection point, HRESULT: " + std::to_string(hr));
+        event_sink_->Release();
+        event_sink_ = nullptr;
+        return false;
+    }
+
+    event_connected_ = true;
+    LOG_INFO("ActiveX events connected successfully, cookie: " + std::to_string(connection_cookie_));
+    return true;
+}
+
+void ActiveXWrapper::DisconnectEvents()
+{
+    if (event_connected_ && connection_point_ && connection_cookie_ != 0)
+    {
+        connection_point_->Unadvise(connection_cookie_);
+        connection_cookie_ = 0;
+        event_connected_ = false;
+    }
+
+    if (connection_point_)
+    {
+        connection_point_->Release();
+        connection_point_ = nullptr;
+    }
+
+    if (event_sink_)
+    {
+        event_sink_->Release();
+        event_sink_ = nullptr;
+    }
+}
+
+bool ActiveXWrapper::InitializeMethodIds()
+{
+    if (!activex_control_)
+    {
+        return false;
+    }
+
+    // 获取方法的DISPID
+    LPOLESTR method_names[] = {
+        const_cast<LPOLESTR>(L"InitMonitor"),
+        const_cast<LPOLESTR>(L"MonitorPort"),
+        const_cast<LPOLESTR>(L"StopPort"),
+        const_cast<LPOLESTR>(L"ReadData"),
+        const_cast<LPOLESTR>(L"WriteData"),
+        const_cast<LPOLESTR>(L"FreeMonitor"),
+        const_cast<LPOLESTR>(L"GetLastError")};
+
+    DISPID *method_ids[] = {
+        &init_monitor_id_,
+        &monitor_port_id_,
+        &stop_port_id_,
+        &read_data_id_,
+        &write_data_id_,
+        &free_monitor_id_,
+        &get_last_error_id_};
+
+    for (int i = 0; i < 7; i++)
+    {
+        HRESULT hr = activex_control_->GetIDsOfNames(IID_NULL, &method_names[i], 1,
+                                                     LOCALE_USER_DEFAULT, method_ids[i]);
+        if (FAILED(hr))
+        {
+            LOG_ERROR("Failed to get method ID for method");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+HRESULT ActiveXWrapper::InvokeMethod(DISPID dispid, VARIANT *params, int param_count, VARIANT *result)
+{
+    if (!activex_control_)
+    {
+        return E_FAIL;
+    }
+
+    DISPPARAMS disp_params = {params, nullptr, param_count, 0};
+    EXCEPINFO excep_info = {0};
+    UINT arg_err = 0;
+
+    return activex_control_->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+                                    DISPATCH_METHOD, &disp_params, result,
+                                    &excep_info, &arg_err);
+}
+
+bool ActiveXWrapper::InitMonitor(const std::string &key)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("ActiveX control not initialized");
+        return false;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    if (callback_initialized_)
+    {
+        return true;
+    }
+
+    // 转换字符串参数
+    _bstr_t bstr_key(key.c_str());
+    VARIANT param;
+    VariantInit(&param);
+    param.vt = VT_BSTR;
+    param.bstrVal = bstr_key;
+
+    VARIANT result;
+    VariantInit(&result);
+
+    HRESULT hr = InvokeMethod(init_monitor_id_, &param, 1, &result);
+
+    bool success = false;
+    if (SUCCEEDED(hr) && result.vt == VT_BOOL)
+    {
+        success = result.boolVal != VARIANT_FALSE;
+        callback_initialized_ = success;
+    }
+
+    VariantClear(&param);
+    VariantClear(&result);
+
+    if (success)
+    {
+        LOG_INFO("InitMonitor succeeded");
+    }
+    else
+    {
+        LOG_ERROR("InitMonitor failed, error code: " + std::to_string(GetLastError()));
+    }
+
+    return success;
+}
+
+bool ActiveXWrapper::MonitorPort(int port)
+{
+    if (!initialized_ || !callback_initialized_)
+    {
+        LOG_ERROR("ActiveX control not properly initialized");
+        return false;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    VARIANT param;
+    VariantInit(&param);
+    param.vt = VT_I4;
+    param.lVal = port;
+
+    VARIANT result;
+    VariantInit(&result);
+
+    HRESULT hr = InvokeMethod(monitor_port_id_, &param, 1, &result);
+
+    bool success = false;
+    if (SUCCEEDED(hr) && result.vt == VT_BOOL)
+    {
+        success = result.boolVal != VARIANT_FALSE;
+        if (success)
+        {
+            monitored_ports_[port] = true;
+        }
+    }
+
+    VariantClear(&param);
+    VariantClear(&result);
+
+    if (success)
+    {
+        LOG_INFO("MonitorPort succeeded for port " + std::to_string(port));
+    }
+    else
+    {
+        LOG_ERROR("MonitorPort failed for port " + std::to_string(port) + ", error code: " + std::to_string(GetLastError()));
+    }
+
+    return success;
+}
+
+bool ActiveXWrapper::StopPort(int port)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("ActiveX control not initialized");
+        return false;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    VARIANT param;
+    VariantInit(&param);
+    param.vt = VT_I4;
+    param.lVal = port;
+
+    VARIANT result;
+    VariantInit(&result);
+
+    HRESULT hr = InvokeMethod(stop_port_id_, &param, 1, &result);
+
+    bool success = false;
+    if (SUCCEEDED(hr) && result.vt == VT_BOOL)
+    {
+        success = result.boolVal != VARIANT_FALSE;
+        if (success)
+        {
+            monitored_ports_[port] = false;
+        }
+    }
+
+    VariantClear(&param);
+    VariantClear(&result);
+
+    if (success)
+    {
+        LOG_INFO("StopPort succeeded for port " + std::to_string(port));
+    }
+    else
+    {
+        LOG_ERROR("StopPort failed for port " + std::to_string(port) + ", error code: " + std::to_string(GetLastError()));
+    }
+
+    return success;
+}
+
+// 修复ReadData函数 - 移除SafeArrayDestroy双重释放
+bool ActiveXWrapper::ReadData(int port, const std::string &hex_data)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("ActiveX control not initialized");
+        return false;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    // 将十六进制字符串转换为字节数组
+    std::vector<BYTE> bytes = Utils::ConvertHexStringToBytes(hex_data);
+
+    // 使用辅助函数创建SafeArray
+    SAFEARRAY *sa = CreateSafeArrayFromBytes(bytes);
+    if (!sa)
+    {
+        LOG_ERROR("Failed to create SafeArray");
+        return false;
+    }
+
+    // 准备参数
+    VARIANT params[3];
+    VariantInit(&params[0]);
+    VariantInit(&params[1]);
+    VariantInit(&params[2]);
+
+    params[0].vt = VT_I4;
+    params[0].lVal = port;
+
+    params[1].vt = VT_ARRAY | VT_UI1;
+    params[1].parray = sa;
+
+    params[2].vt = VT_I4;
+    params[2].lVal = static_cast<LONG>(bytes.size());
+
+    VARIANT result;
+    VariantInit(&result);
+
+    // 调用ActiveX控件的ReadData方法
+    HRESULT hr = InvokeMethod(read_data_id_, params, 3, &result);
+
+    bool success = SUCCEEDED(hr);
+    if (success && result.vt == VT_BOOL)
+    {
+        success = result.boolVal != VARIANT_FALSE;
+    }
+
+    // 只清理VARIANT,VariantClear会自动处理SafeArray
+    for (int i = 0; i < 3; i++)
+    {
+        VariantClear(&params[i]);
+    }
+    VariantClear(&result);
+    // 不要调用SafeArrayDestroy(sa) - 这会导致双重释放崩溃
+
+    if (success)
+    {
+        LOG_DEBUG("ReadData succeeded for port " + std::to_string(port) + ", data: " + hex_data);
+    }
+    else
+    {
+        LOG_ERROR("ReadData failed for port " + std::to_string(port) + ", HRESULT: " + std::to_string(hr));
+    }
+
+    return success;
+}
+
+// 修复WriteData函数 - 移除SafeArrayDestroy双重释放
+bool ActiveXWrapper::WriteData(int port, const std::string &hex_data)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("ActiveX control not initialized");
+        return false;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    // 将十六进制字符串转换为字节数组
+    std::vector<BYTE> bytes = Utils::ConvertHexStringToBytes(hex_data);
+
+    // 使用辅助函数创建SafeArray
+    SAFEARRAY *sa = CreateSafeArrayFromBytes(bytes);
+    if (!sa)
+    {
+        LOG_ERROR("Failed to create SafeArray");
+        return false;
+    }
+
+    // 准备参数
+    VARIANT params[3];
+    VariantInit(&params[0]);
+    VariantInit(&params[1]);
+    VariantInit(&params[2]);
+
+    params[0].vt = VT_I4;
+    params[0].lVal = port;
+
+    params[1].vt = VT_ARRAY | VT_UI1;
+    params[1].parray = sa;
+
+    params[2].vt = VT_I4;
+    params[2].lVal = static_cast<LONG>(bytes.size());
+
+    VARIANT result;
+    VariantInit(&result);
+
+    // 调用ActiveX控件的WriteData方法
+    HRESULT hr = InvokeMethod(write_data_id_, params, 3, &result);
+
+    bool success = SUCCEEDED(hr);
+    if (success && result.vt == VT_BOOL)
+    {
+        success = result.boolVal != VARIANT_FALSE;
+    }
+
+    // 只清理VARIANT,VariantClear会自动处理SafeArray
+    for (int i = 0; i < 3; i++)
+    {
+        VariantClear(&params[i]);
+    }
+    VariantClear(&result);
+    // 不要调用SafeArrayDestroy(sa) - 这会导致双重释放崩溃
+
+    if (success)
+    {
+        LOG_DEBUG("WriteData succeeded for port " + std::to_string(port) + ", data: " + hex_data);
+    }
+    else
+    {
+        LOG_ERROR("WriteData failed for port " + std::to_string(port) + ", HRESULT: " + std::to_string(hr));
+    }
+
+    return success;
+}
+
+bool ActiveXWrapper::FreeMonitor()
+{
+    if (!initialized_)
+    {
+        return true;
+    }
+
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    VARIANT result;
+    VariantInit(&result);
+
+    HRESULT hr = InvokeMethod(free_monitor_id_, nullptr, 0, &result);
+
+    bool success = SUCCEEDED(hr);
+    if (success)
+    {
+        callback_initialized_ = false;
+        monitored_ports_.clear();
+        LOG_INFO("FreeMonitor succeeded");
+    }
+    else
+    {
+        LOG_ERROR("FreeMonitor failed");
+    }
+
+    VariantClear(&result);
+    return success;
+}
+
+int ActiveXWrapper::GetLastError()
+{
+    if (!initialized_)
+    {
+        return -1;
+    }
+
+    VARIANT result;
+    VariantInit(&result);
+
+    HRESULT hr = InvokeMethod(get_last_error_id_, nullptr, 0, &result);
+
+    int error_code = -1;
+    if (SUCCEEDED(hr) && result.vt == VT_I4)
+    {
+        error_code = result.lVal;
+    }
+
+    VariantClear(&result);
+    return error_code;
+}
+
+void ActiveXWrapper::SetEventCallback(CommEventCallback callback)
+{
+    // 调用基类的实现来设置回调
+    CommWrapperBase::SetEventCallback(callback);
+
+    // 设置ActiveX事件回调,将ActiveX事件数据转换为通用事件数据后再调用通用回调
+    event_callback_ = [this](const CommEventData &event_data)
+    {
+        // 调用通用回调
+        if (event_callback_)
+        {
+            event_callback_(event_data);
+        }
+    };
+}
+
+std::string ActiveXWrapper::GetErrorMessage(int error_code)
+{
+    switch (error_code)
+    {
+    case -241:
+        return "安装驱动失败";
+    case -243:
+        return "其他错误";
+    case -244:
+        return "驱动文件";
+    case -255:
+        return "绑定串口失败";
+    case -254:
+        return "第一次启动安装,必须以管理员权限运行";
+    case -253:
+        return "启动驱动服务失败";
+    case -252:
+        return "请检查Key是否有效";
+    case -1:
+        return "无效操作";
+    case 0:
+        return "成功";
+    case 1:
+        return "串口打开失败";
+    case 2:
+        return "串口配置失败";
+    case 3:
+        return "串口读取失败";
+    case 4:
+        return "串口写入失败";
+    case 5:
+        return "串口关闭失败";
+    default:
+        return "未知错误";
+    }
+}
+
+bool ActiveXWrapper::IsPortMonitored(int port)
+{
+    std::lock_guard<std::mutex> lock(mutex_);
+    auto it = monitored_ports_.find(port);
+    return it != monitored_ports_.end() && it->second;
+}
+
+SAFEARRAY *ActiveXWrapper::CreateSafeArrayFromBytes(const std::vector<BYTE> &bytes)
+{
+    // 创建SafeArray来传递字节数组
+    SAFEARRAYBOUND bounds[1];
+    bounds[0].lLbound = 0;
+    bounds[0].cElements = static_cast<ULONG>(bytes.size());
+    SAFEARRAY *sa = SafeArrayCreate(VT_UI1, 1, bounds);
+
+    if (!sa)
+    {
+        LOG_ERROR("Failed to create SafeArray");
+        return nullptr;
+    }
+
+    // 将数据复制到SafeArray
+    BYTE *data_ptr;
+    HRESULT hr = SafeArrayAccessData(sa, reinterpret_cast<void **>(&data_ptr));
+    if (SUCCEEDED(hr))
+    {
+        memcpy(data_ptr, bytes.data(), bytes.size());
+        SafeArrayUnaccessData(sa);
+    }
+    else
+    {
+        LOG_ERROR("Failed to access SafeArray data");
+        SafeArrayDestroy(sa);
+        return nullptr;
+    }
+
+    return sa;
+}
+
+void ActiveXWrapper::Cleanup()
+{
+    if (initialized_)
+    {
+        FreeMonitor();
+        DisconnectEvents();
+
+        if (activex_control_)
+        {
+            activex_control_->Release();
+            activex_control_ = nullptr;
+        }
+
+        // 释放COM
+        CoUninitialize();
+        initialized_ = false;
+        LOG_INFO("ActiveX control cleaned up");
+    }
+}

+ 125 - 0
ActiveXWrapper.h

@@ -0,0 +1,125 @@
+#pragma once
+
+#include "CommWrapperBase.h"
+#include "Utils.h"
+#include <windows.h>
+#include <comdef.h>
+#include <string>
+#include <vector>
+#include <functional>
+#include <map>
+#include <mutex>
+#include <thread>
+
+// ActiveX控件的CLSID和接口IID定义
+static const CLSID CLSID_CommModifyKit = {0x97531C46, 0x4E70, 0x414F, {0x9A, 0x8F, 0x75, 0x8D, 0x38, 0xD5, 0x74, 0xC4}};
+static const IID IID_ICommModifyKit = {0xAE3785CB, 0x0862, 0x4FD0, {0xB6, 0x24, 0x1E, 0x10, 0x38, 0x2D, 0x21, 0x7A}};
+static const IID IID_ICommModifyKitEvents = {0x18A98A73, 0xE96C, 0x4268, {0x88, 0x1E, 0x1E, 0x82, 0xDE, 0x50, 0xB2, 0x10}};
+static const IID IID_TypeLib_CommModifyKit = {0x41159543, 0xEA6B, 0x4C44, {0x84, 0xF2, 0xD5, 0xF9, 0xFC, 0xEE, 0x35, 0x41}};
+
+// 使用基类定义的事件类型、数据结构和回调函数类型
+// enum class ActiveXEventType -> CommEventType
+// struct ActiveXEventData -> CommEventData
+// using ActiveXEventCallback -> CommEventCallback
+
+// COM事件接收器类
+class ActiveXEventSink : public IDispatch
+{
+private:
+    LONG ref_count_;
+    CommEventCallback callback_;
+
+public:
+    ActiveXEventSink(CommEventCallback callback);
+    virtual ~ActiveXEventSink();
+
+    // IUnknown methods
+    STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
+    STDMETHOD_(ULONG, AddRef)();
+    STDMETHOD_(ULONG, Release)();
+
+    // IDispatch methods
+    STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
+    STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
+    STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
+    STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
+};
+
+class ActiveXWrapper : public CommWrapperBase
+{
+private:
+    IDispatch *activex_control_;
+    IConnectionPoint *connection_point_;
+    DWORD connection_cookie_;
+    ActiveXEventSink *event_sink_;
+    bool event_connected_;
+
+    // COM接口方法ID
+    DISPID init_monitor_id_;
+    DISPID monitor_port_id_;
+    DISPID stop_port_id_;
+    DISPID read_data_id_;
+    DISPID write_data_id_;
+    DISPID free_monitor_id_;
+    DISPID get_last_error_id_;
+
+    // 初始化方法ID
+    bool InitializeMethodIds();
+
+    // 连接事件
+    bool ConnectEvents();
+
+    // 断开事件
+    void DisconnectEvents();
+
+    // 调用COM方法的辅助函数
+    HRESULT InvokeMethod(DISPID dispid, VARIANT *params, int param_count, VARIANT *result = nullptr);
+
+    // 创建SAFEARRAY的辅助函数
+    SAFEARRAY* CreateSafeArrayFromBytes(const std::vector<BYTE>& bytes);
+
+
+
+public:
+    ActiveXWrapper();
+    ~ActiveXWrapper();
+
+    // 初始化ActiveX控件
+    bool Initialize();
+
+    // 释放资源
+    void Cleanup();
+
+    // 初始化监控
+    bool InitMonitor(const std::string &key = "C09976511B62F0ADB759D87E6906D865");
+
+    // 监控端口
+    bool MonitorPort(int port);
+
+    // 停止监控端口
+    bool StopPort(int port);
+
+    // 读数据
+    bool ReadData(int port, const std::string &hex_data);
+
+    // 写数据
+    bool WriteData(int port, const std::string &hex_data);
+
+    // 释放监控
+    bool FreeMonitor();
+
+    // 获取最后错误
+    int GetLastError();
+
+    // 设置事件回调
+    void SetEventCallback(CommEventCallback callback) override;
+
+    // 获取错误信息
+    std::string GetErrorMessage(int error_code) override;
+
+    // 检查端口是否正在监控
+    bool IsPortMonitored(int port) override;
+
+    // 友元类,允许事件接收器访问私有方法
+    friend class ActiveXEventSink;
+};

+ 329 - 0
Authorization.cpp

@@ -0,0 +1,329 @@
+#include "Authorization.h"
+#include "Logger.h"
+#include "Utils.h"
+#include <windows.h>
+#include <winioctl.h>
+#include <iphlpapi.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+#include <vector>
+#include <ctime>
+#include "cryptopp/cryptlib.h"
+#include "cryptopp/sha.h"
+#include "cryptopp/hex.h"
+#include "cryptopp/base64.h"
+#include "cryptopp/files.h"
+#include "cryptopp/aes.h"
+#include "cryptopp/modes.h"
+
+#ifdef _WIN64// 是 64 位 Windows	
+#ifdef _DEBUG
+#pragma comment(lib, "cryptopp/x64/Debug/cryptlib.lib")
+#else
+#pragma comment(lib, "cryptopp/x64/Release/cryptlib.lib")
+#endif
+#else	
+#ifdef _DEBUG// 是 32 位 Windows
+#pragma comment(lib, "cryptopp/Win32/Debug/cryptlib.lib")
+#else
+#pragma comment(lib, "cryptopp/Win32/Release/cryptlib.lib")
+#endif
+#endif
+
+#pragma comment(lib, "Iphlpapi.lib")
+
+// 简单的加密密钥(实际应用中应该更安全)
+const std::string ENCRYPTION_KEY = "CommModifyServiceKey12345";
+
+bool Authorization::IsAuthorized()
+{
+    // 获取可执行文件目录并构建完整路径
+    std::string exeDir = Utils::GetExecutableDirectory();
+    std::string licensePath = exeDir + "\\license.dat";
+
+    // 检查授权文件是否存在
+    std::ifstream licenseFile(licensePath);
+    if (!licenseFile.is_open())
+    {
+        LOG_WARNING("License file not found");
+
+        // 生成授权码文件
+        std::string machineCode = GetMachineCode();
+        if (!GenerateAuthorizationCodeFile(machineCode))
+        {
+            LOG_ERROR("Failed to generate authorization code file");
+        }
+
+        return false;
+    }
+
+    // 读取授权文件内容
+    std::stringstream buffer;
+    buffer << licenseFile.rdbuf();
+    std::string encryptedData = buffer.str();
+    licenseFile.close();
+
+    // 验证授权文件
+    return VerifyLicenseFile(licensePath);
+}
+
+bool Authorization::GenerateAuthorizationCodeFile(const std::string &machineCode)
+{
+    try
+    {
+        // 获取可执行文件目录并构建完整路径
+        std::string exeDir = Utils::GetExecutableDirectory();
+        std::string filePath = exeDir + "\\auth_code.dat";
+
+        std::ofstream codeFile(filePath);
+        if (!codeFile.is_open())
+        {
+            LOG_ERROR("Failed to create authorization code file");
+            return false;
+        }
+
+        // 写入机器码到授权码文件
+        codeFile << machineCode;
+        codeFile.close();
+
+        LOG_INFO("Authorization code file generated successfully");
+        return true;
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error generating authorization code file: " + std::string(e.what()));
+        return false;
+    }
+}
+
+std::string Authorization::GetMachineCode()
+{
+    std::string cpuId = GetCPUID();
+    std::string diskSerial = GetHardDiskSerial();
+    std::string macAddress = GetMACAddress();
+
+    // 组合所有硬件信息
+    std::string hardwareInfo = cpuId + diskSerial + macAddress;
+
+    // 使用SHA256生成机器码
+    CryptoPP::SHA256 sha256;
+    std::string hash;
+    CryptoPP::StringSource ss(hardwareInfo, true,
+                              new CryptoPP::HashFilter(sha256,
+                                                       new CryptoPP::HexEncoder(
+                                                           new CryptoPP::StringSink(hash))));
+
+    return hash;
+}
+
+std::string Authorization::GetCPUID()
+{
+    int cpuInfo[4] = {0};
+    __cpuid(cpuInfo, 0);
+
+    std::stringstream ss;
+    ss << std::hex << std::uppercase << std::setfill('0');
+    for (int i = 0; i < 4; i++)
+    {
+        ss << std::setw(8) << cpuInfo[i];
+    }
+
+    return ss.str();
+}
+
+std::string Authorization::GetHardDiskSerial()
+{
+    HANDLE hDevice = CreateFileA("\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 NULL, OPEN_EXISTING, 0, NULL);
+
+    if (hDevice == INVALID_HANDLE_VALUE)
+    {
+        return "UNKNOWN";
+    }
+
+    STORAGE_PROPERTY_QUERY query = {};
+    query.PropertyId = StorageDeviceProperty;
+    query.QueryType = PropertyStandardQuery;
+
+    STORAGE_DESCRIPTOR_HEADER header = {};
+    DWORD bytesReturned = 0;
+
+    if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query),
+                         &header, sizeof(header), &bytesReturned, NULL))
+    {
+        CloseHandle(hDevice);
+        return "UNKNOWN";
+    }
+
+    std::vector<BYTE> buffer(header.Size);
+    STORAGE_DEVICE_DESCRIPTOR *deviceDescriptor = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR *>(buffer.data());
+
+    if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query),
+                         buffer.data(), header.Size, &bytesReturned, NULL))
+    {
+        CloseHandle(hDevice);
+        return "UNKNOWN";
+    }
+
+    CloseHandle(hDevice);
+
+    if (deviceDescriptor->SerialNumberOffset == 0)
+    {
+        return "UNKNOWN";
+    }
+
+    std::string serialNumber(reinterpret_cast<char *>(buffer.data() + deviceDescriptor->SerialNumberOffset));
+    return serialNumber;
+}
+
+std::string Authorization::GetMACAddress()
+{
+    PIP_ADAPTER_INFO adapterInfo;
+    ULONG bufferSize = sizeof(IP_ADAPTER_INFO);
+    adapterInfo = (IP_ADAPTER_INFO *)malloc(bufferSize);
+
+    if (GetAdaptersInfo(adapterInfo, &bufferSize) == ERROR_BUFFER_OVERFLOW)
+    {
+        free(adapterInfo);
+        adapterInfo = (IP_ADAPTER_INFO *)malloc(bufferSize);
+    }
+
+    if (GetAdaptersInfo(adapterInfo, &bufferSize) == NO_ERROR)
+    {
+        std::stringstream ss;
+        ss << std::hex << std::uppercase << std::setfill('0');
+
+        for (int i = 0; i < adapterInfo->AddressLength; i++)
+        {
+            if (i > 0)
+                ss << "-";
+            ss << std::setw(2) << static_cast<int>(adapterInfo->Address[i]);
+        }
+
+        free(adapterInfo);
+        return ss.str();
+    }
+
+    free(adapterInfo);
+    return "UNKNOWN";
+}
+
+bool Authorization::VerifyLicenseFile(const std::string &licenseFile)
+{
+    try
+    {
+        std::ifstream file(licenseFile, std::ios::binary);
+        if (!file.is_open())
+        {
+            return false;
+        }
+
+        std::stringstream buffer;
+        buffer << file.rdbuf();
+        std::string encryptedData = buffer.str();
+        file.close();
+
+        // 解密授权文件
+        std::string decryptedData = DecryptLicense(encryptedData);
+
+        // 检查解密后的数据是否包含当前机器码
+        std::string currentMachineCode = GetMachineCode();
+        if (decryptedData.find(currentMachineCode) == std::string::npos)
+        {
+            return false;
+        }
+
+        // 检查授权是否过期
+        // 查找Expiration行
+        size_t expirationPos = decryptedData.find("Expiration: ");
+        if (expirationPos == std::string::npos)
+        {
+            // 如果没有找到Expiration行,则认为授权永不过期
+            return true;
+        }
+
+        // 提取过期日期
+        size_t dateStart = expirationPos + 12; // "Expiration: "的长度
+        size_t dateEnd = decryptedData.find('\n', dateStart);
+        if (dateEnd == std::string::npos)
+        {
+            dateEnd = decryptedData.length();
+        }
+        std::string expirationDate = decryptedData.substr(dateStart, dateEnd - dateStart);
+
+        // 获取当前日期
+        time_t t = time(0);
+        struct tm now;
+        localtime_s(&now, &t);
+        char currentDateStr[11];
+        strftime(currentDateStr, sizeof(currentDateStr), "%Y-%m-%d", &now);
+        std::string currentDate(currentDateStr);
+
+        // 比较日期
+        if (currentDate >= expirationDate)
+        {
+            LOG_WARNING("License has expired");
+            return false;
+        }
+
+        return true;
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error verifying license file: " + std::string(e.what()));
+        return false;
+    }
+}
+
+std::string Authorization::DecryptLicense(const std::string &encryptedData)
+{
+    try
+    {
+        // 使用Base64解码
+        std::string decoded;
+        CryptoPP::StringSource ss(encryptedData, true,
+                                  new CryptoPP::Base64Decoder(
+                                      new CryptoPP::StringSink(decoded)));
+
+        // 使用AES解密
+        CryptoPP::AES::Decryption aesDecryption((CryptoPP::byte *)ENCRYPTION_KEY.data(), 16);
+        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (CryptoPP::byte *)ENCRYPTION_KEY.data());
+
+        std::string decrypted;
+        CryptoPP::StringSource ss2(decoded, true,
+                                   new CryptoPP::StreamTransformationFilter(cbcDecryption,
+                                                                            new CryptoPP::StringSink(decrypted)));
+
+        return decrypted;
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error decrypting license: " + std::string(e.what()));
+        return "";
+    }
+}
+
+std::string Authorization::EncryptData(const std::string &data)
+{
+    try
+    {
+        // 使用AES加密
+        CryptoPP::AES::Encryption aesEncryption((CryptoPP::byte *)ENCRYPTION_KEY.data(), 16);
+        CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (CryptoPP::byte *)ENCRYPTION_KEY.data());
+
+        std::string encrypted;
+        CryptoPP::StringSource ss(data, true,
+                                  new CryptoPP::StreamTransformationFilter(cbcEncryption,
+                                                                           new CryptoPP::Base64Encoder(
+                                                                               new CryptoPP::StringSink(encrypted))));
+
+        return encrypted;
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error encrypting data: " + std::string(e.what()));
+        return "";
+    }
+}

+ 69 - 0
Authorization.h

@@ -0,0 +1,69 @@
+#pragma once
+
+#include <string>
+
+/**
+ * @brief 授权管理类
+ */
+class Authorization
+{
+public:
+    /**
+     * @brief 检查授权文件是否有效
+     * @return true 如果授权有效,false 如果授权无效或不存在
+     */
+    static bool IsAuthorized();
+
+    /**
+     * @brief 生成授权码文件
+     * @param machineCode 机器码
+     * @return true 如果生成成功,false 如果失败
+     */
+    static bool GenerateAuthorizationCodeFile(const std::string &machineCode);
+
+    /**
+     * @brief 获取机器码
+     * @return 机器码字符串
+     */
+    static std::string GetMachineCode();
+
+private:
+    /**
+     * @brief 获取CPU ID
+     * @return CPU ID字符串
+     */
+    static std::string GetCPUID();
+
+    /**
+     * @brief 获取硬盘序列号
+     * @return 硬盘序列号字符串
+     */
+    static std::string GetHardDiskSerial();
+
+    /**
+     * @brief 获取MAC地址
+     * @return MAC地址字符串
+     */
+    static std::string GetMACAddress();
+
+    /**
+     * @brief 验证授权文件
+     * @param licenseFile 授权文件路径
+     * @return true 如果授权文件有效,false 如果无效
+     */
+    static bool VerifyLicenseFile(const std::string &licenseFile);
+
+    /**
+     * @brief 解密授权文件
+     * @param encryptedData 加密的数据
+     * @return 解密后的数据
+     */
+    static std::string DecryptLicense(const std::string &encryptedData);
+
+    /**
+     * @brief 加密数据
+     * @param data 要加密的数据
+     * @return 加密后的数据
+     */
+    static std::string EncryptData(const std::string &data);
+};

+ 185 - 0
CommModifyService.vcxproj

@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{12345678-1234-5678-9012-123456789012}</ProjectGuid>
+    <RootNamespace>CommModifyService</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <IncludePath>D:\Boost\boost_1_88_0;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Boost\boost_1_88_0\stage\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>D:\Boost\boost_1_88_0;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Boost\boost_1_88_0\stage\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <IncludePath>D:\Boost\boost_1_88_0;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Boost\boost_1_88_0\stage\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>D:\Boost\boost_1_88_0;$(IncludePath)</IncludePath>
+    <LibraryPath>D:\Boost\boost_1_88_0\stage\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="ActiveXWrapper.cpp" />
+    <ClCompile Include="Authorization.cpp" />
+    <ClCompile Include="DllWrapper.cpp" />
+    <ClCompile Include="Logger.cpp" />
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="Utils.cpp" />
+    <ClCompile Include="WebServer.cpp" />
+    <ClCompile Include="WebSocketHandler.cpp" />
+    <ClCompile Include="WebSocketSession.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ActiveXWrapper.h" />
+    <ClInclude Include="Authorization.h" />
+    <ClInclude Include="CommWrapperBase.h" />
+    <ClInclude Include="DllWrapper.h" />
+    <ClInclude Include="Logger.h" />
+    <ClInclude Include="Utils.h" />
+    <ClInclude Include="WebServer.h" />
+    <ClInclude Include="WebSocketHandler.h" />
+    <ClInclude Include="WebSocketSession.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 25 - 0
CommModifyService.vcxproj.filters

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="ActiveXWrapper.cpp" />
+    <ClCompile Include="Logger.cpp" />
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="WebServer.cpp" />
+    <ClCompile Include="WebSocketHandler.cpp" />
+    <ClCompile Include="WebSocketSession.cpp" />
+    <ClCompile Include="DllWrapper.cpp" />
+    <ClCompile Include="Utils.cpp" />
+    <ClCompile Include="Authorization.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ActiveXWrapper.h" />
+    <ClInclude Include="Logger.h" />
+    <ClInclude Include="WebServer.h" />
+    <ClInclude Include="WebSocketHandler.h" />
+    <ClInclude Include="WebSocketSession.h" />
+    <ClInclude Include="CommWrapperBase.h" />
+    <ClInclude Include="DllWrapper.h" />
+    <ClInclude Include="Utils.h" />
+    <ClInclude Include="Authorization.h" />
+  </ItemGroup>
+</Project>

+ 89 - 0
CommWrapperBase.h

@@ -0,0 +1,89 @@
+#pragma once
+
+#include <windows.h>
+#include <string>
+#include <vector>
+#include <functional>
+#include <map>
+#include <mutex>
+
+// 事件类型
+enum class CommEventType
+{
+    OP_NONE = 0,
+    OP_OPEN = 1,
+    OP_READ = 2,
+    OP_WRITE = 3,
+    OP_CLOSE = 4
+};
+
+// 事件数据结构
+struct CommEventData
+{
+    CommEventType event_type;
+    int port;
+    std::vector<BYTE> data;
+    DWORD data_size;
+};
+
+// 事件回调函数类型
+using CommEventCallback = std::function<void(const CommEventData &)>;
+
+// 通信包装器基类
+class CommWrapperBase
+{
+protected:
+    bool initialized_;
+    bool callback_initialized_;
+    std::map<int, bool> monitored_ports_;
+    std::mutex mutex_;
+    CommEventCallback event_callback_;
+
+public:
+    CommWrapperBase() : initialized_(false), callback_initialized_(false) {}    
+    virtual ~CommWrapperBase() = default;
+
+    // 初始化
+    virtual bool Initialize() = 0;
+
+    // 释放资源
+    virtual void Cleanup() = 0;
+
+    // 初始化监控
+    virtual bool InitMonitor(const std::string &key = "C09976511B62F0ADB759D87E6906D865") = 0;
+
+    // 监控端口
+    virtual bool MonitorPort(int port) = 0;
+
+    // 停止监控端口
+    virtual bool StopPort(int port) = 0;
+
+    // 读数据
+    virtual bool ReadData(int port, const std::string &hex_data) = 0;
+
+    // 写数据
+    virtual bool WriteData(int port, const std::string &hex_data) = 0;
+
+    // 释放监控
+    virtual bool FreeMonitor() = 0;
+
+    // 获取最后错误
+    virtual int GetLastError() = 0;
+
+    // 设置事件回调
+    virtual void SetEventCallback(CommEventCallback callback)
+    {
+        event_callback_ = callback;
+    }
+
+    // 获取错误信息
+    virtual std::string GetErrorMessage(int error_code) = 0;
+
+    // 检查端口是否正在监控
+    virtual bool IsPortMonitored(int port)
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        auto it = monitored_ports_.find(port);
+        return it != monitored_ports_.end() && it->second;
+    }
+};

+ 347 - 0
DllWrapper.cpp

@@ -0,0 +1,347 @@
+#include "DllWrapper.h"
+#include "Logger.h"
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+
+#define SDKDLL L"PCommMKit.dll"
+
+// 静态成员变量,用于在回调函数中访问类实例
+static DllWrapper *g_dll_wrapper_instance = nullptr;
+
+DllWrapper::DllWrapper()
+    : dll_handle_(nullptr), init_monitor_(nullptr),
+      start_monitor_(nullptr), stop_monitor_(nullptr),
+      set_write_data_(nullptr), set_read_data_(nullptr),
+      free_monitor_(nullptr), get_last_error_(nullptr)
+{
+    // 设置静态实例指针
+    g_dll_wrapper_instance = this;
+}
+
+DllWrapper::~DllWrapper()
+{
+    Cleanup();
+    g_dll_wrapper_instance = nullptr;
+}
+
+bool DllWrapper::Initialize()
+{
+    if (initialized_)
+    {
+        return true;
+    }
+
+    // 获取可执行文件所在目录
+    wchar_t buffer[MAX_PATH];
+    GetModuleFileName(NULL, buffer, MAX_PATH);
+    std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\");
+    std::wstring exe_path = std::wstring(buffer).substr(0, pos);
+
+    // 构建完整的DLL路径
+    std::wstring full_dll_path = exe_path + L"\\" + SDKDLL;
+
+    // 加载DLL
+    dll_handle_ = LoadLibrary(full_dll_path.c_str());
+    if (!dll_handle_)
+    {
+        LOG_ERROR("Failed to load DLL: " + std::to_string(GetLastError()));
+        return false;
+    }
+
+    // 获取DLL函数地址
+    init_monitor_ = (TInitMonitor)GetProcAddress(dll_handle_, "InitMonitor");
+    start_monitor_ = (TMonitor)GetProcAddress(dll_handle_, "Monitor");
+    stop_monitor_ = (TStop)GetProcAddress(dll_handle_, "Stop");
+    set_write_data_ = (TSetWrite_Data)GetProcAddress(dll_handle_, "SetWrite_Data");
+    set_read_data_ = (TSetRead_Data)GetProcAddress(dll_handle_, "SetRead_Data");
+    free_monitor_ = (TFreeMonitor)GetProcAddress(dll_handle_, "FreeMonitor");
+    get_last_error_ = (Tget_LastErrror)GetProcAddress(dll_handle_, "get_LastErrror");
+
+    if (!init_monitor_ || !start_monitor_ || !stop_monitor_ ||
+        !set_write_data_ || !set_read_data_ || !free_monitor_ || !get_last_error_)
+    {
+        LOG_ERROR("Failed to get function addresses from DLL");
+        FreeLibrary(dll_handle_);
+        dll_handle_ = nullptr;
+        return false;
+    }
+
+    initialized_ = true;
+    return true;
+}
+
+void DllWrapper::Cleanup()
+{
+    if (dll_handle_)
+    {
+        FreeLibrary(dll_handle_);
+        dll_handle_ = nullptr;
+    }
+
+    init_monitor_ = nullptr;
+    start_monitor_ = nullptr;
+    stop_monitor_ = nullptr;
+    set_write_data_ = nullptr;
+    set_read_data_ = nullptr;
+    free_monitor_ = nullptr;
+    get_last_error_ = nullptr;
+
+    initialized_ = false;
+    callback_initialized_ = false;
+}
+
+bool DllWrapper::InitMonitor(const std::string &key)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return false;
+    }
+
+    if (callback_initialized_)
+    {
+        return true;
+    }
+
+    // 将std::string转换为宽字符串
+    std::wstring wide_key(key.begin(), key.end());
+
+    // 调用DLL的InitMonitor函数
+    callback_initialized_ = init_monitor_(wide_key.c_str(), OnMonitorEx);
+
+    if (!callback_initialized_)
+    {
+        LOG_ERROR("Failed to initialize monitor: " + std::to_string(GetLastError()));
+        return false;
+    }
+
+    return true;
+}
+
+bool DllWrapper::MonitorPort(int port)
+{
+    if (!initialized_ || !callback_initialized_)
+    {
+        LOG_ERROR("DLL not initialized or monitor not initialized");
+        return false;
+    }
+
+    // 调用DLL的Monitor函数
+    bool result = start_monitor_(port);
+
+    if (result)
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        monitored_ports_[port] = true;
+        LOG_INFO("Started monitoring port: " + std::to_string(port));
+    }
+    else
+    {
+        LOG_ERROR("Failed to start monitoring port: " + std::to_string(port) + ", error: " + std::to_string(GetLastError()));
+    }
+
+    return result;
+}
+
+bool DllWrapper::StopPort(int port)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return false;
+    }
+
+    // 调用DLL的Stop函数
+    bool result = stop_monitor_(port);
+
+    if (result)
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        monitored_ports_.erase(port);
+        LOG_INFO("Stopped monitoring port: " + std::to_string(port));
+    }
+    else
+    {
+        LOG_ERROR("Failed to stop monitoring port: " + std::to_string(port) + ", error: " + std::to_string(GetLastError()));
+    }
+
+    return result;
+}
+
+bool DllWrapper::ReadData(int port, const std::string &hex_data)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return false;
+    }
+
+    // 将十六进制字符串转换为字节数组
+    std::vector<BYTE> bytes = Utils::ConvertHexStringToBytes(hex_data);
+
+    // 调用DLL的SetRead_Data函数
+    bool result = set_read_data_(port, reinterpret_cast<char *>(bytes.data()), static_cast<int>(bytes.size()));
+
+    if (!result)
+    {
+        LOG_ERROR("Failed to set read data for port: " + std::to_string(port) + ", error: " + std::to_string(GetLastError()));
+    }
+
+    return result;
+}
+
+bool DllWrapper::WriteData(int port, const std::string &hex_data)
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return false;
+    }
+
+    // 将十六进制字符串转换为字节数组
+    std::vector<BYTE> bytes = Utils::ConvertHexStringToBytes(hex_data);
+
+    // 调用DLL的SetWrite_Data函数
+    bool result = set_write_data_(port, reinterpret_cast<char *>(bytes.data()), static_cast<int>(bytes.size()));
+
+    if (!result)
+    {
+        LOG_ERROR("Failed to set write data for port: " + std::to_string(port) + ", error: " + std::to_string(GetLastError()));
+    }
+
+    return result;
+}
+
+bool DllWrapper::FreeMonitor()
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return false;
+    }
+
+    // 调用DLL的FreeMonitor函数
+    free_monitor_();
+
+    // 清空监控端口列表
+    std::lock_guard<std::mutex> lock(mutex_);
+    monitored_ports_.clear();
+
+    LOG_INFO("Freed monitor");
+    return true;
+}
+
+int DllWrapper::GetLastError()
+{
+    if (!initialized_)
+    {
+        LOG_ERROR("DLL not initialized");
+        return -1;
+    }
+
+    // 调用DLL的get_LastErrror函数
+    return get_last_error_();
+}
+
+void DllWrapper::SetEventCallback(CommEventCallback callback)
+{
+    // 调用基类的实现来设置回调
+    CommWrapperBase::SetEventCallback(callback);
+
+    // 设置DLL事件回调,直接使用通用事件数据调用通用回调
+    dll_event_callback_ = [this](const CommEventData &event_data)
+    {
+        // 直接使用通用事件数据调用通用回调
+        if (event_callback_)
+        {
+            event_callback_(event_data);
+        }
+    };
+}
+
+std::string DllWrapper::GetErrorMessage(int error_code)
+{
+    switch (error_code)
+    {
+    case -241:
+        return "安装驱动失败";
+    case -243:
+        return "其他错误";
+    case -244:
+        return "驱动文件";
+    case -255:
+        return "绑定串口失败";
+    case -254:
+        return "第一次启动安装,必须以管理员权限运行";
+    case -253:
+        return "启动驱动服务失败";
+    case -252:
+        return "请检查Key是否有效";
+    case -1:
+        return "无效操作";
+    case 0:
+        return "成功";
+    case 1:
+        return "串口打开失败";
+    case 2:
+        return "串口配置失败";
+    case 3:
+        return "串口读取失败";
+    case 4:
+        return "串口写入失败";
+    case 5:
+        return "串口关闭失败";
+    default:
+        return "未知错误";
+    }
+}
+
+bool DllWrapper::IsPortMonitored(int port)
+{
+    std::lock_guard<std::mutex> lock(mutex_);
+    auto it = monitored_ports_.find(port);
+    return (it != monitored_ports_.end() && it->second);
+}
+
+// 静态回调函数,用于接收DLL事件
+LONG CALLBACK DllWrapper::OnMonitorEx(int Sequence, double dTime, DWORD ComNumber, DWORD Irp, DWORD dwSize, char *lpData)
+{
+    // 检查是否有有效的类实例
+    if (!g_dll_wrapper_instance)
+    {
+        return 0;
+    }
+
+    // 检查是否有设置回调函数
+    if (!g_dll_wrapper_instance->event_callback_)
+    {
+        return 0;
+    }
+
+    try
+    {
+        // 创建CommEventData结构以传递给回调函数
+        CommEventData event_data;
+        event_data.event_type = static_cast<CommEventType>(Irp);
+        event_data.port = static_cast<int>(ComNumber);
+
+        if (lpData && dwSize > 0)
+        {
+            event_data.data.assign(reinterpret_cast<BYTE *>(lpData), reinterpret_cast<BYTE *>(lpData) + dwSize);
+        }
+        event_data.data_size = dwSize;
+
+        // 调用用户设置的回调函数
+        g_dll_wrapper_instance->event_callback_(event_data);
+
+        LOG_DEBUG("DLL event processed successfully");
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Error processing DLL event: " + std::string(e.what()));
+        return -1;
+    }
+
+    return 0;
+}

+ 84 - 0
DllWrapper.h

@@ -0,0 +1,84 @@
+#pragma once
+
+#include "CommWrapperBase.h"
+#include "Utils.h"
+#include <windows.h>
+#include <string>
+#include <vector>
+#include <functional>
+#include <map>
+#include <mutex>
+
+// DLL函数指针类型定义
+typedef LONG(CALLBACK* TOnData)(int Sequence, double dTime, DWORD ComNumber, DWORD Irp, DWORD dwSize, char* lpData);
+typedef BOOL(CALLBACK* TInitMonitor)(LPCWSTR cKey, TOnData lpDataProc);
+typedef BOOL(CALLBACK* TMonitor)(DWORD dwNumber);
+typedef BOOL(CALLBACK* TStop)(DWORD dwNumber);
+typedef BOOL(CALLBACK* TSetWrite_Data)(DWORD dwNumber, char* lpBuffer, int Len);
+typedef BOOL(CALLBACK* TSetRead_Data)(DWORD dwNumber, char* lpBuffer, int Len);
+typedef void(CALLBACK* TFreeMonitor)(void);
+typedef int(CALLBACK* Tget_LastErrror)(void);
+
+// 使用基类定义的事件类型、数据结构和回调函数类型
+// enum class DllEventType -> CommEventType
+// struct DllEventData -> CommEventData
+// using DllEventCallback -> CommEventCallback
+
+class DllWrapper : public CommWrapperBase
+{
+private:
+    HINSTANCE dll_handle_;
+    TInitMonitor init_monitor_;
+    TMonitor start_monitor_;
+    TStop stop_monitor_;
+    TSetWrite_Data set_write_data_;
+    TSetRead_Data set_read_data_;
+    TFreeMonitor free_monitor_;
+    Tget_LastErrror get_last_error_;
+    
+    // DLL事件回调
+    CommEventCallback dll_event_callback_;
+    
+    // DLL事件回调函数
+    static LONG CALLBACK OnMonitorEx(int Sequence, double dTime, DWORD ComNumber, DWORD Irp, DWORD dwSize, char* lpData);
+    
+public:
+    DllWrapper();
+    ~DllWrapper();
+    
+    // 初始化DLL
+    bool Initialize() override;
+    
+    // 释放资源
+    void Cleanup() override;
+    
+    // 初始化监控
+    bool InitMonitor(const std::string& key = "C09976511B62F0ADB759D87E6906D865") override;
+    
+    // 监控端口
+    bool MonitorPort(int port) override;
+    
+    // 停止监控端口
+    bool StopPort(int port) override;
+    
+    // 读数据
+    bool ReadData(int port, const std::string& hex_data) override;
+    
+    // 写数据
+    bool WriteData(int port, const std::string& hex_data) override;
+    
+    // 释放监控
+    bool FreeMonitor() override;
+    
+    // 获取最后错误
+    int GetLastError() override;
+    
+    // 设置事件回调
+    void SetEventCallback(CommEventCallback callback) override;
+    
+    // 获取错误信息
+    std::string GetErrorMessage(int error_code) override;
+    
+    // 检查端口是否正在监控
+    bool IsPortMonitored(int port) override;
+};

+ 89 - 0
Logger.cpp

@@ -0,0 +1,89 @@
+#define _CRT_SECURE_NO_WARNINGS
+#include "Logger.h"
+#include <iostream>
+#include <ctime>
+#include <windows.h>
+
+std::unique_ptr<Logger> Logger::instance_ = nullptr;
+std::mutex Logger::mutex_;
+
+Logger::Logger(const std::string& log_file_path) : log_file_path_(log_file_path) {
+    // 获取可执行文件所在目录
+    char buffer[MAX_PATH];
+    GetModuleFileNameA(NULL, buffer, MAX_PATH);
+    std::string::size_type pos = std::string(buffer).find_last_of("\\");
+    std::string exe_path = std::string(buffer).substr(0, pos);
+    
+    // 构建完整的日志文件路径
+    std::string full_log_path = exe_path + "\\" + log_file_path;
+    
+    log_file_.open(full_log_path, std::ios::app);
+    if (!log_file_.is_open()) {
+        std::cerr << "Failed to open log file: " << full_log_path << std::endl;
+    }
+}
+
+Logger::~Logger() {
+    if (log_file_.is_open()) {
+        log_file_.close();
+    }
+}
+
+Logger* Logger::GetInstance(const std::string& log_file_path) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    if (instance_ == nullptr) {
+        std::string path = log_file_path.empty() ? "CommModifyService.log" : log_file_path;
+        instance_ = std::unique_ptr<Logger>(new Logger(path));
+    }
+    return instance_.get();
+}
+
+void Logger::Log(LogLevel level, const std::string& message) {
+    return;
+    std::lock_guard<std::mutex> lock(file_mutex_);
+    
+    // 获取当前时间
+    auto now = std::time(nullptr);
+    auto tm = *std::localtime(&now);
+    
+    // 格式化时间字符串
+    char time_buffer[100];
+    std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", &tm);
+    
+    // 获取日志级别字符串
+    std::string level_str;
+    switch (level) {
+        case LogLevel::LOG_LEVEL_INFO: level_str = "INFO"; break;
+        case LogLevel::LOG_LEVEL_WARNING: level_str = "WARNING"; break;
+        case LogLevel::LOG_LEVEL_ERROR: level_str = "ERROR"; break;
+        case LogLevel::LOG_LEVEL_DEBUG: level_str = "DEBUG"; break;
+    }
+    
+    // 构建日志消息
+    std::string log_message = "[" + std::string(time_buffer) + "] [" + level_str + "] " + message;
+    
+    // 写入文件
+    if (log_file_.is_open()) {
+        log_file_ << log_message << std::endl;
+        log_file_.flush();
+    }
+    
+    // 输出到控制台
+    std::cout << log_message << std::endl;
+}
+
+void Logger::LogInfo(const std::string& message) {
+    Log(LogLevel::LOG_LEVEL_INFO, message);
+}
+
+void Logger::LogWarning(const std::string& message) {
+    Log(LogLevel::LOG_LEVEL_WARNING, message);
+}
+
+void Logger::LogError(const std::string& message) {
+    Log(LogLevel::LOG_LEVEL_ERROR, message);
+}
+
+void Logger::LogDebug(const std::string& message) {
+    Log(LogLevel::LOG_LEVEL_DEBUG, message);
+}

+ 46 - 0
Logger.h

@@ -0,0 +1,46 @@
+#pragma once
+
+#include <string>
+#include <fstream>
+#include <mutex>
+#include <memory>
+
+enum class LogLevel {
+    LOG_LEVEL_INFO,
+    LOG_LEVEL_WARNING,
+    LOG_LEVEL_ERROR,
+    LOG_LEVEL_DEBUG
+};
+
+class Logger {
+private:
+    static std::unique_ptr<Logger> instance_;
+    static std::mutex mutex_;
+    
+    std::ofstream log_file_;
+    std::mutex file_mutex_;
+    std::string log_file_path_;
+    
+    Logger(const std::string& log_file_path);
+    
+public:
+    static Logger* GetInstance(const std::string& log_file_path = "");
+    
+    void Log(LogLevel level, const std::string& message);
+    void LogInfo(const std::string& message);
+    void LogWarning(const std::string& message);
+    void LogError(const std::string& message);
+    void LogDebug(const std::string& message);
+    
+    ~Logger();
+    
+    // 禁用拷贝构造和赋值
+    Logger(const Logger&) = delete;
+    Logger& operator=(const Logger&) = delete;
+};
+
+// 便利宏
+#define LOG_INFO(msg) Logger::GetInstance()->LogInfo(msg)
+#define LOG_WARNING(msg) Logger::GetInstance()->LogWarning(msg)
+#define LOG_ERROR(msg) Logger::GetInstance()->LogError(msg)
+#define LOG_DEBUG(msg) Logger::GetInstance()->LogDebug(msg)

+ 54 - 0
Utils.cpp

@@ -0,0 +1,54 @@
+#include "Utils.h"
+#include "CommWrapperBase.h"
+#include <algorithm>
+#include <sstream>
+#include <iomanip>
+
+namespace Utils
+{
+    // 字符串转字节数组
+    std::vector<BYTE> ConvertHexStringToBytes(const std::string &hex_string)
+    {
+        std::string clean_hex = hex_string;
+        // 移除空格
+        clean_hex.erase(std::remove(clean_hex.begin(), clean_hex.end(), ' '), clean_hex.end());
+
+        // 如果长度为奇数,补0
+        if (clean_hex.length() % 2 != 0)
+        {
+            clean_hex += '0';
+        }
+
+        std::vector<BYTE> bytes;
+        for (size_t i = 0; i < clean_hex.length(); i += 2)
+        {
+            std::string byte_str = clean_hex.substr(i, 2);
+            BYTE byte_val = static_cast<BYTE>(std::stoul(byte_str, nullptr, 16));
+            bytes.push_back(byte_val);
+        }
+
+        return bytes;
+    }
+
+    std::string Utils::ConvertBytesToHexString(const std::vector<BYTE> &bytes)
+    {
+        std::stringstream ss;
+        for (size_t i = 0; i < bytes.size(); i++)
+        {
+            if (i > 0)
+                ss << " ";
+            ss << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<int>(bytes[i]);
+        }
+        return ss.str();
+    }
+    
+    // 获取当前可执行文件目录
+    std::string Utils::GetExecutableDirectory()
+    {
+        char buffer[MAX_PATH];
+        GetModuleFileNameA(NULL, buffer, MAX_PATH);
+        std::string::size_type pos = std::string(buffer).find_last_of("\\");
+        return std::string(buffer).substr(0, pos);
+    }
+
+} // namespace Utils

+ 16 - 0
Utils.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <windows.h>
+#include <string>
+#include <vector>
+
+// 工具函数声明
+namespace Utils
+{
+    // 字符串转字节数组
+    std::vector<BYTE> ConvertHexStringToBytes(const std::string &hex_string);
+    std::string ConvertBytesToHexString(const std::vector<BYTE> &bytes);
+    
+    // 获取当前可执行文件目录
+    std::string GetExecutableDirectory();
+}

+ 343 - 0
WebServer.cpp

@@ -0,0 +1,343 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <shlwapi.h>
+
+#include "WebServer.h"
+#include "WebSocketSession.h"
+#include "Logger.h"
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+WebServer::WebServer(int port, bool use_dll) : port_(port), acceptor_(ioc_), running_(false)
+{
+    websocket_handler_ = std::make_shared<WebSocketHandler>(use_dll);
+}
+
+WebServer::~WebServer()
+{
+    Stop();
+}
+
+bool WebServer::Start()
+{
+    try
+    {
+        // 初始化WebSocketHandler(包括ActiveX控件)
+        if (!websocket_handler_->Initialize())
+        {
+            LOG_ERROR("Failed to initialize WebSocketHandler");
+            return false;
+        }
+
+        // 设置端点
+        tcp::endpoint endpoint(net::ip::make_address("0.0.0.0"), port_);
+
+        // 打开acceptor
+        acceptor_.open(endpoint.protocol());
+        acceptor_.set_option(net::socket_base::reuse_address(true));
+        acceptor_.bind(endpoint);
+        acceptor_.listen(net::socket_base::max_listen_connections);
+
+        running_ = true;
+
+        // 开始接受连接
+        DoAccept();
+
+        // 在单独线程中运行io_context
+        server_thread_ = std::thread([this]()
+                                     { ioc_.run(); });
+
+        LOG_INFO("WebServer started on port " + std::to_string(port_));
+        return true;
+    }
+    catch (const std::exception &e)
+    {
+        LOG_ERROR("Failed to start WebServer: " + std::string(e.what()));
+        return false;
+    }
+}
+
+void WebServer::Stop()
+{
+    if (running_)
+    {
+        running_ = false;
+
+        // 停止acceptor
+        beast::error_code ec;
+        acceptor_.close(ec);
+
+        // 停止io_context
+        ioc_.stop();
+
+        // 等待线程结束
+        if (server_thread_.joinable())
+        {
+            server_thread_.join();
+        }
+
+        // 清理WebSocketHandler
+        if (websocket_handler_)
+        {
+            websocket_handler_->Cleanup();
+        }
+
+        LOG_INFO("WebServer stopped");
+    }
+}
+
+void WebServer::DoAccept()
+{
+    acceptor_.async_accept(
+        net::make_strand(ioc_),
+        [self = shared_from_this()](beast::error_code ec, tcp::socket socket)
+        {
+            self->OnAccept(ec, std::move(socket));
+        });
+}
+
+void WebServer::OnAccept(beast::error_code ec, tcp::socket socket)
+{
+    if (ec)
+    {
+        if (ec != net::error::operation_aborted)
+        {
+            LOG_ERROR("Accept error: " + ec.message());
+        }
+        return;
+    }
+
+    // 创建HTTP会话来处理连接
+    std::make_shared<HttpSession>(std::move(socket), shared_from_this())->run();
+
+    // 继续接受新连接
+    if (running_)
+    {
+        DoAccept();
+    }
+}
+
+std::string WebServer::GetStaticFileContent(const std::string &path)
+{
+    // 获取可执行文件所在目录
+    char buffer[MAX_PATH];
+    GetModuleFileNameA(NULL, buffer, MAX_PATH);
+    std::string::size_type pos = std::string(buffer).find_last_of("\\");
+    std::string exe_path = std::string(buffer).substr(0, pos);
+
+    std::string file_path;
+
+    if (path == "/" || path == "/index.html")
+    {
+        file_path = exe_path + "\\web\\index.html";
+    }
+    else if (path == "/style.css")
+    {
+        file_path = exe_path + "\\web\\style.css";
+    }
+    else if (path == "/script.js")
+    {
+        file_path = exe_path + "\\web\\script.js";
+    }
+    else
+    {
+        return "";
+    }
+
+    // 以二进制模式打开文件,避免编码问题
+    std::ifstream file(file_path, std::ios::binary);
+    if (!file.is_open())
+    {
+        LOG_ERROR("Failed to open file: " + file_path);
+        return "";
+    }
+
+    // 读取文件内容
+    std::stringstream content_buffer;
+    content_buffer << file.rdbuf();
+    return content_buffer.str();
+}
+
+std::string WebServer::GetMimeType(const std::string &path)
+{
+    if (path == "/" || path == "/index.html" || path.ends_with(".html"))
+    {
+        return "text/html; charset=utf-8";
+    }
+    if (path.ends_with(".css"))
+    {
+        return "text/css; charset=utf-8";
+    }
+    if (path.ends_with(".js"))
+    {
+        return "application/javascript; charset=utf-8";
+    }
+    if (path.ends_with(".json"))
+    {
+        return "application/json; charset=utf-8";
+    }
+    return "text/plain; charset=utf-8";
+}
+
+void WebServer::HandleHttpRequest(http::request<http::dynamic_body> &&req,
+                                  std::function<void(http::response<http::dynamic_body>)> send)
+{
+    // 处理普通HTTP请求
+    auto const bad_request = [&req](beast::string_view why)
+    {
+        http::response<http::dynamic_body> res{http::status::bad_request, req.version()};
+        res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+        res.set(http::field::content_type, "text/html; charset=utf-8");
+        res.keep_alive(req.keep_alive());
+        beast::ostream(res.body()) << "Bad request: " << why;
+        res.prepare_payload();
+        return res;
+    };
+
+    auto const not_found = [&req](beast::string_view target)
+    {
+        http::response<http::dynamic_body> res{http::status::not_found, req.version()};
+        res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+        res.set(http::field::content_type, "text/html; charset=utf-8");
+        res.keep_alive(req.keep_alive());
+        beast::ostream(res.body()) << "The resource '" << target << "' was not found.";
+        res.prepare_payload();
+        return res;
+    };
+
+    // 确保我们可以处理这个方法
+    if (req.method() != http::verb::get && req.method() != http::verb::head)
+    {
+        return send(bad_request("Unknown HTTP-method"));
+    }
+
+    // 请求路径不能包含".."
+    if (req.target().empty() || req.target()[0] != '/' || req.target().find("..") != beast::string_view::npos)
+    {
+        return send(bad_request("Illegal request-target"));
+    }
+
+    // 获取文件内容
+    std::string path = std::string(req.target());
+    std::string content = GetStaticFileContent(path);
+
+    if (content.empty())
+    {
+        return send(not_found(req.target()));
+    }
+
+    // 创建响应
+    http::response<http::dynamic_body> res{http::status::ok, req.version()};
+    res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+    res.set(http::field::content_type, GetMimeType(path));
+    res.keep_alive(req.keep_alive());
+
+    // 设置响应体
+    beast::ostream(res.body()) << content;
+    res.prepare_payload();
+
+    return send(std::move(res));
+}
+
+// HttpSession实现
+HttpSession::HttpSession(tcp::socket &&socket, std::shared_ptr<WebServer> server)
+    : stream_(std::move(socket)), server_(server)
+{
+}
+
+void HttpSession::run()
+{
+    net::dispatch(stream_.get_executor(),
+                  beast::bind_front_handler(&HttpSession::do_read, shared_from_this()));
+}
+
+void HttpSession::do_read()
+{
+    req_ = {};
+
+    stream_.expires_after(std::chrono::seconds(30));
+
+    http::async_read(stream_, buffer_, req_,
+                     beast::bind_front_handler(&HttpSession::on_read, shared_from_this()));
+}
+
+void HttpSession::on_read(beast::error_code ec, std::size_t bytes_transferred)
+{
+    boost::ignore_unused(bytes_transferred);
+
+    if (ec == http::error::end_of_stream)
+    {
+        return do_close();
+    }
+
+    if (ec)
+    {
+        LOG_ERROR("HTTP read error: " + ec.message());
+        return;
+    }
+
+    // 检查是否是WebSocket升级请求
+    if (websocket::is_upgrade(req_))
+    {
+        // 释放socket并传递给WebSocket会话
+        tcp::socket socket = stream_.release_socket();
+
+        // 创建WebSocket会话
+        auto ws_session = std::make_shared<WebSocketSession>(std::move(socket), std::move(req_));
+
+        // 设置WebSocketHandler引用
+        ws_session->set_websocket_handler(server_->GetWebSocketHandler());
+
+        // 设置消息处理回调
+        ws_session->set_message_handler([server = server_](std::shared_ptr<WebSocketSession> session, const std::string &message)
+                                        { server->GetWebSocketHandler()->HandleMessage(session, message); });
+
+        // 添加到WebSocket处理器
+        server_->GetWebSocketHandler()->AddClient(ws_session);
+
+        ws_session->run();
+        return;
+    }
+
+    // 处理普通HTTP请求
+    server_->HandleHttpRequest(std::move(req_),
+                               [self = shared_from_this()](http::response<http::dynamic_body> res)
+                               {
+                                   // 发送响应
+                                   auto sp = std::make_shared<http::response<http::dynamic_body>>(std::move(res));
+
+                                   http::async_write(self->stream_, *sp,
+                                                     [self, sp](beast::error_code ec, std::size_t bytes_transferred)
+                                                     {
+                                                         self->on_write(sp->need_eof(), ec, bytes_transferred);
+                                                     });
+                               });
+}
+
+void HttpSession::on_write(bool close, beast::error_code ec, std::size_t bytes_transferred)
+{
+    boost::ignore_unused(bytes_transferred);
+
+    if (ec)
+    {
+        LOG_ERROR("HTTP write error: " + ec.message());
+        return;
+    }
+
+    if (close)
+    {
+        return do_close();
+    }
+
+    // 读取另一个请求
+    do_read();
+}
+
+void HttpSession::do_close()
+{
+    beast::error_code ec;
+    stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
+}

+ 87 - 0
WebServer.h

@@ -0,0 +1,87 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/strand.hpp>
+#include <memory>
+#include <string>
+#include <thread>
+#include <atomic>
+#include "WebSocketHandler.h"
+
+namespace beast = boost::beast;
+namespace http = beast::http;
+namespace websocket = beast::websocket;
+namespace net = boost::asio;
+using tcp = boost::asio::ip::tcp;
+
+// 前向声明
+class WebSocketSession;
+
+class WebServer : public std::enable_shared_from_this<WebServer> {
+private:
+    net::io_context ioc_;
+    tcp::acceptor acceptor_;
+    std::shared_ptr<WebSocketHandler> websocket_handler_;
+    std::thread server_thread_;
+    std::atomic<bool> running_;
+    int port_;
+    
+    // 获取静态文件内容
+    std::string GetStaticFileContent(const std::string& path);
+    
+    // 获取MIME类型
+    std::string GetMimeType(const std::string& path);
+    
+    // 接受连接
+    void DoAccept();
+    
+    // 处理连接
+    void OnAccept(beast::error_code ec, tcp::socket socket);
+    
+public:
+    WebServer(int port = 8080, bool use_dll = true);
+    ~WebServer();
+    
+    // 启动服务器
+    bool Start();
+    
+    // 停止服务器
+    void Stop();
+    
+    // 检查是否运行中
+    bool IsRunning() const { return running_; }
+    
+    // 获取WebSocketHandler
+    std::shared_ptr<WebSocketHandler> GetWebSocketHandler() { return websocket_handler_; }
+    
+    // HTTP请求处理
+    void HandleHttpRequest(http::request<http::dynamic_body>&& req, 
+                          std::function<void(http::response<http::dynamic_body>)> send);
+};
+
+// HTTP会话类
+class HttpSession : public std::enable_shared_from_this<HttpSession> {
+    beast::tcp_stream stream_;
+    beast::flat_buffer buffer_;
+    http::request<http::dynamic_body> req_;
+    std::shared_ptr<WebServer> server_;
+    
+public:
+    explicit HttpSession(tcp::socket&& socket, std::shared_ptr<WebServer> server);
+    
+    void run();
+    
+private:
+    void do_read();
+    void on_read(beast::error_code ec, std::size_t bytes_transferred);
+    void on_write(bool close, beast::error_code ec, std::size_t bytes_transferred);
+    void do_close();
+};

+ 368 - 0
WebSocketHandler.cpp

@@ -0,0 +1,368 @@
+#include "WebSocketHandler.h"
+#include "WebSocketSession.h"
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include "Logger.h"
+#include <algorithm>
+#include <chrono>
+
+WebSocketHandler::WebSocketHandler(bool use_dll) : use_dll_(use_dll), timeout_thread_running_(false)
+{
+    if (use_dll_)
+    {
+        comm_wrapper_ = std::make_shared<DllWrapper>();
+    }
+    else
+    {
+        comm_wrapper_ = std::make_shared<ActiveXWrapper>();
+    }
+}
+
+WebSocketHandler::~WebSocketHandler()
+{
+    Cleanup();
+}
+
+bool WebSocketHandler::Initialize()
+{
+    if (!comm_wrapper_->Initialize())
+    {
+        LOG_ERROR("Failed to initialize communication wrapper");
+        return false;
+    }
+
+    // 设置事件回调
+    comm_wrapper_->SetEventCallback([this](const CommEventData &event_data)
+                                    { OnCommEvent(event_data); });
+
+    // 初始化监控
+    if (!comm_wrapper_->InitMonitor())
+    {
+        LOG_ERROR("Failed to initialize communication monitor");
+        return false;
+    }
+
+    // 启动超时检测线程
+    //timeout_thread_running_ = true;
+    //timeout_check_thread_ = std::thread(&WebSocketHandler::TimeoutCheckThread, this);
+
+    LOG_INFO("WebSocketHandler initialized successfully");
+    return true;
+}
+
+void WebSocketHandler::AddClient(std::shared_ptr<WebSocketSession> session)
+{
+    std::lock_guard<std::mutex> lock(clients_mutex_);
+    connected_clients_.insert(session);
+    LOG_INFO("Client connected, total clients: " + std::to_string(connected_clients_.size()));
+}
+
+void WebSocketHandler::RemoveClient(std::shared_ptr<WebSocketSession> session)
+{
+    std::lock_guard<std::mutex> lock(clients_mutex_);
+    // 从连接客户端集合中移除
+    connected_clients_.erase(session);
+
+    // 关闭WebSocket连接
+    session->close();
+
+    LOG_INFO("Client disconnected, total clients: " + std::to_string(connected_clients_.size()));
+}
+
+void WebSocketHandler::HandleMessage(std::shared_ptr<WebSocketSession> session, const std::string &message)
+{
+    rapidjson::Document doc;
+    if (doc.Parse(message.c_str()).HasParseError())
+    {
+        LOG_ERROR("Failed to parse JSON message: " + message);
+        return;
+    }
+
+    if (!doc.HasMember("cmd") || !doc["cmd"].IsString())
+    {
+        LOG_ERROR("Invalid message format: missing 'cmd' field");
+        return;
+    }
+
+    std::string cmd = doc["cmd"].GetString();
+
+    if (cmd == "InitMonitor")
+    {
+        if (!doc.HasMember("port") || !doc["port"].IsInt())
+        {
+            LOG_ERROR("Invalid InitMonitor message: missing 'port' field");
+            return;
+        }
+        int port = doc["port"].GetInt();
+        HandleInitMonitor(session, port);
+    }
+    else if (cmd == "StopPort")
+    {
+        if (!doc.HasMember("port") || !doc["port"].IsInt())
+        {
+            LOG_ERROR("Invalid StopPort message: missing 'port' field");
+            return;
+        }
+        int port = doc["port"].GetInt();
+        HandleStopPort(session, port);
+    }
+    else if (cmd == "ReadData")
+    {
+        if (!doc.HasMember("port") || !doc["port"].IsInt() ||
+            !doc.HasMember("data") || !doc["data"].IsString())
+        {
+            LOG_ERROR("Invalid ReadData message: missing required fields");
+            return;
+        }
+        int port = doc["port"].GetInt();
+        std::string data = doc["data"].GetString();
+        HandleReadData(session, port, data);
+    }
+    else if (cmd == "WriteData")
+    {
+        if (!doc.HasMember("port") || !doc["port"].IsInt() ||
+            !doc.HasMember("data") || !doc["data"].IsString())
+        {
+            LOG_ERROR("Invalid WriteData message: missing required fields");
+            return;
+        }
+        int port = doc["port"].GetInt();
+        std::string data = doc["data"].GetString();
+        HandleWriteData(session, port, data);
+    }
+    else
+    {
+        LOG_ERROR("Unknown command: " + cmd);
+    }
+}
+
+void WebSocketHandler::HandleInitMonitor(std::shared_ptr<WebSocketSession> session, int port)
+{
+    bool result = comm_wrapper_->MonitorPort(port);
+    SendResponse(session, "InitMonitor", result, port);
+
+    if (!result)
+    {
+        int error_code = comm_wrapper_->GetLastError();
+        std::string error_msg = comm_wrapper_->GetErrorMessage(error_code);
+        LOG_ERROR("InitMonitor failed for port " + std::to_string(port) + ": " + error_msg);
+    }
+}
+
+void WebSocketHandler::HandleStopPort(std::shared_ptr<WebSocketSession> session, int port)
+{
+    bool result = comm_wrapper_->StopPort(port);
+    SendResponse(session, "StopPort", result, port);
+}
+
+void WebSocketHandler::HandleReadData(std::shared_ptr<WebSocketSession> session, int port, const std::string &data)
+{
+    // 移除端口活动时间
+    RemovePortActivity(port);
+    
+    bool result = comm_wrapper_->ReadData(port, data);
+    SendResponse(session, "ReadData", result, port);
+}
+
+void WebSocketHandler::HandleWriteData(std::shared_ptr<WebSocketSession> session, int port, const std::string &data)
+{
+	// 移除端口活动时间
+	RemovePortActivity(port);
+    
+    bool result = comm_wrapper_->WriteData(port, data);
+    SendResponse(session, "WriteData", result, port);
+}
+
+void WebSocketHandler::SendResponse(std::shared_ptr<WebSocketSession> session, const std::string &cmd, bool result, int port)
+{
+    rapidjson::StringBuffer buffer;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+
+    writer.StartObject();
+    writer.Key("cmd");
+    writer.String(cmd.c_str());
+    writer.Key("result");
+    writer.Bool(result);
+    if (port > 0)
+    {
+        writer.Key("port");
+        writer.Int(port);
+    }
+    writer.EndObject();
+
+    std::string response = buffer.GetString();
+    auto message = std::make_shared<std::string>(response);
+    session->safe_send(message);
+
+    LOG_DEBUG("Sent response: " + response);
+}
+
+void WebSocketHandler::BroadcastEvent(const std::string &cmd, int port, const std::string &data)
+{
+    rapidjson::StringBuffer buffer;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+
+    writer.StartObject();
+    writer.Key("cmd");
+    writer.String(cmd.c_str());
+    writer.Key("port");
+    writer.Int(port);
+    if (!data.empty())
+    {
+        writer.Key("data");
+        writer.String(data.c_str());
+    }
+    writer.EndObject();
+
+    std::string event_message = buffer.GetString();
+    auto message = std::make_shared<std::string>(event_message);
+
+    std::lock_guard<std::mutex> lock(clients_mutex_);
+    for (auto &client : connected_clients_)
+    {
+        client->safe_send(message);
+    }
+
+    LOG_DEBUG(std::to_string(connected_clients_.size()) + " Broadcasted event: " + event_message);
+}
+
+void WebSocketHandler::Cleanup()
+{
+    // 停止超时检测线程
+    if (timeout_thread_running_)
+    {
+        timeout_thread_running_ = false;
+        if (timeout_check_thread_.joinable())
+        {
+            timeout_check_thread_.join();
+        }
+    }
+
+    if (comm_wrapper_)
+    {
+        comm_wrapper_->Cleanup();
+    }
+
+    std::lock_guard<std::mutex> lock(clients_mutex_);
+    connected_clients_.clear();
+
+    LOG_INFO("WebSocketHandler cleaned up");
+}
+
+void WebSocketHandler::OnCommEvent(const CommEventData &event_data)
+{
+    std::string cmd;
+    std::string data_str;
+
+    switch (event_data.event_type)
+    {
+    case CommEventType::OP_OPEN:
+        cmd = "OP_OPEN";
+        break;
+    case CommEventType::OP_CLOSE:
+        cmd = "OP_CLOSE";
+        break;
+    case CommEventType::OP_READ:
+        cmd = "OP_READ";
+        // 将字节数组转换为十六进制字符串
+        for (size_t i = 0; i < event_data.data.size(); i++)
+        {
+            if (i > 0)
+                data_str += " ";
+            char hex[3];
+            sprintf_s(hex, "%02X", event_data.data[i]);
+            data_str += hex;
+        }
+        break;
+    case CommEventType::OP_WRITE:
+        cmd = "OP_WRITE";
+        // 将字节数组转换为十六进制字符串
+        for (size_t i = 0; i < event_data.data.size(); i++)
+        {
+            if (i > 0)
+                data_str += " ";
+            char hex[3];
+            sprintf_s(hex, "%02X", event_data.data[i]);
+            data_str += hex;
+        }
+        break;
+    default:
+        return; // 忽略未知事件
+	}
+
+	BroadcastEvent(cmd, event_data.port, data_str);
+
+	switch (event_data.event_type)
+	{
+	case CommEventType::OP_READ:
+	case CommEventType::OP_WRITE:
+		// 更新端口活动时间
+		UpdatePortActivity(event_data.port);
+		break;
+	default:
+        break;
+	}
+}
+
+void WebSocketHandler::UpdatePortActivity(int port)
+{
+    std::lock_guard<std::mutex> lock(activity_mutex_);
+    last_activity_time_[port] = std::chrono::steady_clock::now();
+}
+
+void WebSocketHandler::RemovePortActivity(int port)
+{
+	std::lock_guard<std::mutex> lock(activity_mutex_);
+    last_activity_time_.erase(port);
+}
+
+void WebSocketHandler::TimeoutCheckThread()
+{
+    //while (timeout_thread_running_)
+    //{
+    //    // 等待一段时间再检查
+    //    std::this_thread::sleep_for(std::chrono::seconds(5));
+
+    //    if (!timeout_thread_running_)
+    //        break;
+
+    //    // 获取当前时间
+    //    auto now = std::chrono::steady_clock::now();
+    //    
+    //    // 创建一个副本以避免在遍历时锁定
+    //    std::map<int, std::chrono::steady_clock::time_point> activity_copy;
+    //    {
+    //        std::lock_guard<std::mutex> lock(activity_mutex_);
+    //        activity_copy = last_activity_time_;
+    //    }
+
+    //    // 检查每个端口的活动时间
+    //    for (const auto &entry : activity_copy)
+    //    {
+    //        int port = entry.first;
+    //        auto last_activity = entry.second;
+    //        
+    //        // 计算自上次活动以来的时间
+    //        auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_activity).count();
+    //        
+    //        // 如果超过30秒没有活动,则停止监听该端口
+    //        if (duration >= TIMEOUT_SECONDS)
+    //        {
+    //            LOG_INFO("Port " + std::to_string(port) + " timeout, stopping monitoring");
+    //            
+    //            // 停止监听端口
+    //            if (comm_wrapper_)
+    //            {
+    //                comm_wrapper_->StopPort(port);
+    //            }
+    //            
+    //            // 从活动时间映射中移除该端口
+    //            {
+    //                std::lock_guard<std::mutex> lock(activity_mutex_);
+    //                last_activity_time_.erase(port);
+    //            }
+    //        }
+    //    }
+    //}
+}

+ 70 - 0
WebSocketHandler.h

@@ -0,0 +1,70 @@
+#pragma once
+
+#include "CommWrapperBase.h"
+#include "ActiveXWrapper.h"
+#include "DllWrapper.h"
+#include "WebSocketSession.h"
+#include <memory>
+#include <set>
+#include <mutex>
+#include <map>
+#include <chrono>
+#include <thread>
+#include <atomic>
+
+
+class WebSocketHandler {
+private:
+    std::shared_ptr<CommWrapperBase> comm_wrapper_;
+    std::set<std::shared_ptr<WebSocketSession>> connected_clients_;
+    std::mutex clients_mutex_;
+    bool use_dll_;
+    
+    // 超时检测相关
+    std::map<int, std::chrono::steady_clock::time_point> last_activity_time_;
+    std::mutex activity_mutex_;
+    std::atomic<bool> timeout_thread_running_;
+    std::thread timeout_check_thread_;
+    const int TIMEOUT_SECONDS = 30;
+    
+    // 超时检测线程函数
+    void TimeoutCheckThread();
+    
+public:
+    WebSocketHandler(bool use_dll = true);
+    ~WebSocketHandler();
+    
+    // 初始化
+    bool Initialize();
+    
+    // 清理资源
+    void Cleanup();
+    
+    // 添加/移除客户端
+    void AddClient(std::shared_ptr<WebSocketSession> session);
+    void RemoveClient(std::shared_ptr<WebSocketSession> session);
+    
+    // 处理WebSocket消息
+    void HandleMessage(std::shared_ptr<WebSocketSession> session, const std::string& message);
+    
+    // 处理具体的命令
+    void HandleInitMonitor(std::shared_ptr<WebSocketSession> session, int port);
+    void HandleStopPort(std::shared_ptr<WebSocketSession> session, int port);
+    void HandleReadData(std::shared_ptr<WebSocketSession> session, int port, const std::string& data);
+    void HandleWriteData(std::shared_ptr<WebSocketSession> session, int port, const std::string& data);
+    
+    // 发送响应
+    void SendResponse(std::shared_ptr<WebSocketSession> session, const std::string& cmd, bool result, int port = 0);
+    
+    // 广播事件
+    void BroadcastEvent(const std::string& cmd, int port, const std::string& data = "");
+    
+    // 处理通信事件
+    void OnCommEvent(const CommEventData& event_data);
+    
+    // 更新端口活动时间
+    void UpdatePortActivity(int port);
+    
+    // 更新端口活动时间
+    void RemovePortActivity(int port);
+};

+ 160 - 0
WebSocketSession.cpp

@@ -0,0 +1,160 @@
+#include "WebSocketSession.h"
+#include "WebSocketHandler.h"
+#include "Logger.h"
+#include <boost/beast/version.hpp>
+
+WebSocketSession::WebSocketSession(tcp::socket&& socket, http::request<http::dynamic_body> req)
+    : ws_(std::move(socket)), req_(std::move(req)) {
+}
+
+WebSocketSession::~WebSocketSession() {
+    close();
+    
+    // 注意:不应该在这里调用RemoveClient,因为如果WebSocketHandler仍然持有shared_ptr,
+    // 析构函数永远不会被调用。正确的做法是在RemoveClient时触发析构。
+}
+
+void WebSocketSession::run() {
+    // 设置建议的超时设置
+    beast::get_lowest_layer(ws_).expires_never();
+    
+    // 设置WebSocket超时参数
+    ws_.set_option(websocket::stream_base::timeout{
+        std::chrono::seconds(30),  // handshake timeout
+        std::chrono::seconds(30),  // idle timeout
+        true                      // 取消关闭连接前的静默超时
+    });
+    
+    // 设置装饰器来改变服务器握手
+    ws_.set_option(websocket::stream_base::decorator(
+        [](websocket::response_type& res) {
+            res.set(http::field::server, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-server-async");
+        }));
+    
+    // 接受WebSocket握手
+    ws_.async_accept(
+        req_,
+        beast::bind_front_handler(&WebSocketSession::on_accept, shared_from_this()));
+}
+
+void WebSocketSession::on_accept(beast::error_code ec) {
+    if (ec) {
+        LOG_ERROR("WebSocket accept failed: " + ec.message());
+        return;
+    }
+    
+    LOG_INFO("WebSocket connection established");
+    
+    // 开始读取消息
+    do_read();
+}
+
+void WebSocketSession::do_read() {
+    if (closed_.load()) {
+        return;
+    }
+    
+    // 读取消息
+    ws_.async_read(
+        buffer_,
+        beast::bind_front_handler(&WebSocketSession::on_read, shared_from_this()));
+}
+
+void WebSocketSession::on_read(beast::error_code ec, std::size_t bytes_transferred) {
+    boost::ignore_unused(bytes_transferred);
+    
+    if (ec) {
+        if (ec != websocket::error::closed) {
+            LOG_ERROR("WebSocket read failed: " + ec.message());
+        }
+        
+        // 通知处理器移除客户端
+        if (websocket_handler_) {
+            websocket_handler_->RemoveClient(shared_from_this());
+        }
+        return;
+    }
+    
+    // 处理接收到的消息
+    std::string message = beast::buffers_to_string(buffer_.data());
+    buffer_.clear();
+    
+    // 调用消息处理回调
+    if (message_handler_) {
+        message_handler_(shared_from_this(), message);
+    }
+    
+    // 继续读取下一个消息
+    do_read();
+}
+
+void WebSocketSession::safe_send(std::shared_ptr<std::string> message) {
+    if (closed_.load()) {
+        return;
+    }
+    
+    std::lock_guard<std::mutex> lock(send_mutex_);
+    send_queue_.push(message);
+    
+    if (!is_sending_) {
+        do_write();
+    }
+}
+
+void WebSocketSession::do_write() {
+    // 注意:此方法应该在持有send_mutex_锁的情况下调用
+    if (closed_.load() || send_queue_.empty()) {
+        is_sending_ = false;
+        return;
+    }
+    
+    is_sending_ = true;
+    current_message_ = send_queue_.front();
+    send_queue_.pop();
+    
+    // 使用成员变量current_message_确保在异步操作期间消息不会被销毁
+    ws_.async_write(
+        net::buffer(*current_message_),
+        beast::bind_front_handler(&WebSocketSession::on_write, shared_from_this()));
+}
+
+void WebSocketSession::on_write(beast::error_code ec, std::size_t bytes_transferred) {
+    boost::ignore_unused(bytes_transferred);
+    
+    std::lock_guard<std::mutex> lock(send_mutex_);
+    current_message_.reset(); // 清理当前消息
+    
+    if (ec) {
+        LOG_ERROR("WebSocket write failed: " + ec.message());
+        is_sending_ = false;
+        
+        // 如果写入失败,关闭连接并通知处理器移除客户端
+        if (websocket_handler_) {
+            close();
+            websocket_handler_->RemoveClient(shared_from_this());
+        }
+        return;
+    }
+    
+    if (!send_queue_.empty()) {
+        do_write();
+    } else {
+        is_sending_ = false;
+    }
+}
+
+void WebSocketSession::close() {
+    if (closed_.exchange(true)) {
+        return; // 已经关闭
+    }
+    
+    beast::error_code ec;
+    ws_.close(websocket::close_code::normal, ec);
+    if (ec) {
+        LOG_ERROR("WebSocket close failed: " + ec.message());
+    }
+}
+
+void WebSocketSession::set_message_handler(MessageHandler handler) {
+    message_handler_ = handler;
+}

+ 66 - 0
WebSocketSession.h

@@ -0,0 +1,66 @@
+#pragma once
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/strand.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <mutex>
+#include <queue>
+#include <atomic>
+
+namespace beast = boost::beast;
+namespace http = beast::http;
+namespace websocket = beast::websocket;
+namespace net = boost::asio;
+using tcp = boost::asio::ip::tcp;
+
+// 前向声明
+class WebSocketHandler;
+
+class WebSocketSession : public std::enable_shared_from_this<WebSocketSession> {
+public:
+    using MessageHandler = std::function<void(std::shared_ptr<WebSocketSession>, const std::string&)>;
+
+private:
+    websocket::stream<beast::tcp_stream> ws_;
+    beast::flat_buffer buffer_;
+    http::request<http::dynamic_body> req_;
+    
+    std::mutex send_mutex_;
+    std::queue<std::shared_ptr<std::string>> send_queue_;
+    std::shared_ptr<std::string> current_message_; // 添加这个成员变量
+    bool is_sending_ = false;
+    std::atomic<bool> closed_{false};
+    
+    MessageHandler message_handler_;
+    
+    // 添加对WebSocketHandler的引用
+    std::shared_ptr<WebSocketHandler> websocket_handler_;
+
+public:
+    explicit WebSocketSession(tcp::socket&& socket, http::request<http::dynamic_body> req);
+    ~WebSocketSession();
+    
+    void run();
+    void safe_send(std::shared_ptr<std::string> message);
+    void close();
+    void set_message_handler(MessageHandler handler);
+    
+    // 添加设置WebSocketHandler的方法
+    void set_websocket_handler(std::shared_ptr<WebSocketHandler> handler) { websocket_handler_ = handler; }
+
+private:
+    void on_accept(beast::error_code ec);
+    void do_read();
+    void on_read(beast::error_code ec, std::size_t bytes_transferred);
+    void do_write();
+    void on_write(beast::error_code ec, std::size_t bytes_transferred);
+};

+ 63 - 0
cryptopp/3way.h

@@ -0,0 +1,63 @@
+// 3way.h - originally written and placed in the public domain by Wei Dai
+
+/// \file 3way.h
+/// \brief Classes for the 3-Way block cipher
+
+#ifndef CRYPTOPP_THREEWAY_H
+#define CRYPTOPP_THREEWAY_H
+
+#include "config.h"
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief ThreeWay block cipher information
+struct ThreeWay_Info : public FixedBlockSize<12>, public FixedKeyLength<12>, public VariableRounds<11>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "3-Way";}
+};
+
+/// \brief ThreeWay block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/3-Way">3-Way</a>
+class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation
+{
+	/// \brief Class specific implementation and overrides used to operate the cipher.
+	/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<ThreeWay_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
+
+	protected:
+		unsigned int m_rounds;
+		FixedSizeSecBlock<word32, 3> m_k;
+	};
+
+	/// \brief Class specific methods used to operate the cipher in the forward direction.
+	/// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION.
+	class CRYPTOPP_NO_VTABLE Enc : public Base
+	{
+	public:
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+	};
+
+	/// \brief Class specific methods used to operate the cipher in the reverse direction.
+	/// \details Implementations and overrides in \p Dec apply to \p DECRYPTION.
+	class CRYPTOPP_NO_VTABLE Dec : public Base
+	{
+	public:
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Dec> Decryption;
+};
+
+typedef ThreeWay::Encryption ThreeWayEncryption;
+typedef ThreeWay::Decryption ThreeWayDecryption;
+
+NAMESPACE_END
+
+#endif

BIN
cryptopp/Win32/Debug/cryptlib.lib


BIN
cryptopp/Win32/Debug/cryptlib.pdb


BIN
cryptopp/Win32/Release/cryptlib.lib


BIN
cryptopp/Win32/Release/cryptlib.pdb


+ 33 - 0
cryptopp/adler32.h

@@ -0,0 +1,33 @@
+// adler32.h - originally written and placed in the public domain by Wei Dai
+
+/// \file adler32.h
+/// \brief Class file for ADLER-32 checksum calculations
+
+#ifndef CRYPTOPP_ADLER32_H
+#define CRYPTOPP_ADLER32_H
+
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// ADLER-32 checksum calculations
+class Adler32 : public HashTransformation
+{
+public:
+	CRYPTOPP_CONSTANT(DIGESTSIZE = 4);
+	Adler32() {Reset();}
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *hash, size_t size);
+	unsigned int DigestSize() const {return DIGESTSIZE;}
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Adler32";}
+    std::string AlgorithmName() const {return StaticAlgorithmName();}
+
+private:
+	void Reset() {m_s1 = 1; m_s2 = 0;}
+
+	word16 m_s1, m_s2;
+};
+
+NAMESPACE_END
+
+#endif

+ 1281 - 0
cryptopp/adv_simd.h

@@ -0,0 +1,1281 @@
+// adv_simd.h - written and placed in the public domain by Jeffrey Walton
+
+/// \file adv_simd.h
+/// \brief Template for AdvancedProcessBlocks and SIMD processing
+
+//    The SIMD based implementations for ciphers that use SSE, NEON and Power7
+//    have a common pattern. Namely, they have a specialized implementation of
+//    AdvancedProcessBlocks which processes multiple block using hardware
+//    acceleration. After several implementations we noticed a lot of copy and
+//    paste occurring. adv_simd.h provides a template to avoid the copy and paste.
+//
+//    There are 6 templates provided in this file. The number following the
+//    function name, 128, is the block size in bits. The name following the
+//    block size is the arrangement and acceleration. For example 4x1_SSE means
+//    Intel SSE using two encrypt (or decrypt) functions: one that operates on
+//    4 SIMD words, and one that operates on 1 SIMD words.
+//
+//      * AdvancedProcessBlocks128_4x1_SSE
+//      * AdvancedProcessBlocks128_6x2_SSE
+//      * AdvancedProcessBlocks128_4x1_NEON
+//      * AdvancedProcessBlocks128_6x1_NEON
+//      * AdvancedProcessBlocks128_4x1_ALTIVEC
+//      * AdvancedProcessBlocks128_6x1_ALTIVEC
+//
+//    If an arrangement ends in 2, like 6x2, then the template will handle the
+//    single block case by padding with 0's and using the two SIMD word
+//    function. This happens at most one time when processing multiple blocks.
+//    The extra processing of a zero block is trivial and worth the tradeoff.
+//
+//    The MAYBE_CONST macro present on x86 is a SunCC workaround. Some versions
+//    of SunCC lose/drop the const-ness in the F1 and F4 functions. It eventually
+//    results in a failed link due to the const/non-const mismatch.
+//
+//    In July 2020 the library stopped using 64-bit block version of
+//    AdvancedProcessBlocks. Testing showed unreliable results and failed
+//    self tests on occasion. Also see Issue 945 and
+//    https://github.com/weidai11/cryptopp/commit/dd7598e638bb.
+
+#ifndef CRYPTOPP_ADVANCED_SIMD_TEMPLATES
+#define CRYPTOPP_ADVANCED_SIMD_TEMPLATES
+
+#include "config.h"
+#include "misc.h"
+#include "stdcpp.h"
+
+#if (CRYPTOPP_ARM_NEON_HEADER)
+# include <arm_neon.h>
+#endif
+
+#if (CRYPTOPP_ARM_ACLE_HEADER)
+# include <stdint.h>
+# include <arm_acle.h>
+#endif
+
+#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
+# include <emmintrin.h>
+# include <xmmintrin.h>
+#endif
+
+// SunCC needs CRYPTOPP_SSSE3_AVAILABLE, too
+#if (CRYPTOPP_SSSE3_AVAILABLE)
+# include <emmintrin.h>
+# include <pmmintrin.h>
+# include <xmmintrin.h>
+#endif
+
+#if defined(__ALTIVEC__)
+# include "ppc_simd.h"
+#endif
+
+// ************************ All block ciphers *********************** //
+
+ANONYMOUS_NAMESPACE_BEGIN
+
+using CryptoPP::BlockTransformation;
+
+CRYPTOPP_CONSTANT(BT_XorInput = BlockTransformation::BT_XorInput);
+CRYPTOPP_CONSTANT(BT_AllowParallel = BlockTransformation::BT_AllowParallel);
+CRYPTOPP_CONSTANT(BT_InBlockIsCounter = BlockTransformation::BT_InBlockIsCounter);
+CRYPTOPP_CONSTANT(BT_ReverseDirection = BlockTransformation::BT_ReverseDirection);
+CRYPTOPP_CONSTANT(BT_DontIncrementInOutPointers = BlockTransformation::BT_DontIncrementInOutPointers);
+
+ANONYMOUS_NAMESPACE_END
+
+// *************************** ARM NEON ************************** //
+
+#if (CRYPTOPP_ARM_NEON_AVAILABLE) || (CRYPTOPP_ARM_ASIMD_AVAILABLE) || \
+    defined(CRYPTOPP_DOXYGEN_PROCESSING)
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief AdvancedProcessBlocks for 1 and 6 blocks
+/// \tparam F1 function to process 1 128-bit block
+/// \tparam F6 function to process 6 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_6x1_NEON processes 6 and 2 NEON SIMD words
+///  at a time.
+/// \details The subkey type is usually word32 or word64. F1 and F6 must use the
+///  same word type.
+template <typename F1, typename F6, typename W>
+inline size_t AdvancedProcessBlocks128_6x1_NEON(F1 func1, F6 func6,
+            const W *subKeys, size_t rounds, const byte *inBlocks,
+            const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+    const unsigned int w_one[] = {0, 0<<24, 0, 1<<24};
+    const uint32x4_t s_one = vld1q_u32(w_one);
+
+    const size_t blockSize = 16;
+    // const size_t neonBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 6*blockSize)
+        {
+            uint64x2_t block0, block1, block2, block3, block4, block5;
+            if (flags & BT_InBlockIsCounter)
+            {
+                const uint64x2_t one = vreinterpretq_u64_u32(s_one);
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                block1 = vaddq_u64(block0, one);
+                block2 = vaddq_u64(block1, one);
+                block3 = vaddq_u64(block2, one);
+                block4 = vaddq_u64(block3, one);
+                block5 = vaddq_u64(block4, one);
+                vst1q_u8(const_cast<byte*>(inBlocks),
+                    vreinterpretq_u8_u64(vaddq_u64(block5, one)));
+            }
+            else
+            {
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 6*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        uint64x2_t block;
+        block = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+
+        if (xorInput)
+            block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func1(block, subKeys, static_cast<unsigned int>(rounds));
+
+        if (xorOutput)
+            block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+
+        vst1q_u8(outBlocks, vreinterpretq_u8_u64(block));
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+/// \brief AdvancedProcessBlocks for 1 and 4 blocks
+/// \tparam F1 function to process 1 128-bit block
+/// \tparam F4 function to process 4 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_4x1_NEON processes 4 and 1 NEON SIMD words
+///  at a time.
+/// \details The subkey type is usually word32 or word64. V is the vector type and it is
+///  usually uint32x4_t or uint32x4_t. F1, F4, and W must use the same word and
+///  vector type.
+template <typename F1, typename F4, typename W>
+inline size_t AdvancedProcessBlocks128_4x1_NEON(F1 func1, F4 func4,
+            const W *subKeys, size_t rounds, const byte *inBlocks,
+            const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+    const unsigned int w_one[] = {0, 0<<24, 0, 1<<24};
+    const uint32x4_t s_one = vld1q_u32(w_one);
+
+    const size_t blockSize = 16;
+    // const size_t neonBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 4*blockSize)
+        {
+            uint32x4_t block0, block1, block2, block3;
+            if (flags & BT_InBlockIsCounter)
+            {
+                const uint32x4_t one = s_one;
+                block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+                block1 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block0), vreinterpretq_u64_u32(one)));
+                block2 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block1), vreinterpretq_u64_u32(one)));
+                block3 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block2), vreinterpretq_u64_u32(one)));
+                vst1q_u8(const_cast<byte*>(inBlocks), vreinterpretq_u8_u64(vaddq_u64(
+                    vreinterpretq_u64_u32(block3), vreinterpretq_u64_u32(one))));
+            }
+            else
+            {
+                block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func4(block0, block1, block2, block3, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            vst1q_u8(outBlocks, vreinterpretq_u8_u32(block0));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u32(block1));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u32(block2));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u32(block3));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 4*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        uint32x4_t block = vreinterpretq_u32_u8(vld1q_u8(inBlocks));
+
+        if (xorInput)
+            block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func1(block, subKeys, static_cast<unsigned int>(rounds));
+
+        if (xorOutput)
+            block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks)));
+
+        vst1q_u8(outBlocks, vreinterpretq_u8_u32(block));
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+/// \brief AdvancedProcessBlocks for 2 and 6 blocks
+/// \tparam F2 function to process 2 128-bit blocks
+/// \tparam F6 function to process 6 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_6x2_NEON processes 6 and 2 NEON SIMD words
+///  at a time. For a single block the template uses F2 with a zero block.
+/// \details The subkey type is usually word32 or word64. F2 and F6 must use the
+///  same word type.
+template <typename F2, typename F6, typename W>
+inline size_t AdvancedProcessBlocks128_6x2_NEON(F2 func2, F6 func6,
+            const W *subKeys, size_t rounds, const byte *inBlocks,
+            const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+    const unsigned int w_one[] = {0, 0<<24, 0, 1<<24};
+    const uint32x4_t s_one = vld1q_u32(w_one);
+
+    const size_t blockSize = 16;
+    // const size_t neonBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 6*blockSize)
+        {
+            uint64x2_t block0, block1, block2, block3, block4, block5;
+            if (flags & BT_InBlockIsCounter)
+            {
+                const uint64x2_t one = vreinterpretq_u64_u32(s_one);
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                block1 = vaddq_u64(block0, one);
+                block2 = vaddq_u64(block1, one);
+                block3 = vaddq_u64(block2, one);
+                block4 = vaddq_u64(block3, one);
+                block5 = vaddq_u64(block4, one);
+                vst1q_u8(const_cast<byte*>(inBlocks),
+                    vreinterpretq_u8_u64(vaddq_u64(block5, one)));
+            }
+            else
+            {
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 6*blockSize;
+        }
+
+        while (length >= 2*blockSize)
+        {
+            uint64x2_t block0, block1;
+            if (flags & BT_InBlockIsCounter)
+            {
+                const uint64x2_t one = vreinterpretq_u64_u32(s_one);
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                block1 = vaddq_u64(block0, one);
+                vst1q_u8(const_cast<byte*>(inBlocks),
+                    vreinterpretq_u8_u64(vaddq_u64(block1, one)));
+            }
+            else
+            {
+                block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func2(block0, block1, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1));
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 2*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        uint64x2_t block, zero = {0,0};
+        block = vreinterpretq_u64_u8(vld1q_u8(inBlocks));
+
+        if (xorInput)
+            block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func2(block, zero, subKeys, static_cast<unsigned int>(rounds));
+
+        if (xorOutput)
+            block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks)));
+
+        vst1q_u8(outBlocks, vreinterpretq_u8_u64(block));
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_ARM_NEON_AVAILABLE
+
+// *************************** Intel SSE ************************** //
+
+#if defined(CRYPTOPP_SSSE3_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+/// \brief SunCC workaround
+/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block
+/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/224">Issue
+///  224, SunCC and failed compile for rijndael.cpp</A>
+# define MAYBE_CONST const
+/// \brief SunCC workaround
+/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block
+/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/224">Issue
+///  224, SunCC and failed compile for rijndael.cpp</A>
+# define MAYBE_UNCONST_CAST(T, x) (x)
+#elif (__SUNPRO_CC >= 0x5130)
+# define MAYBE_CONST
+# define MAYBE_UNCONST_CAST(T, x) const_cast<MAYBE_CONST T>(x)
+#else
+# define MAYBE_CONST const
+# define MAYBE_UNCONST_CAST(T, x) (x)
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+/// \brief Clang workaround
+/// \details Clang issues spurious alignment warnings
+/// \sa <A HREF="http://bugs.llvm.org/show_bug.cgi?id=20670">Issue
+///  20670, _mm_loadu_si128 parameter has wrong type</A>
+# define M128_CAST(x) ((__m128i *)(void *)(x))
+/// \brief Clang workaround
+/// \details Clang issues spurious alignment warnings
+/// \sa <A HREF="http://bugs.llvm.org/show_bug.cgi?id=20670">Issue
+///  20670, _mm_loadu_si128 parameter has wrong type</A>
+# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x))
+#else
+# ifndef M128_CAST
+#  define M128_CAST(x) ((__m128i *)(void *)(x))
+# endif
+# ifndef CONST_M128_CAST
+#  define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x))
+# endif
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief AdvancedProcessBlocks for 2 and 6 blocks
+/// \tparam F2 function to process 2 128-bit blocks
+/// \tparam F6 function to process 6 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_6x2_SSE processes 6 and 2 SSE SIMD words
+///  at a time. For a single block the template uses F2 with a zero block.
+/// \details The subkey type is usually word32 or word64. F2 and F6 must use the
+///  same word type.
+template <typename F2, typename F6, typename W>
+inline size_t AdvancedProcessBlocks128_6x2_SSE(F2 func2, F6 func6,
+        MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks,
+        const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+    const size_t blockSize = 16;
+    // const size_t xmmBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 6*blockSize)
+        {
+            __m128i block0, block1, block2, block3, block4, block5;
+            if (flags & BT_InBlockIsCounter)
+            {
+                // Increment of 1 in big-endian compatible with the ctr byte array.
+                const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0);
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                block1 = _mm_add_epi32(block0, s_one);
+                block2 = _mm_add_epi32(block1, s_one);
+                block3 = _mm_add_epi32(block2, s_one);
+                block4 = _mm_add_epi32(block3, s_one);
+                block5 = _mm_add_epi32(block4, s_one);
+                _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block5, s_one));
+            }
+            else
+            {
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block4 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block5 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            _mm_storeu_si128(M128_CAST(outBlocks), block0);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block1);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block2);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block3);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block4);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block5);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 6*blockSize;
+        }
+
+        while (length >= 2*blockSize)
+        {
+            __m128i block0, block1;
+            if (flags & BT_InBlockIsCounter)
+            {
+                // Increment of 1 in big-endian compatible with the ctr byte array.
+                const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0);
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                block1 = _mm_add_epi32(block0, s_one);
+                _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block1, s_one));
+            }
+            else
+            {
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func2(block0, block1, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            _mm_storeu_si128(M128_CAST(outBlocks), block0);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block1);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 2*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        __m128i block, zero = _mm_setzero_si128();
+        block = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+
+        if (xorInput)
+            block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func2(block, zero, subKeys, static_cast<unsigned int>(rounds));
+
+        if (xorOutput)
+            block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+
+        _mm_storeu_si128(M128_CAST(outBlocks), block);
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+/// \brief AdvancedProcessBlocks for 1 and 4 blocks
+/// \tparam F1 function to process 1 128-bit block
+/// \tparam F4 function to process 4 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_4x1_SSE processes 4 and 1 SSE SIMD words
+///  at a time.
+/// \details The subkey type is usually word32 or word64. F1 and F4 must use the
+///  same word type.
+template <typename F1, typename F4, typename W>
+inline size_t AdvancedProcessBlocks128_4x1_SSE(F1 func1, F4 func4,
+        MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks,
+        const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+    const size_t blockSize = 16;
+    // const size_t xmmBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 4*blockSize)
+        {
+            __m128i block0, block1, block2, block3;
+            if (flags & BT_InBlockIsCounter)
+            {
+                // Increment of 1 in big-endian compatible with the ctr byte array.
+                const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0);
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                block1 = _mm_add_epi32(block0, s_one);
+                block2 = _mm_add_epi32(block1, s_one);
+                block3 = _mm_add_epi32(block2, s_one);
+                _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block3, s_one));
+            }
+            else
+            {
+                block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func4(block0, block1, block2, block3, subKeys, static_cast<unsigned int>(rounds));
+
+            if (xorOutput)
+            {
+                block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            _mm_storeu_si128(M128_CAST(outBlocks), block0);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block1);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block2);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            _mm_storeu_si128(M128_CAST(outBlocks), block3);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 4*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        __m128i block = _mm_loadu_si128(CONST_M128_CAST(inBlocks));
+
+        if (xorInput)
+            block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func1(block, subKeys, static_cast<unsigned int>(rounds));
+
+        if (xorOutput)
+            block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks)));
+
+        _mm_storeu_si128(M128_CAST(outBlocks), block);
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_SSSE3_AVAILABLE
+
+// ************************** Altivec/Power 4 ************************** //
+
+#if defined(__ALTIVEC__) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief AdvancedProcessBlocks for 1 and 4 blocks
+/// \tparam F1 function to process 1 128-bit block
+/// \tparam F4 function to process 4 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_4x1_ALTIVEC processes 4 and 1 Altivec SIMD words
+///  at a time.
+/// \details The subkey type is usually word32 or word64. F1 and F4 must use the
+///  same word type.
+template <typename F1, typename F4, typename W>
+inline size_t AdvancedProcessBlocks128_4x1_ALTIVEC(F1 func1, F4 func4,
+        const W *subKeys, size_t rounds, const byte *inBlocks,
+        const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+#if (CRYPTOPP_LITTLE_ENDIAN)
+    const uint32x4_p s_one  = {1,0,0,0};
+#else
+    const uint32x4_p s_one = {0,0,0,1};
+#endif
+
+    const size_t blockSize = 16;
+    // const size_t simdBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 4*blockSize)
+        {
+            uint32x4_p block0, block1, block2, block3;
+
+            if (flags & BT_InBlockIsCounter)
+            {
+                block0 = VecLoadBE(inBlocks);
+                block1 = VecAdd(block0, s_one);
+                block2 = VecAdd(block1, s_one);
+                block3 = VecAdd(block2, s_one);
+
+                // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE).
+                // CTR_ModePolicy::OperateKeystream is wired such that after
+                // returning from this function CTR_ModePolicy will detect wrap on
+                // on the last counter byte and increment the next to last byte.
+                // The problem is, with a big-endian load, inBlocks[15] is really
+                // located at index 15. The vector addition using a 32-bit element
+                // generates a carry into inBlocks[14] and then CTR_ModePolicy
+                // increments inBlocks[14] too.
+                const_cast<byte*>(inBlocks)[15] += 6;
+            }
+            else
+            {
+                block0 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = VecXor(block0, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = VecXor(block1, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = VecXor(block2, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = VecXor(block3, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func4(block0, block1, block2, block3, subKeys, rounds);
+
+            if (xorOutput)
+            {
+                block0 = VecXor(block0, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = VecXor(block1, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = VecXor(block2, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = VecXor(block3, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            VecStoreBE(block0, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block1, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block2, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block3, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 4*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        uint32x4_p block = VecLoadBE(inBlocks);
+
+        if (xorInput)
+            block = VecXor(block, VecLoadBE(xorBlocks));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func1(block, subKeys, rounds);
+
+        if (xorOutput)
+            block = VecXor(block, VecLoadBE(xorBlocks));
+
+        VecStoreBE(block, outBlocks);
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+/// \brief AdvancedProcessBlocks for 1 and 6 blocks
+/// \tparam F1 function to process 1 128-bit block
+/// \tparam F6 function to process 6 128-bit blocks
+/// \tparam W word type of the subkey table
+/// \details AdvancedProcessBlocks128_6x1_ALTIVEC processes 6 and 1 Altivec SIMD words
+///  at a time.
+/// \details The subkey type is usually word32 or word64. F1 and F6 must use the
+///  same word type.
+template <typename F1, typename F6, typename W>
+inline size_t AdvancedProcessBlocks128_6x1_ALTIVEC(F1 func1, F6 func6,
+        const W *subKeys, size_t rounds, const byte *inBlocks,
+        const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags)
+{
+    CRYPTOPP_ASSERT(subKeys);
+    CRYPTOPP_ASSERT(inBlocks);
+    CRYPTOPP_ASSERT(outBlocks);
+    CRYPTOPP_ASSERT(length >= 16);
+
+#if (CRYPTOPP_LITTLE_ENDIAN)
+    const uint32x4_p s_one  = {1,0,0,0};
+#else
+    const uint32x4_p s_one = {0,0,0,1};
+#endif
+
+    const size_t blockSize = 16;
+    // const size_t simdBlockSize = 16;
+
+    size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize;
+    size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0;
+    size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize;
+
+    // Clang and Coverity are generating findings using xorBlocks as a flag.
+    const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput));
+    const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput));
+
+    if (flags & BT_ReverseDirection)
+    {
+        inBlocks = PtrAdd(inBlocks, length - blockSize);
+        xorBlocks = PtrAdd(xorBlocks, length - blockSize);
+        outBlocks = PtrAdd(outBlocks, length - blockSize);
+        inIncrement = 0-inIncrement;
+        xorIncrement = 0-xorIncrement;
+        outIncrement = 0-outIncrement;
+    }
+
+    if (flags & BT_AllowParallel)
+    {
+        while (length >= 6*blockSize)
+        {
+            uint32x4_p block0, block1, block2, block3, block4, block5;
+
+            if (flags & BT_InBlockIsCounter)
+            {
+                block0 = VecLoadBE(inBlocks);
+                block1 = VecAdd(block0, s_one);
+                block2 = VecAdd(block1, s_one);
+                block3 = VecAdd(block2, s_one);
+                block4 = VecAdd(block3, s_one);
+                block5 = VecAdd(block4, s_one);
+
+                // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE).
+                // CTR_ModePolicy::OperateKeystream is wired such that after
+                // returning from this function CTR_ModePolicy will detect wrap on
+                // on the last counter byte and increment the next to last byte.
+                // The problem is, with a big-endian load, inBlocks[15] is really
+                // located at index 15. The vector addition using a 32-bit element
+                // generates a carry into inBlocks[14] and then CTR_ModePolicy
+                // increments inBlocks[14] too.
+                //
+                // To find this bug we needed a test case with a ctr of 0xNN...FA.
+                // The last octet is 0xFA and adding 6 creates the wrap to trigger
+                // the issue. If the last octet was 0xFC then 4 would trigger it.
+                // We dumb-lucked into the test with SPECK-128. The test case of
+                // interest is the one with IV 348ECA9766C09F04 826520DE47A212FA.
+                uint8x16_p temp = VecAdd((uint8x16_p)block5, (uint8x16_p)s_one);
+                VecStoreBE(temp, const_cast<byte*>(inBlocks));
+            }
+            else
+            {
+                block0 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block1 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block2 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block3 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block4 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+                block5 = VecLoadBE(inBlocks);
+                inBlocks = PtrAdd(inBlocks, inIncrement);
+            }
+
+            if (xorInput)
+            {
+                block0 = VecXor(block0, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = VecXor(block1, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = VecXor(block2, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = VecXor(block3, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = VecXor(block4, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = VecXor(block5, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            func6(block0, block1, block2, block3, block4, block5, subKeys, rounds);
+
+            if (xorOutput)
+            {
+                block0 = VecXor(block0, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block1 = VecXor(block1, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block2 = VecXor(block2, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block3 = VecXor(block3, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block4 = VecXor(block4, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+                block5 = VecXor(block5, VecLoadBE(xorBlocks));
+                xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+            }
+
+            VecStoreBE(block0, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block1, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block2, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block3, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block4, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+            VecStoreBE(block5, outBlocks);
+            outBlocks = PtrAdd(outBlocks, outIncrement);
+
+            length -= 6*blockSize;
+        }
+    }
+
+    while (length >= blockSize)
+    {
+        uint32x4_p block = VecLoadBE(inBlocks);
+
+        if (xorInput)
+            block = VecXor(block, VecLoadBE(xorBlocks));
+
+        if (flags & BT_InBlockIsCounter)
+            const_cast<byte *>(inBlocks)[15]++;
+
+        func1(block, subKeys, rounds);
+
+        if (xorOutput)
+            block = VecXor(block, VecLoadBE(xorBlocks));
+
+        VecStoreBE(block, outBlocks);
+
+        inBlocks = PtrAdd(inBlocks, inIncrement);
+        outBlocks = PtrAdd(outBlocks, outIncrement);
+        xorBlocks = PtrAdd(xorBlocks, xorIncrement);
+        length -= blockSize;
+    }
+
+    return length;
+}
+
+NAMESPACE_END  // CryptoPP
+
+#endif  // __ALTIVEC__
+
+#endif  // CRYPTOPP_ADVANCED_SIMD_TEMPLATES

+ 30 - 0
cryptopp/aes.h

@@ -0,0 +1,30 @@
+// aes.h - originally written and placed in the public domain by Wei Dai
+
+/// \file
+/// \brief Class file for the AES cipher (Rijndael)
+/// \details AES is a typdef for Rijndael classes. All key sizes are supported.
+///   The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks
+/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0,
+///   Power8 AES since Crypto++ 6.0
+
+#ifndef CRYPTOPP_AES_H
+#define CRYPTOPP_AES_H
+
+#include "rijndael.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief AES block cipher (Rijndael)
+/// \details AES is a typdef for Rijndael classes. All key sizes are supported.
+///   The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks
+/// \sa <a href="http://www.cryptolounge.org/wiki/AES">AES</a> winner, announced on 10/2/2000
+/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0,
+///   Power8 AES since Crypto++ 6.0
+DOCUMENTED_TYPEDEF(Rijndael, AES);
+
+typedef RijndaelEncryption AESEncryption;
+typedef RijndaelDecryption AESDecryption;
+
+NAMESPACE_END
+
+#endif

+ 30 - 0
cryptopp/aes_armv4.h

@@ -0,0 +1,30 @@
+/* Header file for use with Cryptogam's ARMv4 AES.         */
+/* Also see http://www.openssl.org/~appro/cryptogams/ and  */
+/* https://wiki.openssl.org/index.php?title=Cryptogams_AES */
+
+#ifndef CRYPTOGAMS_AES_ARMV4_H
+#define CRYPTOGAMS_AES_ARMV4_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define AES_MAXNR 14
+//typedef struct AES_KEY_st {
+//    unsigned int rd_key[4 * (AES_MAXNR + 1)];
+//    int rounds;
+//} AES_KEY;
+
+// Instead of AES_KEY we use a 'word32 rkey[4*15+4]'. It has space for
+// both the AES_MAXNR round keys and the number of rounds in the tail.
+
+int cryptogams_AES_set_encrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey);
+int cryptogams_AES_set_decrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey);
+void cryptogams_AES_encrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey);
+void cryptogams_AES_decrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* CRYPTOGAMS_AES_ARMV4_H */

+ 453 - 0
cryptopp/algebra.h

@@ -0,0 +1,453 @@
+// algebra.h - originally written and placed in the public domain by Wei Dai
+
+/// \file algebra.h
+/// \brief Classes for performing mathematics over different fields
+
+#ifndef CRYPTOPP_ALGEBRA_H
+#define CRYPTOPP_ALGEBRA_H
+
+#include "config.h"
+#include "integer.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+class Integer;
+
+/// \brief Abstract group
+/// \tparam T element class or type
+/// \details <tt>const Element&</tt> returned by member functions are references
+///   to internal data members. Since each object may have only
+///   one such data member for holding results, the following code
+///   will produce incorrect results:
+///   <pre>    abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
+///   But this should be fine:
+///   <pre>    abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
+template <class T> class CRYPTOPP_NO_VTABLE AbstractGroup
+{
+public:
+	typedef T Element;
+
+	virtual ~AbstractGroup() {}
+
+	/// \brief Compare two elements for equality
+	/// \param a first element
+	/// \param b second element
+	/// \return true if the elements are equal, false otherwise
+	/// \details Equal() tests the elements for equality using <tt>a==b</tt>
+	virtual bool Equal(const Element &a, const Element &b) const =0;
+
+	/// \brief Provides the Identity element
+	/// \return the Identity element
+	virtual const Element& Identity() const =0;
+
+	/// \brief Adds elements in the group
+	/// \param a first element
+	/// \param b second element
+	/// \return the sum of <tt>a</tt> and <tt>b</tt>
+	virtual const Element& Add(const Element &a, const Element &b) const =0;
+
+	/// \brief Inverts the element in the group
+	/// \param a first element
+	/// \return the inverse of the element
+	virtual const Element& Inverse(const Element &a) const =0;
+
+	/// \brief Determine if inversion is fast
+	/// \return true if inversion is fast, false otherwise
+	virtual bool InversionIsFast() const {return false;}
+
+	/// \brief Doubles an element in the group
+	/// \param a the element
+	/// \return the element doubled
+	virtual const Element& Double(const Element &a) const;
+
+	/// \brief Subtracts elements in the group
+	/// \param a first element
+	/// \param b second element
+	/// \return the difference of <tt>a</tt> and <tt>b</tt>. The element <tt>a</tt> must provide a Subtract member function.
+	virtual const Element& Subtract(const Element &a, const Element &b) const;
+
+	/// \brief TODO
+	/// \param a first element
+	/// \param b second element
+	/// \return TODO
+	virtual Element& Accumulate(Element &a, const Element &b) const;
+
+	/// \brief Reduces an element in the congruence class
+	/// \param a element to reduce
+	/// \param b the congruence class
+	/// \return the reduced element
+	virtual Element& Reduce(Element &a, const Element &b) const;
+
+	/// \brief Performs a scalar multiplication
+	/// \param a multiplicand
+	/// \param e multiplier
+	/// \return the product
+	virtual Element ScalarMultiply(const Element &a, const Integer &e) const;
+
+	/// \brief TODO
+	/// \param x first multiplicand
+	/// \param e1 the first multiplier
+	/// \param y second multiplicand
+	/// \param e2 the second multiplier
+	/// \return TODO
+	virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
+
+	/// \brief Multiplies a base to multiple exponents in a group
+	/// \param results an array of Elements
+	/// \param base the base to raise to the exponents
+	/// \param exponents an array of exponents
+	/// \param exponentsCount the number of exponents in the array
+	/// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the
+	///   result at the respective position in the results array.
+	/// \details SimultaneousMultiply() must be implemented in a derived class.
+	/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
+	/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
+	virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
+};
+
+/// \brief Abstract ring
+/// \tparam T element class or type
+/// \details <tt>const Element&</tt> returned by member functions are references
+///   to internal data members. Since each object may have only
+///   one such data member for holding results, the following code
+///   will produce incorrect results:
+///   <pre>    abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
+///   But this should be fine:
+///   <pre>    abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
+template <class T> class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup<T>
+{
+public:
+	typedef T Element;
+
+	/// \brief Construct an AbstractRing
+	AbstractRing() {m_mg.m_pRing = this;}
+
+	/// \brief Copy construct an AbstractRing
+	/// \param source other AbstractRing
+	AbstractRing(const AbstractRing &source)
+		{CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;}
+
+	/// \brief Assign an AbstractRing
+	/// \param source other AbstractRing
+	AbstractRing& operator=(const AbstractRing &source)
+		{CRYPTOPP_UNUSED(source); return *this;}
+
+	/// \brief Determines whether an element is a unit in the group
+	/// \param a the element
+	/// \return true if the element is a unit after reduction, false otherwise.
+	virtual bool IsUnit(const Element &a) const =0;
+
+	/// \brief Retrieves the multiplicative identity
+	/// \return the multiplicative identity
+	virtual const Element& MultiplicativeIdentity() const =0;
+
+	/// \brief Multiplies elements in the group
+	/// \param a the multiplicand
+	/// \param b the multiplier
+	/// \return the product of a and b
+	virtual const Element& Multiply(const Element &a, const Element &b) const =0;
+
+	/// \brief Calculate the multiplicative inverse of an element in the group
+	/// \param a the element
+	virtual const Element& MultiplicativeInverse(const Element &a) const =0;
+
+	/// \brief Square an element in the group
+	/// \param a the element
+	/// \return the element squared
+	virtual const Element& Square(const Element &a) const;
+
+	/// \brief Divides elements in the group
+	/// \param a the dividend
+	/// \param b the divisor
+	/// \return the quotient
+	virtual const Element& Divide(const Element &a, const Element &b) const;
+
+	/// \brief Raises a base to an exponent in the group
+	/// \param a the base
+	/// \param e the exponent
+	/// \return the exponentiation
+	virtual Element Exponentiate(const Element &a, const Integer &e) const;
+
+	/// \brief TODO
+	/// \param x first element
+	/// \param e1 first exponent
+	/// \param y second element
+	/// \param e2 second exponent
+	/// \return TODO
+	virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
+
+	/// \brief Exponentiates a base to multiple exponents in the Ring
+	/// \param results an array of Elements
+	/// \param base the base to raise to the exponents
+	/// \param exponents an array of exponents
+	/// \param exponentsCount the number of exponents in the array
+	/// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the
+	///   result at the respective position in the results array.
+	/// \details SimultaneousExponentiate() must be implemented in a derived class.
+	/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
+	/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
+	virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
+
+	/// \brief Retrieves the multiplicative group
+	/// \return the multiplicative group
+	virtual const AbstractGroup<T>& MultiplicativeGroup() const
+		{return m_mg;}
+
+private:
+	class MultiplicativeGroupT : public AbstractGroup<T>
+	{
+	public:
+		const AbstractRing<T>& GetRing() const
+			{return *m_pRing;}
+
+		bool Equal(const Element &a, const Element &b) const
+			{return GetRing().Equal(a, b);}
+
+		const Element& Identity() const
+			{return GetRing().MultiplicativeIdentity();}
+
+		const Element& Add(const Element &a, const Element &b) const
+			{return GetRing().Multiply(a, b);}
+
+		Element& Accumulate(Element &a, const Element &b) const
+			{return a = GetRing().Multiply(a, b);}
+
+		const Element& Inverse(const Element &a) const
+			{return GetRing().MultiplicativeInverse(a);}
+
+		const Element& Subtract(const Element &a, const Element &b) const
+			{return GetRing().Divide(a, b);}
+
+		Element& Reduce(Element &a, const Element &b) const
+			{return a = GetRing().Divide(a, b);}
+
+		const Element& Double(const Element &a) const
+			{return GetRing().Square(a);}
+
+		Element ScalarMultiply(const Element &a, const Integer &e) const
+			{return GetRing().Exponentiate(a, e);}
+
+		Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
+			{return GetRing().CascadeExponentiate(x, e1, y, e2);}
+
+		void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const
+			{GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);}
+
+		const AbstractRing<T> *m_pRing;
+	};
+
+	MultiplicativeGroupT m_mg;
+};
+
+// ********************************************************
+
+/// \brief Base and exponent
+/// \tparam T base class or type
+/// \tparam E exponent class or type
+template <class T, class E = Integer>
+struct BaseAndExponent
+{
+public:
+	BaseAndExponent() {}
+	BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {}
+	bool operator<(const BaseAndExponent<T, E> &rhs) const {return exponent < rhs.exponent;}
+	T base;
+	E exponent;
+};
+
+// VC60 workaround: incomplete member template support
+template <class Element, class Iterator>
+	Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end);
+template <class Element, class Iterator>
+	Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end);
+
+// ********************************************************
+
+/// \brief Abstract Euclidean domain
+/// \tparam T element class or type
+/// \details <tt>const Element&</tt> returned by member functions are references
+///   to internal data members. Since each object may have only
+///   one such data member for holding results, the following code
+///   will produce incorrect results:
+///   <pre>    abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
+///   But this should be fine:
+///   <pre>    abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
+template <class T> class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing<T>
+{
+public:
+	typedef T Element;
+
+	/// \brief Performs the division algorithm on two elements in the ring
+	/// \param r the remainder
+	/// \param q the quotient
+	/// \param a the dividend
+	/// \param d the divisor
+	virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0;
+
+	/// \brief Performs a modular reduction in the ring
+	/// \param a the element
+	/// \param b the modulus
+	/// \return the result of <tt>a%b</tt>.
+	virtual const Element& Mod(const Element &a, const Element &b) const =0;
+
+	/// \brief Calculates the greatest common denominator in the ring
+	/// \param a the first element
+	/// \param b the second element
+	/// \return the greatest common denominator of a and b.
+	virtual const Element& Gcd(const Element &a, const Element &b) const;
+
+protected:
+	mutable Element result;
+};
+
+// ********************************************************
+
+/// \brief Euclidean domain
+/// \tparam T element class or type
+/// \details <tt>const Element&</tt> returned by member functions are references
+///   to internal data members. Since each object may have only
+///   one such data member for holding results, the following code
+///   will produce incorrect results:
+///   <pre>    abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
+///   But this should be fine:
+///   <pre>    abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
+template <class T> class EuclideanDomainOf : public AbstractEuclideanDomain<T>
+{
+public:
+	typedef T Element;
+
+	EuclideanDomainOf() {}
+
+	bool Equal(const Element &a, const Element &b) const
+		{return a==b;}
+
+	const Element& Identity() const
+		{return Element::Zero();}
+
+	const Element& Add(const Element &a, const Element &b) const
+		{return result = a+b;}
+
+	Element& Accumulate(Element &a, const Element &b) const
+		{return a+=b;}
+
+	const Element& Inverse(const Element &a) const
+		{return result = -a;}
+
+	const Element& Subtract(const Element &a, const Element &b) const
+		{return result = a-b;}
+
+	Element& Reduce(Element &a, const Element &b) const
+		{return a-=b;}
+
+	const Element& Double(const Element &a) const
+		{return result = a.Doubled();}
+
+	const Element& MultiplicativeIdentity() const
+		{return Element::One();}
+
+	const Element& Multiply(const Element &a, const Element &b) const
+		{return result = a*b;}
+
+	const Element& Square(const Element &a) const
+		{return result = a.Squared();}
+
+	bool IsUnit(const Element &a) const
+		{return a.IsUnit();}
+
+	const Element& MultiplicativeInverse(const Element &a) const
+		{return result = a.MultiplicativeInverse();}
+
+	const Element& Divide(const Element &a, const Element &b) const
+		{return result = a/b;}
+
+	const Element& Mod(const Element &a, const Element &b) const
+		{return result = a%b;}
+
+	void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const
+		{Element::Divide(r, q, a, d);}
+
+	bool operator==(const EuclideanDomainOf<T> &rhs) const
+		{CRYPTOPP_UNUSED(rhs); return true;}
+
+private:
+	mutable Element result;
+};
+
+/// \brief Quotient ring
+/// \tparam T element class or type
+/// \details <tt>const Element&</tt> returned by member functions are references
+///   to internal data members. Since each object may have only
+///   one such data member for holding results, the following code
+///   will produce incorrect results:
+///   <pre>    abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
+///   But this should be fine:
+///   <pre>    abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
+template <class T> class QuotientRing : public AbstractRing<typename T::Element>
+{
+public:
+	typedef T EuclideanDomain;
+	typedef typename T::Element Element;
+
+	QuotientRing(const EuclideanDomain &domain, const Element &modulus)
+		: m_domain(domain), m_modulus(modulus) {}
+
+	const EuclideanDomain & GetDomain() const
+		{return m_domain;}
+
+	const Element& GetModulus() const
+		{return m_modulus;}
+
+	bool Equal(const Element &a, const Element &b) const
+		{return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());}
+
+	const Element& Identity() const
+		{return m_domain.Identity();}
+
+	const Element& Add(const Element &a, const Element &b) const
+		{return m_domain.Add(a, b);}
+
+	Element& Accumulate(Element &a, const Element &b) const
+		{return m_domain.Accumulate(a, b);}
+
+	const Element& Inverse(const Element &a) const
+		{return m_domain.Inverse(a);}
+
+	const Element& Subtract(const Element &a, const Element &b) const
+		{return m_domain.Subtract(a, b);}
+
+	Element& Reduce(Element &a, const Element &b) const
+		{return m_domain.Reduce(a, b);}
+
+	const Element& Double(const Element &a) const
+		{return m_domain.Double(a);}
+
+	bool IsUnit(const Element &a) const
+		{return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));}
+
+	const Element& MultiplicativeIdentity() const
+		{return m_domain.MultiplicativeIdentity();}
+
+	const Element& Multiply(const Element &a, const Element &b) const
+		{return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);}
+
+	const Element& Square(const Element &a) const
+		{return m_domain.Mod(m_domain.Square(a), m_modulus);}
+
+	const Element& MultiplicativeInverse(const Element &a) const;
+
+	bool operator==(const QuotientRing<T> &rhs) const
+		{return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;}
+
+protected:
+	EuclideanDomain m_domain;
+	Element m_modulus;
+};
+
+NAMESPACE_END
+
+#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
+#include "algebra.cpp"
+#endif
+
+#endif

+ 520 - 0
cryptopp/algparam.h

@@ -0,0 +1,520 @@
+// algparam.h - originally written and placed in the public domain by Wei Dai
+
+/// \file algparam.h
+/// \brief Classes for working with NameValuePairs
+
+#ifndef CRYPTOPP_ALGPARAM_H
+#define CRYPTOPP_ALGPARAM_H
+
+#include "config.h"
+#include "cryptlib.h"
+
+#include "smartptr.h"
+#include "secblock.h"
+#include "integer.h"
+#include "misc.h"
+
+#include <string>
+#include <typeinfo>
+#include <exception>
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Used to pass byte array input as part of a NameValuePairs object
+class ConstByteArrayParameter
+{
+public:
+	/// \brief Construct a ConstByteArrayParameter
+	/// \param data a C-String
+	/// \param deepCopy flag indicating whether the data should be copied
+	/// \details The deepCopy option is used when the NameValuePairs object can't
+	///   keep a copy of the data available
+	ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false)
+		: m_deepCopy(false), m_data(NULLPTR), m_size(0)
+	{
+		Assign(reinterpret_cast<const byte *>(data), data ? strlen(data) : 0, deepCopy);
+	}
+
+	/// \brief Construct a ConstByteArrayParameter
+	/// \param data a memory buffer
+	/// \param size the length of the memory buffer
+	/// \param deepCopy flag indicating whether the data should be copied
+	/// \details The deepCopy option is used when the NameValuePairs object can't
+	///   keep a copy of the data available
+	ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
+		: m_deepCopy(false), m_data(NULLPTR), m_size(0)
+	{
+		Assign(data, size, deepCopy);
+	}
+
+	/// \brief Construct a ConstByteArrayParameter
+	/// \tparam T a std::basic_string<char> or std::vector<byte> class
+	/// \param string a std::basic_string<char> or std::vector<byte> object
+	/// \param deepCopy flag indicating whether the data should be copied
+	/// \details The deepCopy option is used when the NameValuePairs object can't
+	///   keep a copy of the data available
+	template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
+		: m_deepCopy(false), m_data(NULLPTR), m_size(0)
+	{
+		CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1);
+		Assign(reinterpret_cast<const byte *>(&string[0]), string.size(), deepCopy);
+	}
+
+	/// \brief Assign contents from a memory buffer
+	/// \param data a memory buffer
+	/// \param size the length of the memory buffer
+	/// \param deepCopy flag indicating whether the data should be copied
+	/// \details The deepCopy option is used when the NameValuePairs object can't
+	///   keep a copy of the data available
+	void Assign(const byte *data, size_t size, bool deepCopy)
+	{
+		// This fires, which means: no data with a size, or data with no size.
+		// CRYPTOPP_ASSERT((data && size) || !(data || size));
+		if (deepCopy)
+			m_block.Assign(data, size);
+		else
+		{
+			m_data = data;
+			m_size = size;
+		}
+		m_deepCopy = deepCopy;
+	}
+
+	/// \brief Pointer to the first byte in the memory block
+	const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
+	/// \brief Pointer beyond the last byte in the memory block
+	const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
+	/// \brief Length of the memory block
+	size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
+
+private:
+	bool m_deepCopy;
+	const byte *m_data;
+	size_t m_size;
+	SecByteBlock m_block;
+};
+
+/// \brief Used to pass byte array input as part of a NameValuePairs object
+class ByteArrayParameter
+{
+public:
+	/// \brief Construct a ByteArrayParameter
+	/// \param data a memory buffer
+	/// \param size the length of the memory buffer
+	ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0)
+		: m_data(data), m_size(size) {}
+
+	/// \brief Construct a ByteArrayParameter
+	/// \param block a SecByteBlock
+	ByteArrayParameter(SecByteBlock &block)
+		: m_data(block.begin()), m_size(block.size()) {}
+
+	/// \brief Pointer to the first byte in the memory block
+	byte *begin() const {return m_data;}
+	/// \brief Pointer beyond the last byte in the memory block
+	byte *end() const {return m_data + m_size;}
+	/// \brief Length of the memory block
+	size_t size() const {return m_size;}
+
+private:
+	byte *m_data;
+	size_t m_size;
+};
+
+/// \brief Combines two sets of NameValuePairs
+/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs.
+///   If a name is not found in the first set, then the second set is searched for the
+///   name and value pair. The second set of NameValuePairs often provides default values.
+class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs
+{
+public:
+	/// \brief Construct a CombinedNameValuePairs
+	/// \param pairs1 reference to the first set of NameValuePairs
+	/// \param pairs2 reference to the second set of NameValuePairs
+	CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2)
+		: m_pairs1(pairs1), m_pairs2(pairs2) {}
+
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+
+private:
+	const NameValuePairs &m_pairs1, &m_pairs2;
+};
+
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+template <class T, class BASE>
+class GetValueHelperClass
+{
+public:
+	GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst)
+		: m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false)
+	{
+		if (strcmp(m_name, "ValueNames") == 0)
+		{
+			m_found = m_getValueNames = true;
+			NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType);
+			if (searchFirst)
+				searchFirst->GetVoidValue(m_name, valueType, pValue);
+			if (typeid(T) != typeid(BASE))
+				pObject->BASE::GetVoidValue(m_name, valueType, pValue);
+			((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';';
+		}
+
+		if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
+		{
+			NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
+			*reinterpret_cast<const T **>(pValue) = pObject;
+			m_found = true;
+			return;
+		}
+
+		if (!m_found && searchFirst)
+			m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
+
+		if (!m_found && typeid(T) != typeid(BASE))
+			m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
+	}
+
+	operator bool() const {return m_found;}
+
+	template <class R>
+	GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
+	{
+		if (m_getValueNames)
+			(*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
+		if (!m_found && strcmp(name, m_name) == 0)
+		{
+			NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
+			*reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
+			m_found = true;
+		}
+		return *this;
+	}
+
+	GetValueHelperClass<T,BASE> &Assignable()
+	{
+#ifndef __INTEL_COMPILER	// ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason
+		if (m_getValueNames)
+			((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';';
+		if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0)
+		{
+			NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType);
+			*reinterpret_cast<T *>(m_pValue) = *m_pObject;
+			m_found = true;
+		}
+#endif
+		return *this;
+	}
+
+private:
+	const T *m_pObject;
+	const char *m_name;
+	const std::type_info *m_valueType;
+	void *m_pValue;
+	bool m_found, m_getValueNames;
+};
+
+template <class BASE, class T>
+GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
+{
+	return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst);
+}
+
+template <class T>
+GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
+{
+	return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst);
+}
+
+// ********************************************************
+
+template <class T, class BASE>
+class AssignFromHelperClass
+{
+public:
+	AssignFromHelperClass(T *pObject, const NameValuePairs &source)
+		: m_pObject(pObject), m_source(source), m_done(false)
+	{
+		if (source.GetThisObject(*pObject))
+			m_done = true;
+		else if (typeid(BASE) != typeid(T))
+			pObject->BASE::AssignFrom(source);
+	}
+
+	template <class R>
+	AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
+	{
+		if (!m_done)
+		{
+			R value;
+			if (!m_source.GetValue(name, value))
+				throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
+			(m_pObject->*pm)(value);
+		}
+		return *this;
+	}
+
+	template <class R, class S>
+	AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
+	{
+		if (!m_done)
+		{
+			R value1;
+			if (!m_source.GetValue(name1, value1))
+				throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
+			S value2;
+			if (!m_source.GetValue(name2, value2))
+				throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
+			(m_pObject->*pm)(value1, value2);
+		}
+		return *this;
+	}
+
+private:
+	T *m_pObject;
+	const NameValuePairs &m_source;
+	bool m_done;
+};
+
+template <class BASE, class T>
+AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source)
+{
+	return AssignFromHelperClass<T, BASE>(pObject, source);
+}
+
+template <class T>
+AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source)
+{
+	return AssignFromHelperClass<T, T>(pObject, source);
+}
+
+#endif // CRYPTOPP_DOXYGEN_PROCESSING
+
+// ********************************************************
+
+#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
+// Allow the linker to discard Integer code if not needed.
+// Also see http://github.com/weidai11/cryptopp/issues/389.
+CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt);
+#endif
+
+CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
+
+/// \brief Base class for AlgorithmParameters
+class CRYPTOPP_DLL AlgorithmParametersBase
+{
+public:
+	/// \brief Exception thrown when an AlgorithmParameter is unused
+	class ParameterNotUsed : public Exception
+	{
+	public:
+		ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {}
+	};
+
+	virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
+	{
+
+#if defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
+		if (std::uncaught_exceptions() == 0)
+#elif defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
+		if (std::uncaught_exception() == false)
+#else
+		try
+#endif
+		{
+			if (m_throwIfNotUsed && !m_used)
+				throw ParameterNotUsed(m_name);
+		}
+#if !defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
+# if !defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
+		catch(const Exception&)
+		{
+		}
+# endif
+#endif
+	}
+
+	// this is actually a move, not a copy
+	AlgorithmParametersBase(const AlgorithmParametersBase &x)
+		: m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
+	{
+		m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
+		x.m_used = true;
+	}
+
+	/// \brief Construct a AlgorithmParametersBase
+	/// \param name the parameter name
+	/// \param throwIfNotUsed flags indicating whether an exception should be thrown
+	/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
+	///   will be thrown in the destructor if the parameter is not not retrieved.
+	AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
+		: m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
+
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+
+protected:
+	friend class AlgorithmParameters;
+	void operator=(const AlgorithmParametersBase& rhs);  // assignment not allowed, declare this for VC60
+
+	virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
+	virtual void MoveInto(void *p) const =0;	// not really const
+
+	const char *m_name;
+	bool m_throwIfNotUsed;
+	mutable bool m_used;
+	member_ptr<AlgorithmParametersBase> m_next;
+};
+
+/// \brief Template base class for AlgorithmParameters
+/// \tparam T the class or type
+template <class T>
+class AlgorithmParametersTemplate : public AlgorithmParametersBase
+{
+public:
+	/// \brief Construct an AlgorithmParametersTemplate
+	/// \param name the name of the value
+	/// \param value a reference to the value
+	/// \param throwIfNotUsed flags indicating whether an exception should be thrown
+	/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
+	///   will be thrown in the destructor if the parameter is not not retrieved.
+	AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed)
+		: AlgorithmParametersBase(name, throwIfNotUsed), m_value(value)
+	{
+	}
+
+	void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
+	{
+#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
+		// Special case for retrieving an Integer parameter when an int was passed in
+		if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value)))
+#endif
+		{
+			NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType);
+			*reinterpret_cast<T *>(pValue) = m_value;
+		}
+	}
+
+#if defined(DEBUG_NEW) && (CRYPTOPP_MSC_VERSION >= 1300)
+# pragma push_macro("new")
+# undef new
+#endif
+
+	void MoveInto(void *buffer) const
+	{
+		AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
+		CRYPTOPP_UNUSED(p);	// silence warning
+	}
+
+#if defined(DEBUG_NEW) && (CRYPTOPP_MSC_VERSION >= 1300)
+# pragma pop_macro("new")
+#endif
+
+protected:
+	T m_value;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<bool>;
+CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<int>;
+CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<ConstByteArrayParameter>;
+
+/// \brief An object that implements NameValuePairs
+/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
+///   repeatedly using operator() on the object returned by MakeParameters, for example:
+///   <pre>
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   </pre>
+class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs
+{
+public:
+	/// \brief Construct a AlgorithmParameters
+	/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
+	///   repeatedly using operator() on the object returned by MakeParameters, for example:
+	///   <pre>
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   </pre>
+	AlgorithmParameters();
+
+#ifdef __BORLANDC__
+	/// \brief Construct a AlgorithmParameters
+	/// \tparam T the class or type
+	/// \param name the name of the object or value to retrieve
+	/// \param value reference to a variable that receives the value
+	/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
+	/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
+	///   such as MSVC 7.0 and earlier.
+	/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
+	///   repeatedly using operator() on the object returned by MakeParameters, for example:
+	///   <pre>
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   </pre>
+	template <class T>
+	AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true)
+		: m_next(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed))
+		, m_defaultThrowIfNotUsed(throwIfNotUsed)
+	{
+	}
+#endif
+
+	AlgorithmParameters(const AlgorithmParameters &x);
+
+	AlgorithmParameters & operator=(const AlgorithmParameters &x);
+
+	/// \tparam T the class or type
+	/// \param name the name of the object or value to retrieve
+	/// \param value reference to a variable that receives the value
+	/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
+	template <class T>
+	AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
+	{
+		member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
+		p->m_next.reset(m_next.release());
+		m_next.reset(p.release());
+		m_defaultThrowIfNotUsed = throwIfNotUsed;
+		return *this;
+	}
+
+	/// \brief Appends a NameValuePair to a collection of NameValuePairs
+	/// \tparam T the class or type
+	/// \param name the name of the object or value to retrieve
+	/// \param value reference to a variable that receives the value
+	template <class T>
+	AlgorithmParameters & operator()(const char *name, const T &value)
+	{
+		return operator()(name, value, m_defaultThrowIfNotUsed);
+	}
+
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+
+protected:
+	member_ptr<AlgorithmParametersBase> m_next;
+	bool m_defaultThrowIfNotUsed;
+};
+
+/// \brief Create an object that implements NameValuePairs
+/// \tparam T the class or type
+/// \param name the name of the object or value to retrieve
+/// \param value reference to a variable that receives the value
+/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
+/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
+///   such as MSVC 7.0 and earlier.
+/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
+///   repeatedly using \p operator() on the object returned by \p MakeParameters, for example:
+///   <pre>
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   </pre>
+#ifdef __BORLANDC__
+typedef AlgorithmParameters MakeParameters;
+#else
+template <class T>
+AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true)
+{
+	return AlgorithmParameters()(name, value, throwIfNotUsed);
+}
+#endif
+
+#define CRYPTOPP_GET_FUNCTION_ENTRY(name)		(Name::name(), &ThisClass::Get##name)
+#define CRYPTOPP_SET_FUNCTION_ENTRY(name)		(Name::name(), &ThisClass::Set##name)
+#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2)	(Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
+
+NAMESPACE_END
+
+#endif

+ 74 - 0
cryptopp/allocate.h

@@ -0,0 +1,74 @@
+// allocate.h - written and placed in the public domain by Jeffrey Walton
+
+// The functions in allocate.h and allocate.cpp were originally in misc.h
+// and misc.cpp. They were extracted in September 2019 to sidestep a circular
+// dependency with misc.h and secblock.h.
+
+/// \file allocate.h
+/// \brief Functions for allocating aligned buffers
+
+#ifndef CRYPTOPP_ALLOCATE_H
+#define CRYPTOPP_ALLOCATE_H
+
+#include "config.h"
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Attempts to reclaim unused memory
+/// \throw bad_alloc
+/// \details In the normal course of running a program, a request for memory
+///  normally succeeds. If a call to AlignedAllocate or UnalignedAllocate fails,
+///  then CallNewHandler is called in n effort to recover. Internally,
+///  CallNewHandler calls set_new_handler(nullptr) in an effort to free memory.
+///  There is no guarantee CallNewHandler will be able to obtain more memory so
+///  an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler
+///  throws a bad_alloc exception.
+/// \throw bad_alloc on failure
+/// \since Crypto++ 5.0
+/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate
+CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler();
+
+/// \brief Allocates a buffer on 16-byte boundary
+/// \param size the size of the buffer
+/// \details AlignedAllocate is primarily used when the data will be
+///  processed by SSE, NEON, ARMv8 or PowerPC instructions. The assembly
+///  language routines rely on the alignment. If the alignment is not
+///  respected, then a SIGBUS could be generated on Unix and Linux, and an
+///  EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows.
+/// \details Formerly, AlignedAllocate and AlignedDeallocate were only
+///  available on certain platforms when CRYTPOPP_DISABLE_ASM was not in
+///  effect. However, Android and iOS debug simulator builds got into a
+///  state where the aligned allocator was not available and caused link
+///  failures.
+/// \since AlignedAllocate for SIMD since Crypto++ 1.0, AlignedAllocate
+///  for all builds since Crypto++ 8.1
+/// \sa AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
+///  <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
+CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size);
+
+/// \brief Frees a buffer allocated with AlignedAllocate
+/// \param ptr the buffer to free
+/// \since AlignedDeallocate for SIMD since Crypto++ 1.0, AlignedAllocate
+///  for all builds since Crypto++ 8.1
+/// \sa AlignedAllocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
+///  <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
+CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr);
+
+/// \brief Allocates a buffer
+/// \param size the size of the buffer
+/// \since Crypto++ 1.0
+/// \sa AlignedAllocate, AlignedDeallocate, UnalignedDeallocate, CallNewHandler,
+///  <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
+CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size);
+
+/// \brief Frees a buffer allocated with UnalignedAllocate
+/// \param ptr the buffer to free
+/// \since Crypto++ 1.0
+/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, CallNewHandler,
+///  <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
+CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr);
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_ALLOCATE_H

+ 89 - 0
cryptopp/arc4.h

@@ -0,0 +1,89 @@
+// arc4.h - originally written and placed in the public domain by Wei Dai
+
+/// \file arc4.h
+/// \brief Classes for ARC4 cipher
+/// \since Crypto++ 3.1
+
+#ifndef CRYPTOPP_ARC4_H
+#define CRYPTOPP_ARC4_H
+
+#include "cryptlib.h"
+#include "strciphr.h"
+#include "secblock.h"
+#include "smartptr.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+namespace Weak1 {
+
+/// \brief ARC4 base class
+/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions
+/// \since Crypto++ 3.1
+class CRYPTOPP_NO_VTABLE ARC4_Base : public VariableKeyLength<16, 1, 256>, public RandomNumberGenerator, public SymmetricCipher, public SymmetricCipherDocumentation
+{
+public:
+	~ARC4_Base();
+
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARC4";}
+
+	void GenerateBlock(byte *output, size_t size);
+	void DiscardBytes(size_t n);
+
+    void ProcessData(byte *outString, const byte *inString, size_t length);
+
+	bool IsRandomAccess() const {return false;}
+	bool IsSelfInverting() const {return true;}
+	bool IsForwardTransformation() const {return true;}
+
+	typedef SymmetricCipherFinal<ARC4_Base> Encryption;
+	typedef SymmetricCipherFinal<ARC4_Base> Decryption;
+
+protected:
+	void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
+	virtual unsigned int GetDefaultDiscardBytes() const {return 0;}
+
+    FixedSizeSecBlock<byte, 256> m_state;
+    byte m_x, m_y;
+};
+
+/// \brief Alleged RC4
+/// \sa <a href="http://www.cryptopp.com/wiki/RC4">Alleged RC4</a>
+/// \since Crypto++ 3.1
+DOCUMENTED_TYPEDEF(SymmetricCipherFinal<ARC4_Base>, ARC4);
+
+/// \brief MARC4 base class
+/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions
+/// \details MARC4 discards the first 256 bytes of keystream, which may be weaker than the rest
+/// \since Crypto++ 3.1
+class CRYPTOPP_NO_VTABLE MARC4_Base : public ARC4_Base
+{
+public:
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARC4";}
+
+	typedef SymmetricCipherFinal<MARC4_Base> Encryption;
+	typedef SymmetricCipherFinal<MARC4_Base> Decryption;
+
+protected:
+	unsigned int GetDefaultDiscardBytes() const {return 256;}
+};
+
+/// \brief Modified Alleged RC4
+/// \sa <a href="http://www.cryptopp.com/wiki/RC4">Alleged RC4</a>
+/// \since Crypto++ 3.1
+DOCUMENTED_TYPEDEF(SymmetricCipherFinal<MARC4_Base>, MARC4);
+
+}
+#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1
+namespace Weak {using namespace Weak1;}		// import Weak1 into CryptoPP::Weak
+#else
+using namespace Weak1;	// import Weak1 into CryptoPP with warning
+#ifdef __GNUC__
+#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning."
+#else
+#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.")
+#endif
+#endif
+
+NAMESPACE_END
+
+#endif

+ 99 - 0
cryptopp/argnames.h

@@ -0,0 +1,99 @@
+// argnames.h - originally written and placed in the public domain by Wei Dai
+
+/// \file argnames.h
+/// \brief Standard names for retrieving values by name when working with \p NameValuePairs
+
+#ifndef CRYPTOPP_ARGNAMES_H
+#define CRYPTOPP_ARGNAMES_H
+
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+DOCUMENTED_NAMESPACE_BEGIN(Name)
+
+#define CRYPTOPP_DEFINE_NAME_STRING(name)	inline const char *name() {return #name;}
+
+CRYPTOPP_DEFINE_NAME_STRING(ValueNames)			///< string, a list of value names with a semicolon (';') after each name
+CRYPTOPP_DEFINE_NAME_STRING(Version)			///< int
+CRYPTOPP_DEFINE_NAME_STRING(Seed)				///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Key)				///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(IV)					///< ConstByteArrayParameter, also accepts const byte * for backwards compatibility
+CRYPTOPP_DEFINE_NAME_STRING(StolenIV)			///< byte *
+CRYPTOPP_DEFINE_NAME_STRING(Nonce)				///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Rounds)				///< int
+CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize)		///< int
+CRYPTOPP_DEFINE_NAME_STRING(WordSize)			///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(BlockSize)			///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength)	///< int, in bits
+CRYPTOPP_DEFINE_NAME_STRING(KeySize)			///< int, in bits
+CRYPTOPP_DEFINE_NAME_STRING(ModulusSize)		///< int, in bits
+CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize)	///< int, in bits
+CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)///< int, in bits
+CRYPTOPP_DEFINE_NAME_STRING(Modulus)			///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(PublicExponent)		///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(PublicElement)		///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder)		///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(Cofactor)			///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator)	///< Integer, ECP::Point, or EC2N::Point
+CRYPTOPP_DEFINE_NAME_STRING(Curve)				///< ECP or EC2N
+CRYPTOPP_DEFINE_NAME_STRING(GroupOID)			///< OID
+CRYPTOPP_DEFINE_NAME_STRING(PointerToPrimeSelector)		///< const PrimeSelector *
+CRYPTOPP_DEFINE_NAME_STRING(Prime1)				///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(Prime2)				///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2)	///< Integer
+CRYPTOPP_DEFINE_NAME_STRING(PutMessage)			///< bool
+CRYPTOPP_DEFINE_NAME_STRING(TruncatedDigestSize)	///< int
+CRYPTOPP_DEFINE_NAME_STRING(BlockPaddingScheme)	///< StreamTransformationFilter::BlockPaddingScheme
+CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags)		///< word32
+CRYPTOPP_DEFINE_NAME_STRING(AuthenticatedDecryptionFilterFlags)	///< word32
+CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags)	///< word32
+CRYPTOPP_DEFINE_NAME_STRING(InputBuffer)		///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer)		///< ByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(InputFileName)		///< const char *
+CRYPTOPP_DEFINE_NAME_STRING(InputFileNameWide)	///< const wchar_t *
+CRYPTOPP_DEFINE_NAME_STRING(InputStreamPointer)	///< std::istream *
+CRYPTOPP_DEFINE_NAME_STRING(InputBinaryMode)	///< bool
+CRYPTOPP_DEFINE_NAME_STRING(OutputFileName)		///< const char *
+CRYPTOPP_DEFINE_NAME_STRING(OutputFileNameWide)	///< const wchar_t *
+CRYPTOPP_DEFINE_NAME_STRING(OutputStreamPointer)	///< std::ostream *
+CRYPTOPP_DEFINE_NAME_STRING(OutputBinaryMode)	///< bool
+CRYPTOPP_DEFINE_NAME_STRING(EncodingParameters)	///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(KeyDerivationParameters)	///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Separator)			///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Terminator)			///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Uppercase)			///< bool
+CRYPTOPP_DEFINE_NAME_STRING(GroupSize)			///< int
+CRYPTOPP_DEFINE_NAME_STRING(Pad)				///< bool
+CRYPTOPP_DEFINE_NAME_STRING(PaddingByte)		///< byte
+CRYPTOPP_DEFINE_NAME_STRING(Log2Base)			///< int
+CRYPTOPP_DEFINE_NAME_STRING(EncodingLookupArray)	///< const byte *
+CRYPTOPP_DEFINE_NAME_STRING(DecodingLookupArray)	///< const byte *
+CRYPTOPP_DEFINE_NAME_STRING(InsertLineBreaks)	///< bool
+CRYPTOPP_DEFINE_NAME_STRING(MaxLineLength)		///< int
+CRYPTOPP_DEFINE_NAME_STRING(DigestSize)			///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(L1KeyLength)		///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(TableSize)			///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(Blinding)			///< bool, timing attack mitigations, ON by default
+CRYPTOPP_DEFINE_NAME_STRING(DerivedKey)			///< ByteArrayParameter, key derivation, derived key
+CRYPTOPP_DEFINE_NAME_STRING(DerivedKeyLength)	///< int, key derivation, derived key length in bytes
+CRYPTOPP_DEFINE_NAME_STRING(Personalization)	///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(PersonalizationSize)	///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(Salt)				///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(Tweak)				///< ConstByteArrayParameter
+CRYPTOPP_DEFINE_NAME_STRING(SaltSize)			///< int, in bytes
+CRYPTOPP_DEFINE_NAME_STRING(TreeMode)			///< byte
+CRYPTOPP_DEFINE_NAME_STRING(FileName)			///< const char *
+CRYPTOPP_DEFINE_NAME_STRING(FileTime)			///< int
+CRYPTOPP_DEFINE_NAME_STRING(Comment)			///< const char *
+CRYPTOPP_DEFINE_NAME_STRING(Identity)			///< ConstByteArrayParameter
+DOCUMENTED_NAMESPACE_END
+
+NAMESPACE_END
+
+#endif

+ 71 - 0
cryptopp/aria.h

@@ -0,0 +1,71 @@
+// aria.h - written and placed in the public domain by Jeffrey Walton
+
+/// \file aria.h
+/// \brief Classes for the ARIA block cipher
+/// \details The Crypto++ ARIA implementation is based on the 32-bit implementation by Aaram Yun
+///   from the National Security Research Institute, KOREA. Aaram Yun's implementation is based on
+///   the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from the Korea
+///   Internet & Security Agency website.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc5794">RFC 5794, A Description of the ARIA Encryption Algorithm</A>,
+///   <A HREF="http://seed.kisa.or.kr/iwt/ko/bbs/EgovReferenceList.do?bbsId=BBSMSTR_000000000002">Korea
+///   Internet & Security Agency homepage</A>
+
+#ifndef CRYPTOPP_ARIA_H
+#define CRYPTOPP_ARIA_H
+
+#include "config.h"
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief ARIA block cipher information
+/// \since Crypto++ 6.0
+struct ARIA_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARIA";}
+};
+
+/// \brief ARIA block cipher
+/// \details The Crypto++ ARIA implementation is based on the 32-bit implementation by Aaram Yun
+///   from the National Security Research Institute, KOREA. Aaram Yun's implementation is based on
+///   the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from the Korea
+///   Internet & Security Agency website.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc5794">RFC 5794, A Description of the ARIA Encryption Algorithm</A>,
+///   <A HREF="http://seed.kisa.or.kr/iwt/ko/bbs/EgovReferenceList.do?bbsId=BBSMSTR_000000000002">Korea
+///   Internet & Security Agency homepage</A>
+/// \sa <a href="http://www.cryptopp.com/wiki/ARIA">ARIA</a>
+/// \since Crypto++ 6.0
+class ARIA : public ARIA_Info, public BlockCipherDocumentation
+{
+public:
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<ARIA_Info>
+	{
+	public:
+		Base() : m_rounds(0) {}
+
+	protected:
+		void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	private:
+		// Reference implementation allocates a table of 17 round keys.
+		typedef SecBlock<byte, AllocatorWithCleanup<byte, true> >     AlignedByteBlock;
+		typedef SecBlock<word32, AllocatorWithCleanup<word32, true> > AlignedWordBlock;
+
+		AlignedWordBlock  m_rk;  // round keys
+		AlignedWordBlock  m_w;   // w0, w1, w2, w3, t and u
+		unsigned int m_rounds;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+typedef ARIA::Encryption ARIAEncryption;
+typedef ARIA::Decryption ARIADecryption;
+
+NAMESPACE_END
+
+#endif

+ 427 - 0
cryptopp/arm_simd.h

@@ -0,0 +1,427 @@
+// arm_simd.h - written and placed in public domain by Jeffrey Walton
+
+/// \file arm_simd.h
+/// \brief Support functions for ARM and vector operations
+
+#ifndef CRYPTOPP_ARM_SIMD_H
+#define CRYPTOPP_ARM_SIMD_H
+
+#include "config.h"
+
+#if (CRYPTOPP_ARM_NEON_HEADER)
+# include <stdint.h>
+# include <arm_neon.h>
+#endif
+
+#if (CRYPTOPP_ARM_ACLE_HEADER)
+# include <stdint.h>
+# include <arm_acle.h>
+#endif
+
+#if (CRYPTOPP_ARM_CRC32_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+///	\name CRC32 checksum
+//@{
+
+/// \brief CRC32 checksum
+/// \param crc the starting crc value
+/// \param val the value to checksum
+/// \return CRC32 value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32B (uint32_t crc, uint8_t val)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32b(crc, val);
+#else
+    __asm__ ("crc32b   %w0, %w0, %w1   \n\t"
+            :"+r" (crc) : "r" (val) );
+    return crc;
+#endif
+}
+
+/// \brief CRC32 checksum
+/// \param crc the starting crc value
+/// \param val the value to checksum
+/// \return CRC32 value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32W (uint32_t crc, uint32_t val)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32w(crc, val);
+#else
+    __asm__ ("crc32w   %w0, %w0, %w1   \n\t"
+            :"+r" (crc) : "r" (val) );
+    return crc;
+#endif
+}
+
+/// \brief CRC32 checksum
+/// \param crc the starting crc value
+/// \param vals the values to checksum
+/// \return CRC32 value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32Wx4 (uint32_t crc, const uint32_t vals[4])
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32w(__crc32w(__crc32w(__crc32w(
+             crc, vals[0]), vals[1]), vals[2]), vals[3]);
+#else
+    __asm__ ("crc32w   %w0, %w0, %w1   \n\t"
+             "crc32w   %w0, %w0, %w2   \n\t"
+             "crc32w   %w0, %w0, %w3   \n\t"
+             "crc32w   %w0, %w0, %w4   \n\t"
+            :"+r" (crc) : "r" (vals[0]), "r" (vals[1]),
+                          "r" (vals[2]), "r" (vals[3]));
+    return crc;
+#endif
+}
+
+//@}
+///	\name CRC32-C checksum
+
+/// \brief CRC32-C checksum
+/// \param crc the starting crc value
+/// \param val the value to checksum
+/// \return CRC32-C value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32CB (uint32_t crc, uint8_t val)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32cb(crc, val);
+#else
+    __asm__ ("crc32cb   %w0, %w0, %w1   \n\t"
+            :"+r" (crc) : "r" (val) );
+    return crc;
+#endif
+}
+
+/// \brief CRC32-C checksum
+/// \param crc the starting crc value
+/// \param val the value to checksum
+/// \return CRC32-C value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32CW (uint32_t crc, uint32_t val)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32cw(crc, val);
+#else
+    __asm__ ("crc32cw   %w0, %w0, %w1   \n\t"
+            :"+r" (crc) : "r" (val) );
+    return crc;
+#endif
+}
+
+/// \brief CRC32-C checksum
+/// \param crc the starting crc value
+/// \param vals the values to checksum
+/// \return CRC32-C value
+/// \since Crypto++ 8.6
+inline uint32_t CRC32CWx4 (uint32_t crc, const uint32_t vals[4])
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+	return __crc32cw(__crc32cw(__crc32cw(__crc32cw(
+             crc, vals[0]), vals[1]), vals[2]), vals[3]);
+#else
+    __asm__ ("crc32cw   %w0, %w0, %w1   \n\t"
+             "crc32cw   %w0, %w0, %w2   \n\t"
+             "crc32cw   %w0, %w0, %w3   \n\t"
+             "crc32cw   %w0, %w0, %w4   \n\t"
+            :"+r" (crc) : "r" (vals[0]), "r" (vals[1]),
+                          "r" (vals[2]), "r" (vals[3]));
+    return crc;
+#endif
+}
+//@}
+#endif  // CRYPTOPP_ARM_CRC32_AVAILABLE
+
+#if (CRYPTOPP_ARM_PMULL_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+///	\name Polynomial multiplication
+//@{
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL_00() performs polynomial multiplication and presents
+///  the result like Intel's <tt>c = _mm_clmulepi64_si128(a, b, 0x00)</tt>.
+///  The <tt>0x00</tt> indicates the low 64-bits of <tt>a</tt> and <tt>b</tt>
+///  are multiplied.
+/// \note An Intel XMM register is composed of 128-bits. The leftmost bit
+///  is MSB and numbered 127, while the rightmost bit is LSB and
+///  numbered 0.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL_00(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 0) };
+    const __n64 y = { vgetq_lane_u64(b, 0) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull    %0.1q, %1.1d, %2.1d   \n\t"
+            :"=w" (r) : "w" (a), "w" (b) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),0),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),0)));
+#endif
+}
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL_01 performs() polynomial multiplication and presents
+///  the result like Intel's <tt>c = _mm_clmulepi64_si128(a, b, 0x01)</tt>.
+///  The <tt>0x01</tt> indicates the low 64-bits of <tt>a</tt> and high
+///  64-bits of <tt>b</tt> are multiplied.
+/// \note An Intel XMM register is composed of 128-bits. The leftmost bit
+///  is MSB and numbered 127, while the rightmost bit is LSB and
+///  numbered 0.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL_01(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 0) };
+    const __n64 y = { vgetq_lane_u64(b, 1) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull    %0.1q, %1.1d, %2.1d   \n\t"
+            :"=w" (r) : "w" (a), "w" (vget_high_u64(b)) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),0),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),1)));
+#endif
+}
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL_10() performs polynomial multiplication and presents
+///  the result like Intel's <tt>c = _mm_clmulepi64_si128(a, b, 0x10)</tt>.
+///  The <tt>0x10</tt> indicates the high 64-bits of <tt>a</tt> and low
+///  64-bits of <tt>b</tt> are multiplied.
+/// \note An Intel XMM register is composed of 128-bits. The leftmost bit
+///  is MSB and numbered 127, while the rightmost bit is LSB and
+///  numbered 0.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL_10(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 1) };
+    const __n64 y = { vgetq_lane_u64(b, 0) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull    %0.1q, %1.1d, %2.1d   \n\t"
+            :"=w" (r) : "w" (vget_high_u64(a)), "w" (b) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),1),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),0)));
+#endif
+}
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL_11() performs polynomial multiplication and presents
+///  the result like Intel's <tt>c = _mm_clmulepi64_si128(a, b, 0x11)</tt>.
+///  The <tt>0x11</tt> indicates the high 64-bits of <tt>a</tt> and <tt>b</tt>
+///  are multiplied.
+/// \note An Intel XMM register is composed of 128-bits. The leftmost bit
+///  is MSB and numbered 127, while the rightmost bit is LSB and
+///  numbered 0.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL_11(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 1) };
+    const __n64 y = { vgetq_lane_u64(b, 1) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull2   %0.1q, %1.2d, %2.2d   \n\t"
+            :"=w" (r) : "w" (a), "w" (b) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),1),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),1)));
+#endif
+}
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL() performs vmull_p64(). PMULL is provided as
+///  GCC inline assembly due to Clang and lack of support for the intrinsic.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 0) };
+    const __n64 y = { vgetq_lane_u64(b, 0) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull    %0.1q, %1.1d, %2.1d   \n\t"
+            :"=w" (r) : "w" (a), "w" (b) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),0),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),0)));
+#endif
+}
+
+/// \brief Polynomial multiplication
+/// \param a the first value
+/// \param b the second value
+/// \return vector product
+/// \details PMULL_HIGH() performs vmull_high_p64(). PMULL_HIGH is provided as
+///  GCC inline assembly due to Clang and lack of support for the intrinsic.
+/// \since Crypto++ 8.0
+inline uint64x2_t PMULL_HIGH(const uint64x2_t a, const uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    const __n64 x = { vgetq_lane_u64(a, 1) };
+    const __n64 y = { vgetq_lane_u64(b, 1) };
+    return vmull_p64(x, y);
+#elif defined(__GNUC__)
+    uint64x2_t r;
+    __asm__ ("pmull2   %0.1q, %1.2d, %2.2d   \n\t"
+            :"=w" (r) : "w" (a), "w" (b) );
+    return r;
+#else
+    return (uint64x2_t)(vmull_p64(
+        vgetq_lane_u64(vreinterpretq_u64_u8(a),1),
+        vgetq_lane_u64(vreinterpretq_u64_u8(b),1))));
+#endif
+}
+
+/// \brief Vector extraction
+/// \tparam C the byte count
+/// \param a the first value
+/// \param b the second value
+/// \return vector
+/// \details VEXT_U8() extracts the first <tt>C</tt> bytes of vector
+///  <tt>a</tt> and the remaining bytes in <tt>b</tt>. VEXT_U8 is provided
+///  as GCC inline assembly due to Clang and lack of support for the intrinsic.
+/// \since Crypto++ 8.0
+template <unsigned int C>
+inline uint64x2_t VEXT_U8(uint64x2_t a, uint64x2_t b)
+{
+    // https://github.com/weidai11/cryptopp/issues/366
+#if defined(CRYPTOPP_MSC_VERSION)
+    return vreinterpretq_u64_u8(vextq_u8(
+        vreinterpretq_u8_u64(a), vreinterpretq_u8_u64(b), C));
+#else
+    uint64x2_t r;
+    __asm__ ("ext   %0.16b, %1.16b, %2.16b, %3   \n\t"
+            :"=w" (r) : "w" (a), "w" (b), "I" (C) );
+    return r;
+#endif
+}
+
+//@}
+#endif // CRYPTOPP_ARM_PMULL_AVAILABLE
+
+#if CRYPTOPP_ARM_SHA3_AVAILABLE  || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+///	\name ARMv8.2 operations
+//@{
+
+/// \brief Three-way XOR
+/// \param a the first value
+/// \param b the second value
+/// \param c the third value
+/// \return three-way exclusive OR of the values
+/// \details VEOR3() performs veor3q_u64(). VEOR3 is provided as GCC inline assembly due
+///  to Clang and lack of support for the intrinsic.
+/// \details VEOR3 requires ARMv8.2.
+/// \since Crypto++ 8.6
+inline uint64x2_t VEOR3(uint64x2_t a, uint64x2_t b, uint64x2_t c)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    return veor3q_u64(a, b, c);
+#else
+    uint64x2_t r;
+    __asm__ ("eor3   %0.16b, %1.16b, %2.16b, %3.16b   \n\t"
+            :"=w" (r) : "w" (a), "w" (b), "w" (c));
+    return r;
+#endif
+}
+
+/// \brief XOR and rotate
+/// \param a the first value
+/// \param b the second value
+/// \param c the third value
+/// \return two-way exclusive OR of the values, then rotated by c
+/// \details VXARQ() performs vxarq_u64(). VXARQ is provided as GCC inline assembly due
+///  to Clang and lack of support for the intrinsic.
+/// \details VXARQ requires ARMv8.2.
+/// \since Crypto++ 8.6
+inline uint64x2_t VXAR(uint64x2_t a, uint64x2_t b, const int c)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    return vxarq_u64(a, b, c);
+#else
+    uint64x2_t r;
+    __asm__ ("xar   %0.2d, %1.2d, %2.2d, %3   \n\t"
+            :"=w" (r) : "w" (a), "w" (b), "I" (c));
+    return r;
+#endif
+}
+
+/// \brief XOR and rotate
+/// \tparam C the rotate amount
+/// \param a the first value
+/// \param b the second value
+/// \return two-way exclusive OR of the values, then rotated by C
+/// \details VXARQ() performs vxarq_u64(). VXARQ is provided as GCC inline assembly due
+///  to Clang and lack of support for the intrinsic.
+/// \details VXARQ requires ARMv8.2.
+/// \since Crypto++ 8.6
+template <unsigned int C>
+inline uint64x2_t VXAR(uint64x2_t a, uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    return vxarq_u64(a, b, C);
+#else
+    uint64x2_t r;
+    __asm__ ("xar   %0.2d, %1.2d, %2.2d, %3   \n\t"
+            :"=w" (r) : "w" (a), "w" (b), "I" (C));
+    return r;
+#endif
+}
+
+/// \brief XOR and rotate
+/// \param a the first value
+/// \param b the second value
+/// \return two-way exclusive OR of the values, then rotated 1-bit
+/// \details VRAX1() performs vrax1q_u64(). VRAX1 is provided as GCC inline assembly due
+///  to Clang and lack of support for the intrinsic.
+/// \details VRAX1 requires ARMv8.2.
+/// \since Crypto++ 8.6
+inline uint64x2_t VRAX1(uint64x2_t a, uint64x2_t b)
+{
+#if defined(CRYPTOPP_MSC_VERSION)
+    return vrax1q_u64(a, b);
+#else
+    uint64x2_t r;
+    __asm__ ("rax1   %0.2d, %1.2d, %2.2d   \n\t"
+            :"=w" (r) : "w" (a), "w" (b));
+    return r;
+#endif
+}
+//@}
+#endif  // CRYPTOPP_ARM_SHA3_AVAILABLE
+
+#endif // CRYPTOPP_ARM_SIMD_H

+ 974 - 0
cryptopp/asn.h

@@ -0,0 +1,974 @@
+// asn.h - originally written and placed in the public domain by Wei Dai
+
+/// \file asn.h
+/// \brief Classes and functions for working with ANS.1 objects
+
+#ifndef CRYPTOPP_ASN_H
+#define CRYPTOPP_ASN_H
+
+#include "cryptlib.h"
+#include "filters.h"
+#include "smartptr.h"
+#include "stdcpp.h"
+#include "queue.h"
+#include "misc.h"
+
+#include <iosfwd>
+
+// Issue 340
+#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief ASN.1 types
+/// \note These tags are not complete
+enum ASNTag
+{
+	/// \brief ASN.1 Boolean
+	BOOLEAN 			= 0x01,
+	/// \brief ASN.1 Integer
+	INTEGER 			= 0x02,
+	/// \brief ASN.1 Bit string
+	BIT_STRING			= 0x03,
+	/// \brief ASN.1 Octet string
+	OCTET_STRING		= 0x04,
+	/// \brief ASN.1 Null
+	TAG_NULL			= 0x05,
+	/// \brief ASN.1 Object identifier
+	OBJECT_IDENTIFIER	= 0x06,
+	/// \brief ASN.1 Object descriptor
+	OBJECT_DESCRIPTOR	= 0x07,
+	/// \brief ASN.1 External reference
+	EXTERNAL			= 0x08,
+	/// \brief ASN.1 Real integer
+	REAL				= 0x09,
+	/// \brief ASN.1 Enumerated value
+	ENUMERATED			= 0x0a,
+	/// \brief ASN.1 UTF-8 string
+	UTF8_STRING			= 0x0c,
+	/// \brief ASN.1 Sequence
+	SEQUENCE			= 0x10,
+	/// \brief ASN.1 Set
+	SET 				= 0x11,
+	/// \brief ASN.1 Numeric string
+	NUMERIC_STRING		= 0x12,
+	/// \brief ASN.1 Printable string
+	PRINTABLE_STRING 	= 0x13,
+	/// \brief ASN.1 T61 string
+	T61_STRING			= 0x14,
+	/// \brief ASN.1 Videotext string
+	VIDEOTEXT_STRING 	= 0x15,
+	/// \brief ASN.1 IA5 string
+	IA5_STRING			= 0x16,
+	/// \brief ASN.1 UTC time
+	UTC_TIME 			= 0x17,
+	/// \brief ASN.1 Generalized time
+	GENERALIZED_TIME 	= 0x18,
+	/// \brief ASN.1 Graphic string
+	GRAPHIC_STRING		= 0x19,
+	/// \brief ASN.1 Visible string
+	VISIBLE_STRING		= 0x1a,
+	/// \brief ASN.1 General string
+	GENERAL_STRING		= 0x1b,
+	/// \brief ASN.1 Universal string
+	UNIVERSAL_STRING	= 0x1c,
+	/// \brief ASN.1 BMP string
+	BMP_STRING  		= 0x1e
+};
+
+/// \brief ASN.1 flags
+/// \note These flags are not complete
+enum ASNIdFlag
+{
+	/// \brief ASN.1 Universal class
+	UNIVERSAL           = 0x00,
+	// DATA           = 0x01,
+	// HEADER           = 0x02,
+	/// \brief ASN.1 Primitive flag
+	PRIMITIVE           = 0x00,
+	/// \brief ASN.1 Constructed flag
+	CONSTRUCTED         = 0x20,
+	/// \brief ASN.1 Application class
+	APPLICATION         = 0x40,
+	/// \brief ASN.1 Context specific class
+	CONTEXT_SPECIFIC    = 0x80,
+	/// \brief ASN.1 Private class
+	PRIVATE             = 0xc0
+};
+
+/// \brief Raises a BERDecodeErr
+inline void BERDecodeError() {throw BERDecodeErr();}
+
+/// \brief Exception thrown when an unknown object identifier is encountered
+class CRYPTOPP_DLL UnknownOID : public BERDecodeErr
+{
+public:
+	/// \brief Construct an UnknownOID
+	UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {}
+	/// \brief Construct an UnknownOID
+	/// \param err error message to use for the exception
+	UnknownOID(const char *err) : BERDecodeErr(err) {}
+};
+
+/// \brief DER encode a length
+/// \param bt BufferedTransformation object for writing
+/// \param length the size to encode
+/// \return the number of octets used for the encoding
+CRYPTOPP_DLL size_t CRYPTOPP_API DERLengthEncode(BufferedTransformation &bt, lword length);
+
+/// \brief BER decode a length
+/// \param bt BufferedTransformation object for reading
+/// \param length the decoded size
+/// \return true if the value was decoded
+/// \throw BERDecodeError if the value fails to decode or is too large for size_t
+/// \details BERLengthDecode() returns false if the encoding is indefinite length.
+CRYPTOPP_DLL bool CRYPTOPP_API BERLengthDecode(BufferedTransformation &bt, size_t &length);
+
+/// \brief DER encode NULL
+/// \param bt BufferedTransformation object for writing
+CRYPTOPP_DLL void CRYPTOPP_API DEREncodeNull(BufferedTransformation &bt);
+
+/// \brief BER decode NULL
+/// \param bt BufferedTransformation object for reading
+CRYPTOPP_DLL void CRYPTOPP_API BERDecodeNull(BufferedTransformation &bt);
+
+/// \brief DER encode octet string
+/// \param bt BufferedTransformation object for writing
+/// \param str the string to encode
+/// \param strLen the length of the string
+/// \return the number of octets used for the encoding
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen);
+
+/// \brief DER encode octet string
+/// \param bt BufferedTransformation object for reading
+/// \param str the string to encode
+/// \return the number of octets used for the encoding
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str);
+
+/// \brief BER decode octet string
+/// \param bt BufferedTransformation object for reading
+/// \param str the decoded string
+/// \return the number of octets used for the encoding
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str);
+
+/// \brief BER decode octet string
+/// \param bt BufferedTransformation object for reading
+/// \param str the decoded string
+/// \return the number of octets used for the encoding
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str);
+
+/// \brief DER encode text string
+/// \param bt BufferedTransformation object for writing
+/// \param str the string to encode
+/// \param strLen the length of the string, in bytes
+/// \param asnTag the ASN.1 identifier
+/// \return the number of octets used for the encoding
+/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const byte* str, size_t strLen, byte asnTag);
+
+/// \brief DER encode text string
+/// \param bt BufferedTransformation object for writing
+/// \param str the string to encode
+/// \param asnTag the ASN.1 identifier
+/// \return the number of octets used for the encoding
+/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag);
+
+/// \brief DER encode text string
+/// \param bt BufferedTransformation object for writing
+/// \param str the string to encode
+/// \param asnTag the ASN.1 identifier
+/// \return the number of octets used for the encoding
+/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING
+/// \since Crypto++ 6.0
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag);
+
+/// \brief BER decode text string
+/// \param bt BufferedTransformation object for reading
+/// \param str the string to decode
+/// \param asnTag the ASN.1 identifier
+/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, SecByteBlock &str, byte asnTag);
+
+/// \brief BER decode text string
+/// \param bt BufferedTransformation object for reading
+/// \param str the string to decode
+/// \param asnTag the ASN.1 identifier
+/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING
+/// \since Crypto++ 6.0
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag);
+
+/// \brief DER encode date
+/// \param bt BufferedTransformation object for writing
+/// \param str the date to encode
+/// \param asnTag the ASN.1 identifier
+/// \return the number of octets used for the encoding
+/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeDate(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag);
+
+/// \brief BER decode date
+/// \param bt BufferedTransformation object for reading
+/// \param str the date to decode
+/// \param asnTag the ASN.1 identifier
+/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeDate(BufferedTransformation &bt, SecByteBlock &str, byte asnTag);
+
+/// \brief DER encode bit string
+/// \param bt BufferedTransformation object for writing
+/// \param str the string to encode
+/// \param strLen the length of the string
+/// \param unusedBits the number of unused bits
+/// \return the number of octets used for the encoding
+/// \details The caller is responsible for shifting octets if unusedBits is
+///  not 0. For example, to DER encode a web server X.509 key usage, the 101b
+///  bit mask is often used (digitalSignature and keyEncipherment). In this
+///  case <tt>str</tt> is one octet with a value=0xa0 and unusedBits=5. The
+///  value 0xa0 is <tt>101b << 5</tt>.
+CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0);
+
+/// \brief DER decode bit string
+/// \param bt BufferedTransformation object for reading
+/// \param str the decoded string
+/// \param unusedBits the number of unused bits
+/// \details The caller is responsible for shifting octets if unusedBits is
+///  not 0. For example, to DER encode a web server X.509 key usage, the 101b
+///  bit mask is often used (digitalSignature and keyEncipherment). In this
+///  case <tt>str</tt> is one octet with a value=0xa0 and unusedBits=5. The
+///  value 0xa0 is <tt>101b << 5</tt>.
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits);
+
+/// \brief BER decode and DER re-encode
+/// \param bt BufferedTransformation object for writing
+/// \param dest BufferedTransformation object
+CRYPTOPP_DLL void CRYPTOPP_API DERReencode(BufferedTransformation &bt, BufferedTransformation &dest);
+
+/// \brief BER decode size
+/// \param bt BufferedTransformation object for reading
+/// \return the length of the ASN.1 value, in bytes
+/// \details BERDecodePeekLength() determines the length of a value without
+///  consuming octets in the stream. The stream must use definite length encoding.
+///  If indefinite length encoding is used or an error occurs, then 0 is returned.
+/// \since Crypto++ 8.3
+CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodePeekLength(const BufferedTransformation &bt);
+
+/// \brief Object Identifier
+class CRYPTOPP_DLL OID
+{
+public:
+	virtual ~OID() {}
+
+	/// \brief Construct an OID
+	OID() {}
+
+	/// \brief Construct an OID
+	/// \param v value to initialize the OID
+	OID(word32 v) : m_values(1, v) {}
+
+	/// \brief Construct an OID
+	/// \param bt BufferedTransformation object
+	OID(BufferedTransformation &bt) {
+		BERDecode(bt);
+	}
+
+	/// \brief Append a value to an OID
+	/// \param rhs the value to append
+	inline OID & operator+=(word32 rhs) {
+		m_values.push_back(rhs); return *this;
+	}
+
+	/// \brief DER encode this OID
+	/// \param bt BufferedTransformation object
+	void DEREncode(BufferedTransformation &bt) const;
+
+	/// \brief BER decode an OID
+	/// \param bt BufferedTransformation object
+	void BERDecode(BufferedTransformation &bt);
+
+	/// \brief BER decode an OID
+	/// \param bt BufferedTransformation object
+	/// \throw BERDecodeErr() if decoded value doesn't match an expected OID
+	/// \details BERDecodeAndCheck() can be used to parse an OID and verify it matches an expected.
+	/// <pre>
+	///   BERSequenceDecoder key(bt);
+	///   ...
+	///   BERSequenceDecoder algorithm(key);
+	///   GetAlgorithmID().BERDecodeAndCheck(algorithm);
+	/// </pre>
+	void BERDecodeAndCheck(BufferedTransformation &bt) const;
+
+	/// \brief Determine if OID is empty
+	/// \return true if OID has 0 elements, false otherwise
+	/// \since Crypto++ 8.0
+	bool Empty() const {
+		return m_values.empty();
+	}
+
+	/// \brief Retrieve OID value array
+	/// \return OID value vector
+	/// \since Crypto++ 8.0
+	const std::vector<word32>& GetValues() const {
+		return m_values;
+	}
+
+	/// \brief Print an OID
+	/// \param out ostream object
+	/// \return ostream reference
+	/// \details Print() writes the OID in a customary format, like
+	///  1.2.840.113549.1.1.11. The caller is reposnsible to convert the
+	///  OID to a friendly name, like sha256WithRSAEncryption.
+	/// \since Crypto++ 8.3
+	std::ostream& Print(std::ostream& out) const;
+
+protected:
+	friend bool operator==(const OID &lhs, const OID &rhs);
+	friend bool operator!=(const OID &lhs, const OID &rhs);
+	friend bool operator< (const OID &lhs, const OID &rhs);
+	friend bool operator> (const OID &lhs, const OID &rhs);
+	friend bool operator<=(const OID &lhs, const OID &rhs);
+	friend bool operator>=(const OID &lhs, const OID &rhs);
+
+	std::vector<word32> m_values;
+
+private:
+	static void EncodeValue(BufferedTransformation &bt, word32 v);
+	static size_t DecodeValue(BufferedTransformation &bt, word32 &v);
+};
+
+/// \brief ASN.1 encoded object filter
+class EncodedObjectFilter : public Filter
+{
+public:
+	enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8};
+	enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state;
+
+	virtual ~EncodedObjectFilter() {}
+
+	/// \brief Construct an EncodedObjectFilter
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \param nObjects the number of objects
+	/// \param flags bitwise OR of EncodedObjectFilter::Flag
+	EncodedObjectFilter(BufferedTransformation *attachment = NULLPTR, unsigned int nObjects = 1, word32 flags = 0);
+
+	/// \brief Input a byte buffer for processing
+	/// \param inString the byte buffer to process
+	/// \param length the size of the string, in bytes
+	void Put(const byte *inString, size_t length);
+
+	unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;}
+	unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];}
+
+private:
+	BufferedTransformation & CurrentTarget();
+
+	ByteQueue m_queue;
+	std::vector<unsigned int> m_positions;
+	lword m_lengthRemaining;
+	word32 m_nObjects, m_nCurrentObject, m_level, m_flags;
+	byte m_id;
+};
+
+/// \brief BER General Decoder
+class CRYPTOPP_DLL BERGeneralDecoder : public Store
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)};
+
+	virtual ~BERGeneralDecoder();
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \details BERGeneralDecoder uses DefaultTag
+	explicit BERGeneralDecoder(BufferedTransformation &inQueue);
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag);
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag);
+
+	/// \brief Determine length encoding
+	/// \return true if the ASN.1 object is definite length encoded, false otherwise
+	bool IsDefiniteLength() const {
+		return m_definiteLength;
+	}
+
+	/// \brief Determine remaining length
+	/// \return number of octets that remain to be consumed
+	/// \details RemainingLength() is only valid if IsDefiniteLength()
+	///  returns true.
+	lword RemainingLength() const {
+		CRYPTOPP_ASSERT(m_definiteLength);
+		return IsDefiniteLength() ? m_length : 0;
+	}
+
+	/// \brief Determine end of stream
+	/// \return true if all octets have been consumed, false otherwise
+	bool EndReached() const;
+
+	/// \brief Determine next octet
+	/// \return next octet in the stream
+	/// \details PeekByte does not consume the octet.
+	/// \throw BERDecodeError if there are no octets remaining
+	byte PeekByte() const;
+
+	/// \brief Determine next octet
+	/// \details CheckByte reads the next byte in the stream and verifies
+	///  the octet matches b.
+	/// \throw BERDecodeError if the next octet is not b
+	void CheckByte(byte b);
+
+	/// \brief Transfer bytes to another BufferedTransformation
+	/// \param target the destination BufferedTransformation
+	/// \param transferBytes the number of bytes to transfer
+	/// \param channel the channel on which the transfer should occur
+	/// \param blocking specifies whether the object should block when
+	///  processing input
+	/// \return the number of bytes that remain in the transfer block
+	///  (i.e., bytes not transferred)
+	/// \details TransferTo2() removes bytes and moves
+	///  them to the destination. Transfer begins at the index position
+	///  in the current stream, and not from an absolute position in the
+	///  stream.
+	/// \details transferBytes is an \a IN and \a OUT parameter. When
+	///  the call is made, transferBytes is the requested size of the
+	///  transfer. When the call returns, transferBytes is the number
+	///  of bytes that were transferred.
+	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+
+	/// \brief Copy bytes to another BufferedTransformation
+	/// \param target the destination BufferedTransformation
+	/// \param begin the 0-based index of the first byte to copy in
+	///  the stream
+	/// \param end the 0-based index of the last byte to copy in
+	///  the stream
+	/// \param channel the channel on which the transfer should occur
+	/// \param blocking specifies whether the object should block when
+	///  processing input
+	/// \return the number of bytes that remain in the copy block
+	///  (i.e., bytes not copied)
+	/// \details CopyRangeTo2 copies bytes to the
+	///  destination. The bytes are not removed from this object. Copying
+	///  begins at the index position in the current stream, and not from
+	///  an absolute position in the stream.
+	/// \details begin is an \a IN and \a OUT parameter. When the call is
+	///  made, begin is the starting position of the copy. When the call
+	///  returns, begin is the position of the first byte that was \a not
+	///  copied (which may be different than end). begin can be used for
+	///  subsequent calls to CopyRangeTo2().
+	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
+
+	/// \brief Signals the end of messages to the object
+	/// \details Call this to denote end of sequence
+	void MessageEnd();
+
+protected:
+	BufferedTransformation &m_inQueue;
+	lword m_length;
+	bool m_finished, m_definiteLength;
+
+private:
+	void Init(byte asnTag);
+	void StoreInitialize(const NameValuePairs &parameters)
+		{CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);}
+	lword ReduceLength(lword delta);
+};
+
+/// \brief DER General Encoder
+class CRYPTOPP_DLL DERGeneralEncoder : public ByteQueue
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)};
+
+	virtual ~DERGeneralEncoder();
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \details DERGeneralEncoder uses DefaultTag
+	explicit DERGeneralEncoder(BufferedTransformation &outQueue);
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag);
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag);
+
+	/// \brief Signals the end of messages to the object
+	/// \details Call this to denote end of sequence
+	void MessageEnd();
+
+private:
+	BufferedTransformation &m_outQueue;
+	byte m_asnTag;
+	bool m_finished;
+};
+
+/// \brief BER Sequence Decoder
+class CRYPTOPP_DLL BERSequenceDecoder : public BERGeneralDecoder
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)};
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \details BERSequenceDecoder uses DefaultTag
+	explicit BERSequenceDecoder(BufferedTransformation &inQueue)
+		: BERGeneralDecoder(inQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag)
+		: BERGeneralDecoder(inQueue, asnTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \details BERSequenceDecoder uses DefaultTag
+	explicit BERSequenceDecoder(BERSequenceDecoder &inQueue)
+		: BERGeneralDecoder(inQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag)
+		: BERGeneralDecoder(inQueue, asnTag) {}
+};
+
+/// \brief DER Sequence Encoder
+class CRYPTOPP_DLL DERSequenceEncoder : public DERGeneralEncoder
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)};
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \details DERSequenceEncoder uses DefaultTag
+	explicit DERSequenceEncoder(BufferedTransformation &outQueue)
+		: DERGeneralEncoder(outQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag)
+		: DERGeneralEncoder(outQueue, asnTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \details DERSequenceEncoder uses DefaultTag
+	explicit DERSequenceEncoder(DERSequenceEncoder &outQueue)
+		: DERGeneralEncoder(outQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag)
+		: DERGeneralEncoder(outQueue, asnTag) {}
+};
+
+/// \brief BER Set Decoder
+class CRYPTOPP_DLL BERSetDecoder : public BERGeneralDecoder
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SET | EnumToInt(CONSTRUCTED)};
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \details BERSetDecoder uses DefaultTag
+	explicit BERSetDecoder(BufferedTransformation &inQueue)
+		: BERGeneralDecoder(inQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag)
+		: BERGeneralDecoder(inQueue, asnTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \details BERSetDecoder uses DefaultTag
+	explicit BERSetDecoder(BERSetDecoder &inQueue)
+		: BERGeneralDecoder(inQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 decoder
+	/// \param inQueue input byte queue
+	/// \param asnTag ASN.1 tag
+	explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag)
+		: BERGeneralDecoder(inQueue, asnTag) {}
+};
+
+/// \brief DER Set Encoder
+class CRYPTOPP_DLL DERSetEncoder : public DERGeneralEncoder
+{
+public:
+	/// \brief Default ASN.1 tag
+	enum {DefaultTag = SET | EnumToInt(CONSTRUCTED)};
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \details DERSetEncoder uses DefaultTag
+	explicit DERSetEncoder(BufferedTransformation &outQueue)
+		: DERGeneralEncoder(outQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag)
+		: DERGeneralEncoder(outQueue, asnTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \details DERSetEncoder uses DefaultTag
+	explicit DERSetEncoder(DERSetEncoder &outQueue)
+		: DERGeneralEncoder(outQueue, DefaultTag) {}
+
+	/// \brief Construct an ASN.1 encoder
+	/// \param outQueue output byte queue
+	/// \param asnTag ASN.1 tag
+	explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag)
+		: DERGeneralEncoder(outQueue, asnTag) {}
+};
+
+/// \brief Optional data encoder and decoder
+/// \tparam T class or type
+template <class T>
+class ASNOptional : public member_ptr<T>
+{
+public:
+	/// \brief BER decode optional data
+	/// \param seqDecoder sequence with the optional ASN.1 data
+	/// \param tag ASN.1 tag to match as optional data
+	/// \param mask the mask to apply when matching the tag
+	/// \sa ASNTag and ASNIdFlag
+	void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED)
+	{
+		byte b;
+		if (seqDecoder.Peek(b) && (b & mask) == tag)
+			reset(new T(seqDecoder));
+	}
+
+	/// \brief DER encode optional data
+	/// \param out BufferedTransformation object
+	void DEREncode(BufferedTransformation &out)
+	{
+		if (this->get() != NULLPTR)
+			this->get()->DEREncode(out);
+	}
+};
+
+/// \brief Encode and decode ASN.1 objects with additional information
+/// \tparam BASE base class or type
+/// \details Encodes and decodes public keys, private keys and group
+///   parameters with OID identifying the algorithm or scheme.
+template <class BASE>
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1CryptoMaterial : public ASN1Object, public BASE
+{
+public:
+	/// \brief DER encode ASN.1 object
+	/// \param bt BufferedTransformation object
+	/// \details Save() will write the OID associated with algorithm or scheme.
+	///   In the case of public and private keys, this function writes the
+	///   subjectPublicKeyInfo and privateKeyInfo parts.
+	void Save(BufferedTransformation &bt) const
+		{BEREncode(bt);}
+
+	/// \brief BER decode ASN.1 object
+	/// \param bt BufferedTransformation object
+	void Load(BufferedTransformation &bt)
+		{BERDecode(bt);}
+};
+
+/// \brief Encodes and decodes subjectPublicKeyInfo
+class CRYPTOPP_DLL X509PublicKey : public ASN1CryptoMaterial<PublicKey>
+{
+public:
+	virtual ~X509PublicKey() {}
+
+	void BERDecode(BufferedTransformation &bt);
+	void DEREncode(BufferedTransformation &bt) const;
+
+	/// \brief Retrieves the OID of the algorithm
+	/// \return OID of the algorithm
+	virtual OID GetAlgorithmID() const =0;
+
+	/// \brief Decode algorithm parameters
+	/// \param bt BufferedTransformation object
+	/// \sa BERDecodePublicKey, <A HREF="http://www.ietf.org/rfc/rfc2459.txt">RFC
+	///  2459, section 7.3.1</A>
+	virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt)
+		{BERDecodeNull(bt); return false;}
+
+	/// \brief Encode algorithm parameters
+	/// \param bt BufferedTransformation object
+	/// \sa DEREncodePublicKey, <A HREF="http://www.ietf.org/rfc/rfc2459.txt">RFC
+	///  2459, section 7.3.1</A>
+	virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const
+		{DEREncodeNull(bt); return false;}
+
+	/// \brief Decode subjectPublicKey part of subjectPublicKeyInfo
+	/// \param bt BufferedTransformation object
+	/// \param parametersPresent flag indicating if algorithm parameters are present
+	/// \param size number of octets to read for the parameters, in bytes
+	/// \details BERDecodePublicKey() the decodes subjectPublicKey part of
+	///  subjectPublicKeyInfo, without the BIT STRING header.
+	/// \details When <tt>parametersPresent = true</tt> then BERDecodePublicKey() calls
+	///  BERDecodeAlgorithmParameters() to parse algorithm parameters.
+	/// \sa BERDecodeAlgorithmParameters
+	virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0;
+
+	/// \brief Encode subjectPublicKey part of subjectPublicKeyInfo
+	/// \param bt BufferedTransformation object
+	/// \details DEREncodePublicKey() encodes the subjectPublicKey part of
+	///  subjectPublicKeyInfo, without the BIT STRING header.
+	/// \sa DEREncodeAlgorithmParameters
+	virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0;
+};
+
+/// \brief Encodes and Decodes privateKeyInfo
+class CRYPTOPP_DLL PKCS8PrivateKey : public ASN1CryptoMaterial<PrivateKey>
+{
+public:
+	virtual ~PKCS8PrivateKey() {}
+
+	void BERDecode(BufferedTransformation &bt);
+	void DEREncode(BufferedTransformation &bt) const;
+
+	/// \brief Retrieves the OID of the algorithm
+	/// \return OID of the algorithm
+	virtual OID GetAlgorithmID() const =0;
+
+	/// \brief Decode optional parameters
+	/// \param bt BufferedTransformation object
+	/// \sa BERDecodePrivateKey, <A HREF="http://www.ietf.org/rfc/rfc2459.txt">RFC
+	///  2459, section 7.3.1</A>
+	virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt)
+		{BERDecodeNull(bt); return false;}
+
+	/// \brief Encode optional parameters
+	/// \param bt BufferedTransformation object
+	/// \sa DEREncodePrivateKey, <A HREF="http://www.ietf.org/rfc/rfc2459.txt">RFC
+	///  2459, section 7.3.1</A>
+	virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const
+		{DEREncodeNull(bt); return false;}
+
+	/// \brief Decode privateKey part of privateKeyInfo
+	/// \param bt BufferedTransformation object
+	/// \param parametersPresent flag indicating if algorithm parameters are present
+	/// \param size number of octets to read for the parameters, in bytes
+	/// \details BERDecodePrivateKey() the decodes privateKey part of privateKeyInfo,
+	///  without the OCTET STRING header.
+	/// \details When <tt>parametersPresent = true</tt> then BERDecodePrivateKey() calls
+	///  BERDecodeAlgorithmParameters() to parse algorithm parameters.
+	/// \sa BERDecodeAlgorithmParameters
+	virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0;
+
+	/// \brief Encode privateKey part of privateKeyInfo
+	/// \param bt BufferedTransformation object
+	/// \details DEREncodePrivateKey() encodes the privateKey part of privateKeyInfo,
+	///  without the OCTET STRING header.
+	/// \sa DEREncodeAlgorithmParameters
+	virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0;
+
+	/// \brief Decode optional attributes
+	/// \param bt BufferedTransformation object
+	/// \details BERDecodeOptionalAttributes() decodes optional attributes including
+	///  context-specific tag.
+	/// \sa BERDecodeAlgorithmParameters, DEREncodeOptionalAttributes
+	/// \note default implementation stores attributes to be output using
+	///  DEREncodeOptionalAttributes
+	virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt);
+
+	/// \brief Encode optional attributes
+	/// \param bt BufferedTransformation object
+	/// \details DEREncodeOptionalAttributes() encodes optional attributes including
+	///  context-specific tag.
+	/// \sa BERDecodeAlgorithmParameters
+	virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const;
+
+protected:
+	ByteQueue m_optionalAttributes;
+};
+
+// ********************************************************
+
+/// \brief DER Encode unsigned value
+/// \tparam T class or type
+/// \param out BufferedTransformation object
+/// \param w unsigned value to encode
+/// \param asnTag the ASN.1 identifier
+/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM
+template <class T>
+size_t DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER)
+{
+	byte buf[sizeof(w)+1];
+	unsigned int bc;
+	if (asnTag == BOOLEAN)
+	{
+		buf[sizeof(w)] = w ? 0xff : 0;
+		bc = 1;
+	}
+	else
+	{
+		buf[0] = 0;
+		for (unsigned int i=0; i<sizeof(w); i++)
+			buf[i+1] = byte(w >> (sizeof(w)-1-i)*8);
+		bc = sizeof(w);
+		while (bc > 1 && buf[sizeof(w)+1-bc] == 0)
+			--bc;
+		if (buf[sizeof(w)+1-bc] & 0x80)
+			++bc;
+	}
+	out.Put(asnTag);
+	size_t lengthBytes = DERLengthEncode(out, bc);
+	out.Put(buf+sizeof(w)+1-bc, bc);
+	return 1+lengthBytes+bc;
+}
+
+/// \brief BER Decode unsigned value
+/// \tparam T fundamental C++ type
+/// \param in BufferedTransformation object
+/// \param w the decoded value
+/// \param asnTag the ASN.1 identifier
+/// \param minValue the minimum expected value
+/// \param maxValue the maximum expected value
+/// \throw BERDecodeErr() if the value cannot be parsed or the decoded value is not within range.
+/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM
+template <class T>
+void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER,
+					   T minValue = 0, T maxValue = T(0xffffffff))
+{
+	byte b;
+	if (!in.Get(b) || b != asnTag)
+		BERDecodeError();
+
+	size_t bc;
+	bool definite = BERLengthDecode(in, bc);
+	if (!definite)
+		BERDecodeError();
+	if (bc > in.MaxRetrievable())  // Issue 346
+		BERDecodeError();
+	if (asnTag == BOOLEAN && bc != 1) // X.690, 8.2.1
+		BERDecodeError();
+	if ((asnTag == INTEGER || asnTag == ENUMERATED) && bc == 0) // X.690, 8.3.1 and 8.4
+		BERDecodeError();
+
+	SecByteBlock buf(bc);
+
+	if (bc != in.Get(buf, bc))
+		BERDecodeError();
+
+	// This consumes leading 0 octets. According to X.690, 8.3.2, it could be non-conforming behavior.
+	//  X.690, 8.3.2 says "the bits of the first octet and bit 8 of the second octet ... (a) shall
+	//  not all be ones and (b) shall not all be zeros ... These rules ensure that an integer value
+	//  is always encoded in the smallest possible number of octet".
+	// We invented AER (Alternate Encoding Rules), which is more relaxed than BER, CER, and DER.
+	const byte *ptr = buf;
+	while (bc > sizeof(w) && *ptr == 0)
+	{
+		bc--;
+		ptr++;
+	}
+	if (bc > sizeof(w))
+		BERDecodeError();
+
+	w = 0;
+	for (unsigned int i=0; i<bc; i++)
+		w = (w << 8) | ptr[i];
+
+	if (w < minValue || w > maxValue)
+		BERDecodeError();
+}
+
+#ifdef CRYPTOPP_DOXYGEN_PROCESSING
+/// \brief Compare two OIDs for equality
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the OIDs are equal, false otherwise
+inline bool operator==(const OID &lhs, const OID &rhs);
+/// \brief Compare two OIDs for inequality
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the OIDs are not equal, false otherwise
+inline bool operator!=(const OID &lhs, const OID &rhs);
+/// \brief Compare two OIDs for ordering
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the first OID is less than the second OID, false otherwise
+/// \details operator<() calls std::lexicographical_compare() on the values.
+inline bool operator<(const OID &lhs, const OID &rhs);
+/// \brief Compare two OIDs for ordering
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the first OID is greater than the second OID, false otherwise
+/// \details operator>() is implemented in terms of operator==() and operator<().
+/// \since Crypto++ 8.3
+inline bool operator>(const OID &lhs, const OID &rhs);
+/// \brief Compare two OIDs for ordering
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the first OID is less than or equal to the second OID, false otherwise
+/// \details operator<=() is implemented in terms of operator==() and operator<().
+/// \since Crypto++ 8.3
+inline bool operator<=(const OID &lhs, const OID &rhs);
+/// \brief Compare two OIDs for ordering
+/// \param lhs the first OID
+/// \param rhs the second OID
+/// \return true if the first OID is greater than or equal to the second OID, false otherwise
+/// \details operator>=() is implemented in terms of operator<().
+/// \since Crypto++ 8.3
+inline bool operator>=(const OID &lhs, const OID &rhs);
+/// \brief Append a value to an OID
+/// \param lhs the OID
+/// \param rhs the value to append
+inline OID operator+(const OID &lhs, unsigned long rhs);
+/// \brief Print a OID value
+/// \param out the output stream
+/// \param oid the OID
+inline std::ostream& operator<<(std::ostream& out, const OID &oid);
+#else
+inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return lhs.m_values == rhs.m_values;}
+inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return lhs.m_values != rhs.m_values;}
+inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());}
+inline bool operator>(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return ! (lhs<rhs || lhs==rhs);}
+inline bool operator<=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return lhs<rhs || lhs==rhs;}
+inline bool operator>=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs)
+	{return ! (lhs<rhs);}
+inline ::CryptoPP::OID operator+(const ::CryptoPP::OID &lhs, unsigned long rhs)
+	{return ::CryptoPP::OID(lhs)+=rhs;}
+inline std::ostream& operator<<(std::ostream& out, const OID &oid)
+	{ return oid.Print(out); }
+#endif
+
+NAMESPACE_END
+
+// Issue 340
+#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
+# pragma GCC diagnostic pop
+#endif
+
+#endif

+ 87 - 0
cryptopp/authenc.h

@@ -0,0 +1,87 @@
+// authenc.h - originally written and placed in the public domain by Wei Dai
+
+/// \file
+/// \brief Classes for authenticated encryption modes of operation
+/// \details Authenticated encryption (AE) schemes combine confidentiality and authenticity
+///   into a single mode of operation They gained traction in the early 2000's because manually
+///   combining them was error prone for the typical developer. Around that time, the desire to
+///   authenticate but not ecrypt additional data (AAD) was also identified. When both features
+///   are available from a scheme, the system is referred to as an AEAD scheme.
+/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM
+///   and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the
+///   motivation for the API, like calling AAD a &quot;header&quot;, can be found in Bellare,
+///   Rogaway and Wagner's <A HREF="http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf">The EAX
+///   Mode of Operation</A>. The EAX paper suggested a basic API to help standardize AEAD
+///   schemes in software and promote adoption of the modes.
+/// \sa <A HREF="http://www.cryptopp.com/wiki/Authenticated_Encryption">Authenticated
+///   Encryption</A> on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+
+#ifndef CRYPTOPP_AUTHENC_H
+#define CRYPTOPP_AUTHENC_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Base class for authenticated encryption modes of operation
+/// \details AuthenticatedSymmetricCipherBase() serves as a base implementation for one direction
+///   (encryption or decryption) of a stream cipher or block cipher mode with authentication.
+/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM
+///   and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the
+///   motivation for the API, like calling AAD a &quot;header&quot;, can be found in Bellare,
+///   Rogaway and Wagner's <A HREF="http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf">The EAX
+///   Mode of Operation</A>. The EAX paper suggested a basic API to help standardize AEAD
+///   schemes in software and promote adoption of the modes.
+/// \sa <A HREF="http://www.cryptopp.com/wiki/Authenticated_Encryption">Authenticated
+///   Encryption</A> on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipherBase : public AuthenticatedSymmetricCipher
+{
+public:
+	AuthenticatedSymmetricCipherBase() : m_totalHeaderLength(0), m_totalMessageLength(0),
+		m_totalFooterLength(0), m_bufferedDataLength(0), m_state(State_Start) {}
+
+	// StreamTransformation interface
+	bool IsRandomAccess() const {return false;}
+	bool IsSelfInverting() const {return true;}
+
+	void SetKey(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Restart() {if (m_state > State_KeySet) m_state = State_KeySet;}
+	void Resynchronize(const byte *iv, int length=-1);
+	void Update(const byte *input, size_t length);
+	void ProcessData(byte *outString, const byte *inString, size_t length);
+	void TruncatedFinal(byte *mac, size_t macSize);
+
+protected:
+	void UncheckedSetKey(const byte * key, unsigned int length,const CryptoPP::NameValuePairs &params)
+		{CRYPTOPP_UNUSED(key), CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); CRYPTOPP_ASSERT(false);}
+
+	void AuthenticateData(const byte *data, size_t len);
+	const SymmetricCipher & GetSymmetricCipher() const
+		{return const_cast<AuthenticatedSymmetricCipherBase *>(this)->AccessSymmetricCipher();}
+
+	virtual SymmetricCipher & AccessSymmetricCipher() =0;
+	virtual bool AuthenticationIsOnPlaintext() const =0;
+	virtual unsigned int AuthenticationBlockSize() const =0;
+	virtual void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params) =0;
+	virtual void Resync(const byte *iv, size_t len) =0;
+	virtual size_t AuthenticateBlocks(const byte *data, size_t len) =0;
+	virtual void AuthenticateLastHeaderBlock() =0;
+	virtual void AuthenticateLastConfidentialBlock() {}
+	virtual void AuthenticateLastFooterBlock(byte *mac, size_t macSize) =0;
+
+	// State_AuthUntransformed: authentication is applied to plain text (Authenticate-then-Encrypt)
+	// State_AuthTransformed: authentication is applied to cipher text (Encrypt-then-Authenticate)
+	enum State {State_Start, State_KeySet, State_IVSet, State_AuthUntransformed, State_AuthTransformed, State_AuthFooter};
+
+	AlignedSecByteBlock m_buffer;
+	lword m_totalHeaderLength, m_totalMessageLength, m_totalFooterLength;
+	unsigned int m_bufferedDataLength;
+	State m_state;
+};
+
+NAMESPACE_END
+
+#endif

+ 158 - 0
cryptopp/base32.h

@@ -0,0 +1,158 @@
+// base32.h - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai
+//              extended hex alphabet added by JW in November, 2017.
+
+/// \file base32.h
+/// \brief Classes for Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+
+#ifndef CRYPTOPP_BASE32_H
+#define CRYPTOPP_BASE32_H
+
+#include "cryptlib.h"
+#include "basecode.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Base32 encodes data using DUDE encoding
+/// \details Converts data to base32 using DUDE encoding. The default code is based on <A HREF="http://www.ietf.org/proceedings/51/I-D/draft-ietf-idn-dude-02.txt">Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt)</A>.
+/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+class Base32Encoder : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a Base32Encoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \param uppercase a flag indicating uppercase output
+	/// \param groupSize the size of the grouping
+	/// \param separator the separator to use between groups
+	/// \param terminator the terminator appeand after processing
+	/// \details Base32Encoder() constructs a default encoder. The constructor lacks fields for padding and
+	///   line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it.
+	/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+	Base32Encoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "")
+		: SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment)
+	{
+		IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator)));
+	}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details The following code modifies the padding and line break parameters for an encoder:
+	///   <pre>
+	///     Base32Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);</pre>
+	/// \details You can change the encoding to <A HREF="http://tools.ietf.org/html/rfc4648#page-10">RFC 4648, Base
+	///   32 Encoding with Extended Hex Alphabet</A> by performing the following:
+	///   <pre>
+	///     Base32Encoder encoder;
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);</pre>
+	/// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and
+	///   the decoder's lookup table.
+	/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+	void IsolatedInitialize(const NameValuePairs &parameters);
+};
+
+/// \brief Base32 decodes data using DUDE encoding
+/// \details Converts data from base32 using DUDE encoding. The default code is based on <A HREF="http://www.ietf.org/proceedings/51/I-D/draft-ietf-idn-dude-02.txt">Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt)</A>.
+/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+class Base32Decoder : public BaseN_Decoder
+{
+public:
+	/// \brief Construct a Base32Decoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \sa IsolatedInitialize() for an example of modifying a Base32Decoder after construction.
+	Base32Decoder(BufferedTransformation *attachment = NULLPTR)
+		: BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details You can change the encoding to <A HREF="http://tools.ietf.org/html/rfc4648#page-10">RFC 4648, Base
+	///   32 Encoding with Extended Hex Alphabet</A> by performing the following:
+	///   <pre>
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     Base32Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 32, true /*insensitive*/);
+	///
+	///     Base32Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);</pre>
+	/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+	void IsolatedInitialize(const NameValuePairs &parameters);
+
+private:
+	/// \brief Provides the default decoding lookup table
+	/// \return default decoding lookup table
+	static const int * CRYPTOPP_API GetDefaultDecodingLookupArray();
+};
+
+/// \brief Base32 encodes data using extended hex
+/// \details Converts data to base32 using extended hex alphabet. The alphabet is different than Base32Encoder.
+/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, <A HREF="http://tools.ietf.org/html/rfc4648#page-10">RFC 4648, Base 32 Encoding with Extended Hex Alphabet</A>.
+/// \since Crypto++ 6.0
+class Base32HexEncoder : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a Base32HexEncoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \param uppercase a flag indicating uppercase output
+	/// \param groupSize the size of the grouping
+	/// \param separator the separator to use between groups
+	/// \param terminator the terminator appeand after processing
+	/// \details Base32HexEncoder() constructs a default encoder. The constructor lacks fields for padding and
+	///   line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it.
+	/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+	Base32HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "")
+		: SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment)
+	{
+		IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator)));
+	}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details The following code modifies the padding and line break parameters for an encoder:
+	///   <pre>
+	///     Base32HexEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);</pre>
+	void IsolatedInitialize(const NameValuePairs &parameters);
+};
+
+/// \brief Base32 decodes data using extended hex
+/// \details Converts data from base32 using extended hex alphabet. The alphabet is different than Base32Decoder.
+/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, <A HREF="http://tools.ietf.org/html/rfc4648#page-10">RFC 4648, Base 32 Encoding with Extended Hex Alphabet</A>.
+/// \since Crypto++ 6.0
+class Base32HexDecoder : public BaseN_Decoder
+{
+public:
+	/// \brief Construct a Base32HexDecoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder
+	Base32HexDecoder(BufferedTransformation *attachment = NULLPTR)
+		: BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	void IsolatedInitialize(const NameValuePairs &parameters);
+
+private:
+	/// \brief Provides the default decoding lookup table
+	/// \return default decoding lookup table
+	static const int * CRYPTOPP_API GetDefaultDecodingLookupArray();
+};
+
+NAMESPACE_END
+
+#endif

+ 158 - 0
cryptopp/base64.h

@@ -0,0 +1,158 @@
+// base64.h - originally written and placed in the public domain by Wei Dai
+
+/// \file base64.h
+/// \brief Classes for the Base64Encoder, Base64Decoder, Base64URLEncoder and Base64URLDecoder
+
+#ifndef CRYPTOPP_BASE64_H
+#define CRYPTOPP_BASE64_H
+
+#include "cryptlib.h"
+#include "basecode.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Base64 encodes data using DUDE
+/// \details Base64 encodes data per <A HREF="http://tools.ietf.org/html/rfc4648#section-4">RFC 4648, Base 64 Encoding</A>.
+class Base64Encoder : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a Base64Encoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \param insertLineBreaks a BufferedTrasformation to attach to this object
+	/// \param maxLineLength the length of a line if line breaks are used
+	/// \details Base64Encoder constructs a default encoder. The constructor lacks a parameter for padding, and you must
+	///   use IsolatedInitialize() to modify the Base64Encoder after construction.
+	/// \sa IsolatedInitialize() for an example of modifying an encoder after construction.
+	Base64Encoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = true, int maxLineLength = 72)
+		: SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment)
+	{
+		IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), insertLineBreaks)(Name::MaxLineLength(), maxLineLength));
+	}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details The following code modifies the padding and line break parameters for an encoder:
+	///   <pre>
+	///     Base64Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);</pre>
+	/// \details You can change the encoding to RFC 4648 web safe alphabet by performing the following:
+	///   <pre>
+	///     Base64Encoder encoder;
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);</pre>
+	/// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and
+	///   the decoder's lookup table.
+	/// \sa Base64URLEncoder for an encoder that provides the web safe alphabet, and Base64Decoder::IsolatedInitialize()
+	///   for an example of modifying a decoder's lookup table after construction.
+	void IsolatedInitialize(const NameValuePairs &parameters);
+};
+
+/// \brief Base64 decodes data using DUDE
+/// \details Base64 encodes data per <A HREF="http://tools.ietf.org/html/rfc4648#section-4">RFC 4648, Base 64 Encoding</A>.
+class Base64Decoder : public BaseN_Decoder
+{
+public:
+	/// \brief Construct a Base64Decoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \sa IsolatedInitialize() for an example of modifying an encoder after construction.
+	Base64Decoder(BufferedTransformation *attachment = NULLPTR)
+		: BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details The default decoding alpahbet is RFC 4868. You can change the to RFC 4868 web safe alphabet
+	///   by performing the following:
+	///   <pre>
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false);
+	///
+	///     Base64Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);</pre>
+	/// \sa Base64URLDecoder for a decoder that provides the web safe alphabet, and Base64Encoder::IsolatedInitialize()
+	///   for an example of modifying an encoder's alphabet after construction.
+	void IsolatedInitialize(const NameValuePairs &parameters);
+
+private:
+	/// \brief Provides the default decoding lookup table
+	/// \return default decoding lookup table
+	static const int * CRYPTOPP_API GetDecodingLookupArray();
+};
+
+/// \brief Base64 encodes data using a web safe alphabet
+/// \details Base64 encodes data per <A HREF="http://tools.ietf.org/html/rfc4648#section-5">RFC 4648, Base 64 Encoding
+///   with URL and Filename Safe Alphabet</A>.
+class Base64URLEncoder : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a Base64URLEncoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \param insertLineBreaks a BufferedTrasformation to attach to this object
+	/// \param maxLineLength the length of a line if line breaks are used
+	/// \details Base64URLEncoder() constructs a default encoder using a web safe alphabet. The constructor ignores
+	///   insertLineBreaks and maxLineLength because the web and URL safe specifications don't use them. They are
+	///   present in the constructor for API compatibility with Base64Encoder so it is a drop-in replacement. The
+	///   constructor also disables padding on the encoder for the same reason.
+	/// \details If you need line breaks or padding, then you must use IsolatedInitialize() to set them
+	///   after constructing a Base64URLEncoder.
+	/// \sa Base64Encoder for an encoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize
+	///   for an example of modifying an encoder after construction.
+	Base64URLEncoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = false, int maxLineLength = -1)
+		: SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment)
+	{
+		CRYPTOPP_UNUSED(insertLineBreaks), CRYPTOPP_UNUSED(maxLineLength);
+		IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), false)(Name::MaxLineLength(), -1)(Name::Pad(),false));
+	}
+
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached
+	///   transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \details The following code modifies the padding and line break parameters for an encoder:
+	///   <pre>
+	///     Base64URLEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Name::Pad(), true)(Name::InsertLineBreaks(), true);
+	///     encoder.IsolatedInitialize(params);</pre>
+	/// \sa Base64Encoder for an encoder that provides a classic alphabet.
+	void IsolatedInitialize(const NameValuePairs &parameters);
+};
+
+/// \brief Base64 decodes data using a web safe alphabet
+/// \details Base64 encodes data per <A HREF="http://tools.ietf.org/html/rfc4648#section-5">RFC 4648, Base 64 Encoding
+///   with URL and Filename Safe Alphabet</A>.
+class Base64URLDecoder : public BaseN_Decoder
+{
+public:
+	/// \brief Construct a Base64URLDecoder
+	/// \param attachment a BufferedTrasformation to attach to this object
+	/// \details Base64URLDecoder() constructs a default decoder using a web safe alphabet.
+	/// \sa Base64Decoder for a decoder that provides a classic alphabet.
+	Base64URLDecoder(BufferedTransformation *attachment = NULLPTR)
+		: BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {}
+
+	/// \brief Initialize or reinitialize this object, without signal propagation
+	/// \param parameters a set of NameValuePairs used to initialize this object
+	/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+	///   number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on
+	///  attached transformations. If initialization should be propagated, then use the Initialize() function.
+	/// \sa Base64Decoder for a decoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize
+	///   for an example of modifying an encoder after construction.
+	void IsolatedInitialize(const NameValuePairs &parameters);
+
+private:
+	/// \brief Provides the default decoding lookup table
+	/// \return default decoding lookup table
+	static const int * CRYPTOPP_API GetDecodingLookupArray();
+};
+
+NAMESPACE_END
+
+#endif

+ 146 - 0
cryptopp/basecode.h

@@ -0,0 +1,146 @@
+// basecode.h - originally written and placed in the public domain by Wei Dai
+
+/// \file
+/// \brief Base classes for working with encoders and decoders.
+
+#ifndef CRYPTOPP_BASECODE_H
+#define CRYPTOPP_BASECODE_H
+
+#include "cryptlib.h"
+#include "filters.h"
+#include "algparam.h"
+#include "argnames.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Encoder for bases that are a power of 2
+class CRYPTOPP_DLL BaseN_Encoder : public Unflushable<Filter>
+{
+public:
+	/// \brief Construct a BaseN_Encoder
+	/// \param attachment a BufferedTransformation to attach to this object
+	BaseN_Encoder(BufferedTransformation *attachment=NULLPTR)
+		: m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0)
+		, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
+			{Detach(attachment);}
+
+	/// \brief Construct a BaseN_Encoder
+	/// \param alphabet table of ASCII characters to use as the alphabet
+	/// \param log2base the log<sub>2</sub>base
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \param padding the character to use as padding
+	/// \pre log2base must be between 1 and 7 inclusive
+	/// \throw InvalidArgument if log2base is not between 1 and 7
+	BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULLPTR, int padding=-1)
+		: m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0)
+		, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
+	{
+		Detach(attachment);
+		BaseN_Encoder::IsolatedInitialize(
+			MakeParameters
+				(Name::EncodingLookupArray(), alphabet)
+				(Name::Log2Base(), log2base)
+				(Name::Pad(), padding != -1)
+				(Name::PaddingByte(), byte(padding)));
+	}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
+
+private:
+	const byte *m_alphabet;
+	int m_padding, m_bitsPerChar, m_outputBlockSize;
+	int m_bytePos, m_bitPos;
+	SecByteBlock m_outBuf;
+};
+
+/// \brief Decoder for bases that are a power of 2
+class CRYPTOPP_DLL BaseN_Decoder : public Unflushable<Filter>
+{
+public:
+	/// \brief Construct a BaseN_Decoder
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \details padding is set to -1, which means use default padding. If not
+	///   required, then the value must be set via IsolatedInitialize().
+	BaseN_Decoder(BufferedTransformation *attachment=NULLPTR)
+		: m_lookup(NULLPTR), m_bitsPerChar(0)
+		, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
+			{Detach(attachment);}
+
+	/// \brief Construct a BaseN_Decoder
+	/// \param lookup table of values
+	/// \param log2base the log<sub>2</sub>base
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \details log2base is the exponent (like 5 in 2<sup>5</sup>), and not
+	///   the number of elements (like 32).
+	/// \details padding is set to -1, which means use default padding. If not
+	///   required, then the value must be set via IsolatedInitialize().
+	BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULLPTR)
+		: m_lookup(NULLPTR), m_bitsPerChar(0)
+		, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
+	{
+		Detach(attachment);
+		BaseN_Decoder::IsolatedInitialize(
+			MakeParameters
+				(Name::DecodingLookupArray(), lookup)
+				(Name::Log2Base(), log2base));
+	}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
+
+	/// \brief Initializes BaseN lookup array
+	/// \param lookup table of values
+	/// \param alphabet table of ASCII characters
+	/// \param base the base for the encoder
+	/// \param caseInsensitive flag indicating whether the alphabet is case sensitivie
+	/// \pre COUNTOF(lookup) == 256
+	/// \pre COUNTOF(alphabet) == base
+	/// \details Internally, the function sets the first 256 elements in the lookup table to
+	///  their value from the alphabet array or -1. base is the number of element (like 32),
+	///  and not an exponent (like 5 in 2<sup>5</sup>)
+	static void CRYPTOPP_API InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive);
+
+private:
+	const int *m_lookup;
+	int m_bitsPerChar, m_outputBlockSize;
+	int m_bytePos, m_bitPos;
+	SecByteBlock m_outBuf;
+};
+
+/// \brief Filter that breaks input stream into groups of fixed size
+class CRYPTOPP_DLL Grouper : public Bufferless<Filter>
+{
+public:
+	/// \brief Construct a Grouper
+	/// \param attachment a BufferedTransformation to attach to this object
+	Grouper(BufferedTransformation *attachment=NULLPTR)
+		: m_groupSize(0), m_counter(0) {Detach(attachment);}
+
+	/// \brief Construct a Grouper
+	/// \param groupSize the size of the grouping
+	/// \param separator the separator to use between groups
+	/// \param terminator the terminator appeand after processing
+	/// \param attachment a BufferedTransformation to attach to this object
+	Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULLPTR)
+		: m_groupSize(0), m_counter(0)
+	{
+		Detach(attachment);
+		Grouper::IsolatedInitialize(
+			MakeParameters
+				(Name::GroupSize(), groupSize)
+				(Name::Separator(), ConstByteArrayParameter(separator))
+				(Name::Terminator(), ConstByteArrayParameter(terminator)));
+	}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
+
+private:
+	SecByteBlock m_separator, m_terminator;
+	size_t m_groupSize, m_counter;
+};
+
+NAMESPACE_END
+
+#endif

+ 105 - 0
cryptopp/bench.h

@@ -0,0 +1,105 @@
+// bench.h - originally written and placed in the public domain by Wei Dai
+//           CryptoPP::Test namespace added by JW in February 2017
+
+#ifndef CRYPTOPP_BENCH_H
+#define CRYPTOPP_BENCH_H
+
+#include "cryptlib.h"
+
+#include <iostream>
+#include <iomanip>
+#include <cmath>
+#include <ctime>
+
+NAMESPACE_BEGIN(CryptoPP)
+NAMESPACE_BEGIN(Test)
+
+// More granular control over benchmarks
+enum TestClass {
+	/// \brief Random number generators
+	UnkeyedRNG=(1<<0),
+	/// \brief Message digests
+	UnkeyedHash=(1<<1),
+	/// \brief Other unkeyed algorithms
+	UnkeyedOther=(1<<2),
+
+	/// \brief Message authentication codes
+	SharedKeyMAC=(1<<3),
+	/// \brief Stream ciphers
+	SharedKeyStream=(1<<4),
+	/// \brief Block ciphers ciphers
+	SharedKeyBlock=(1<<5),
+	/// \brief Other shared key algorithms
+	SharedKeyOther=(1<<6),
+
+	/// \brief Key agreement algorithms over integers
+	PublicKeyAgreement=(1<<7),
+	/// \brief Encryption algorithms over integers
+	PublicKeyEncryption=(1<<8),
+	/// \brief Signature algorithms over integers
+	PublicKeySignature=(1<<9),
+	/// \brief Other public key algorithms over integers
+	PublicKeyOther=(1<<10),
+
+	/// \brief Key agreement algorithms over EC
+	PublicKeyAgreementEC=(1<<11),
+	/// \brief Encryption algorithms over EC
+	PublicKeyEncryptionEC=(1<<12),
+	/// \brief Signature algorithms over EC
+	PublicKeySignatureEC=(1<<13),
+	/// \brief Other public key algorithms over EC
+	PublicKeyOtherEC=(1<<14),
+
+	Unkeyed=UnkeyedRNG|UnkeyedHash|UnkeyedOther,
+	SharedKey=SharedKeyMAC|SharedKeyStream|SharedKeyBlock|SharedKeyOther,
+	PublicKey=PublicKeyAgreement|PublicKeyEncryption|PublicKeySignature|PublicKeyOther,
+	PublicKeyEC=PublicKeyAgreementEC|PublicKeyEncryptionEC|PublicKeySignatureEC|PublicKeyOtherEC,
+
+	All=Unkeyed|SharedKey|PublicKey|PublicKeyEC,
+
+	TestFirst=(0), TestLast=(1<<15)
+};
+
+extern const double CLOCK_TICKS_PER_SECOND;
+extern double g_allocatedTime;
+extern double g_hertz;
+extern double g_logTotal;
+extern unsigned int g_logCount;
+extern const byte defaultKey[];
+
+// Test book keeping
+extern time_t g_testBegin;
+extern time_t g_testEnd;
+
+// Benchmark command handler
+void BenchmarkWithCommand(int argc, const char* const argv[]);
+// Top level, prints preamble and postamble
+void Benchmark(Test::TestClass suites, double t, double hertz);
+// Unkeyed systems
+void BenchmarkUnkeyedAlgorithms(double t, double hertz);
+// Shared key systems
+void BenchmarkSharedKeyedAlgorithms(double t, double hertz);
+// Public key systems over integers
+void BenchmarkPublicKeyAlgorithms(double t, double hertz);
+// Public key systems over elliptic curves
+void BenchmarkEllipticCurveAlgorithms(double t, double hertz);
+
+// These are defined in bench1.cpp
+extern void OutputResultKeying(double iterations, double timeTaken);
+extern void OutputResultBytes(const char *name, const char *provider, double length, double timeTaken);
+extern void OutputResultOperations(const char *name, const char *provider, const char *operation, bool pc, unsigned long iterations, double timeTaken);
+
+// These are defined in bench1.cpp
+extern void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal);
+extern void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal);
+extern void BenchMark(const char *name, HashTransformation &ht, double timeTotal);
+extern void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal);
+
+// These are defined in bench2.cpp
+extern void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs &params);
+extern void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal);
+
+NAMESPACE_END  // Test
+NAMESPACE_END  // CryptoPP
+
+#endif

+ 444 - 0
cryptopp/blake2.h

@@ -0,0 +1,444 @@
+// blake2.h - written and placed in the public domain by Jeffrey Walton
+//            and Zooko Wilcox-O'Hearn. Based on Aumasson, Neves,
+//            Wilcox-O'Hearn and Winnerlein's reference BLAKE2
+//            implementation at http://github.com/BLAKE2/BLAKE2.
+
+/// \file blake2.h
+/// \brief Classes for BLAKE2b and BLAKE2s message digests and keyed message digests
+/// \details This implementation follows Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's
+///   <A HREF="http://blake2.net/blake2.pdf">BLAKE2: simpler, smaller, fast as MD5</A> (2013.01.29).
+///   Static algorithm name return either "BLAKE2b" or "BLAKE2s". An object algorithm name follows
+///   the naming described in <A HREF="http://tools.ietf.org/html/rfc7693#section-4">RFC 7693, The
+///   BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)</A>.
+/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0,
+///   Power8 since Crypto++ 8.0
+
+#ifndef CRYPTOPP_BLAKE2_H
+#define CRYPTOPP_BLAKE2_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+#include "seckey.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief BLAKE2s hash information
+/// \since Crypto++ 5.6.4
+struct BLAKE2s_Info : public VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE>
+{
+    typedef VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase;
+    CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH);
+    CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH);
+
+    CRYPTOPP_CONSTANT(BLOCKSIZE = 64);
+    CRYPTOPP_CONSTANT(DIGESTSIZE = 32);
+    CRYPTOPP_CONSTANT(SALTSIZE = 8);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 8);
+
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";}
+};
+
+/// \brief BLAKE2b hash information
+/// \since Crypto++ 5.6.4
+struct BLAKE2b_Info : public VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE>
+{
+    typedef VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase;
+    CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH);
+    CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH);
+
+    CRYPTOPP_CONSTANT(BLOCKSIZE = 128);
+    CRYPTOPP_CONSTANT(DIGESTSIZE = 64);
+    CRYPTOPP_CONSTANT(SALTSIZE = 16);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 16);
+
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";}
+};
+
+/// \brief BLAKE2s parameter block
+struct CRYPTOPP_NO_VTABLE BLAKE2s_ParameterBlock
+{
+    CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE);
+    CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE);
+
+    BLAKE2s_ParameterBlock()
+    {
+        Reset();
+    }
+
+    BLAKE2s_ParameterBlock(size_t digestSize)
+    {
+        Reset(digestSize);
+    }
+
+    BLAKE2s_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength,
+        const byte* personalization, size_t personalizationLength);
+
+    void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0);
+
+    byte* data() {
+        return m_data.data();
+    }
+
+    const byte* data() const {
+        return m_data.data();
+    }
+
+    size_t size() const {
+        return m_data.size();
+    }
+
+    byte* salt() {
+        return m_data + SaltOff;
+    }
+
+    byte* personalization() {
+        return m_data + PersonalizationOff;
+    }
+
+    // Offsets into the byte array
+    enum {
+        DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8,
+        NodeDepthOff = 14, InnerOff = 15, SaltOff = 16, PersonalizationOff = 24
+    };
+
+    FixedSizeAlignedSecBlock<byte, 32, true> m_data;
+};
+
+/// \brief BLAKE2b parameter block
+struct CRYPTOPP_NO_VTABLE BLAKE2b_ParameterBlock
+{
+    CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE);
+    CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE);
+
+    BLAKE2b_ParameterBlock()
+    {
+        Reset();
+    }
+
+    BLAKE2b_ParameterBlock(size_t digestSize)
+    {
+        Reset(digestSize);
+    }
+
+    BLAKE2b_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength,
+        const byte* personalization, size_t personalizationLength);
+
+    void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0);
+
+    byte* data() {
+        return m_data.data();
+    }
+
+    const byte* data() const {
+        return m_data.data();
+    }
+
+    size_t size() const {
+        return m_data.size();
+    }
+
+    byte* salt() {
+        return m_data + SaltOff;
+    }
+
+    byte* personalization() {
+        return m_data + PersonalizationOff;
+    }
+
+    // Offsets into the byte array
+    enum {
+        DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8,
+        NodeDepthOff = 16, InnerOff = 17, RfuOff = 18, SaltOff = 32, PersonalizationOff = 48
+    };
+
+    FixedSizeAlignedSecBlock<byte, 64, true> m_data;
+};
+
+/// \brief BLAKE2s state information
+/// \since Crypto++ 5.6.4
+struct CRYPTOPP_NO_VTABLE BLAKE2s_State
+{
+    BLAKE2s_State() {
+        Reset();
+    }
+
+    void Reset();
+
+    inline word32* h() {
+        return m_hft.data();
+    }
+
+    inline word32* t() {
+        return m_hft.data() + 8;
+    }
+
+    inline word32* f() {
+        return m_hft.data() + 10;
+    }
+
+    inline byte* data() {
+        return m_buf.data();
+    }
+
+    // SSE4, Power7 and NEON depend upon t[] and f[] being side-by-side
+    CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE);
+    FixedSizeAlignedSecBlock<word32, 8+2+2, true> m_hft;
+    FixedSizeAlignedSecBlock<byte, BLOCKSIZE, true> m_buf;
+    size_t m_len;
+};
+
+/// \brief BLAKE2b state information
+/// \since Crypto++ 5.6.4
+struct CRYPTOPP_NO_VTABLE BLAKE2b_State
+{
+    BLAKE2b_State() {
+        Reset();
+    }
+
+    void Reset();
+
+    inline word64* h() {
+        return m_hft.data();
+    }
+
+    inline word64* t() {
+        return m_hft.data() + 8;
+    }
+
+    inline word64* f() {
+        return m_hft.data() + 10;
+    }
+
+    inline byte* data() {
+        return m_buf.data();
+    }
+
+    // SSE4, Power8 and NEON depend upon t[] and f[] being side-by-side
+    CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE);
+    FixedSizeAlignedSecBlock<word64, 8+2+2, true> m_hft;
+    FixedSizeAlignedSecBlock<byte, BLOCKSIZE, true> m_buf;
+    size_t m_len;
+};
+
+/// \brief The BLAKE2s cryptographic hash function
+/// \details BLAKE2s can function as both a hash and keyed hash. If you want only the hash,
+///   then use the BLAKE2s constructor that accepts no parameters or digest size. If you
+///   want a keyed hash, then use the constructor that accpts the key as a parameter.
+///   Once a key and digest size are selected, its effectively immutable. The Restart()
+///   method that accepts a ParameterBlock does not allow you to change it.
+/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's
+///   <A HREF="http://blake2.net/blake2.pdf">BLAKE2: simpler, smaller, fast as MD5</A> (2013.01.29).
+/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0,
+///   Power8 since Crypto++ 8.0
+class BLAKE2s : public SimpleKeyingInterfaceImpl<MessageAuthenticationCode, BLAKE2s_Info>
+{
+public:
+    CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2s_Info::DEFAULT_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2s_Info::MIN_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2s_Info::MAX_KEYLENGTH);
+
+    CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE);
+    CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE);
+    CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE);
+
+    typedef BLAKE2s_State State;
+    typedef BLAKE2s_ParameterBlock ParameterBlock;
+
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";}
+
+    virtual ~BLAKE2s() {}
+
+    /// \brief Construct a BLAKE2s hash
+    /// \param digestSize the digest size, in bytes
+    /// \param treeMode flag indicating tree mode
+    /// \since Crypto++ 5.6.4
+    BLAKE2s(bool treeMode=false, unsigned int digestSize = DIGESTSIZE);
+
+    /// \brief Construct a BLAKE2s hash
+    /// \param digestSize the digest size, in bytes
+    /// \details treeMode flag is set to false
+    /// \since Crypto++ 8.2
+    BLAKE2s(unsigned int digestSize);
+
+    /// \brief Construct a BLAKE2s hash
+    /// \param key a byte array used to key the cipher
+    /// \param keyLength the size of the byte array
+    /// \param salt a byte array used as salt
+    /// \param saltLength the size of the byte array
+    /// \param personalization a byte array used as personalization string
+    /// \param personalizationLength the size of the byte array
+    /// \param treeMode flag indicating tree mode
+    /// \param digestSize the digest size, in bytes
+    /// \since Crypto++ 5.6.4
+    BLAKE2s(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0,
+        const byte* personalization = NULLPTR, size_t personalizationLength = 0,
+        bool treeMode=false, unsigned int digestSize = DIGESTSIZE);
+
+    /// \brief Retrieve the object's name
+    /// \return the object's algorithm name following RFC 7693
+    /// \details Object algorithm name follows the naming described in
+    ///   <A HREF="http://tools.ietf.org/html/rfc7693#section-4">RFC 7693, The BLAKE2 Cryptographic Hash and
+    /// Message Authentication Code (MAC)</A>. For example, "BLAKE2b-512" and "BLAKE2s-256".
+    std::string AlgorithmName() const {return std::string(BLAKE2s_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);}
+
+    unsigned int BlockSize() const {return BLOCKSIZE;}
+    unsigned int DigestSize() const {return m_digestSize;}
+    unsigned int OptimalDataAlignment() const;
+
+    void Update(const byte *input, size_t length);
+    void Restart();
+
+    /// \brief Restart a hash with parameter block and counter
+    /// \param block parameter block
+    /// \param counter counter array
+    /// \details Parameter block is persisted across calls to Restart().
+    void Restart(const BLAKE2s_ParameterBlock& block, const word32 counter[2]);
+
+    /// \brief Set tree mode
+    /// \param mode the new tree mode
+    /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1].
+    ///   If <tt>treeMode=false</tt> (default), then State::f[1] is never set. If
+    ///   <tt>treeMode=true</tt>, then State::f[1] is set when State::f[0] is set.
+    ///   Tree mode is persisted across calls to Restart().
+    void SetTreeMode(bool mode) {m_treeMode=mode;}
+
+    /// \brief Get tree mode
+    /// \return the current tree mode
+    /// \details Tree mode is persisted across calls to Restart().
+    bool GetTreeMode() const {return m_treeMode;}
+
+    void TruncatedFinal(byte *hash, size_t size);
+
+    std::string AlgorithmProvider() const;
+
+protected:
+    // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's.
+    void Compress(const byte *input);
+    inline void IncrementCounter(size_t count=BLOCKSIZE);
+
+    void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params);
+
+private:
+    State m_state;
+    ParameterBlock m_block;
+    AlignedSecByteBlock m_key;
+    word32 m_digestSize, m_keyLength;
+    bool m_treeMode;
+};
+
+/// \brief The BLAKE2b cryptographic hash function
+/// \details BLAKE2b can function as both a hash and keyed hash. If you want only the hash,
+///   then use the BLAKE2b constructor that accepts no parameters or digest size. If you
+///   want a keyed hash, then use the constructor that accpts the key as a parameter.
+///   Once a key and digest size are selected, its effectively immutable. The Restart()
+///   method that accepts a ParameterBlock does not allow you to change it.
+/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's
+///   <A HREF="http://blake2.net/blake2.pdf">BLAKE2: simpler, smaller, fast as MD5</A> (2013.01.29).
+/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0,
+///   Power8 since Crypto++ 8.0
+class BLAKE2b : public SimpleKeyingInterfaceImpl<MessageAuthenticationCode, BLAKE2b_Info>
+{
+public:
+    CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2b_Info::DEFAULT_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2b_Info::MIN_KEYLENGTH);
+    CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2b_Info::MAX_KEYLENGTH);
+
+    CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE);
+    CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE);
+    CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE);
+    CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE);
+
+    typedef BLAKE2b_State State;
+    typedef BLAKE2b_ParameterBlock ParameterBlock;
+
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";}
+
+    virtual ~BLAKE2b() {}
+
+    /// \brief Construct a BLAKE2b hash
+    /// \param digestSize the digest size, in bytes
+    /// \param treeMode flag indicating tree mode
+    /// \since Crypto++ 5.6.4
+    BLAKE2b(bool treeMode=false, unsigned int digestSize = DIGESTSIZE);
+
+    /// \brief Construct a BLAKE2s hash
+    /// \param digestSize the digest size, in bytes
+    /// \details treeMode flag is set to false
+    /// \since Crypto++ 8.2
+    BLAKE2b(unsigned int digestSize);
+
+    /// \brief Construct a BLAKE2b hash
+    /// \param key a byte array used to key the cipher
+    /// \param keyLength the size of the byte array
+    /// \param salt a byte array used as salt
+    /// \param saltLength the size of the byte array
+    /// \param personalization a byte array used as personalization string
+    /// \param personalizationLength the size of the byte array
+    /// \param treeMode flag indicating tree mode
+    /// \param digestSize the digest size, in bytes
+    /// \since Crypto++ 5.6.4
+    BLAKE2b(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0,
+        const byte* personalization = NULLPTR, size_t personalizationLength = 0,
+        bool treeMode=false, unsigned int digestSize = DIGESTSIZE);
+
+    /// \brief Retrieve the object's name
+    /// \return the object's algorithm name following RFC 7693
+    /// \details Object algorithm name follows the naming described in
+    ///   <A HREF="http://tools.ietf.org/html/rfc7693#section-4">RFC 7693, The BLAKE2 Cryptographic Hash and
+    /// Message Authentication Code (MAC)</A>. For example, "BLAKE2b-512" and "BLAKE2s-256".
+    std::string AlgorithmName() const {return std::string(BLAKE2b_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);}
+
+    unsigned int BlockSize() const {return BLOCKSIZE;}
+    unsigned int DigestSize() const {return m_digestSize;}
+    unsigned int OptimalDataAlignment() const;
+
+    void Update(const byte *input, size_t length);
+    void Restart();
+
+    /// \brief Restart a hash with parameter block and counter
+    /// \param block parameter block
+    /// \param counter counter array
+    /// \details Parameter block is persisted across calls to Restart().
+    void Restart(const BLAKE2b_ParameterBlock& block, const word64 counter[2]);
+
+    /// \brief Set tree mode
+    /// \param mode the new tree mode
+    /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1].
+    ///   If <tt>treeMode=false</tt> (default), then State::f[1] is never set. If
+    ///   <tt>treeMode=true</tt>, then State::f[1] is set when State::f[0] is set.
+    ///   Tree mode is persisted across calls to Restart().
+    void SetTreeMode(bool mode) {m_treeMode=mode;}
+
+    /// \brief Get tree mode
+    /// \return the current tree mode
+    /// \details Tree mode is persisted across calls to Restart().
+    bool GetTreeMode() const {return m_treeMode;}
+
+    void TruncatedFinal(byte *hash, size_t size);
+
+    std::string AlgorithmProvider() const;
+
+protected:
+
+    // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's.
+    void Compress(const byte *input);
+    inline void IncrementCounter(size_t count=BLOCKSIZE);
+
+    void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params);
+
+private:
+    State m_state;
+    ParameterBlock m_block;
+    AlignedSecByteBlock m_key;
+    word32 m_digestSize, m_keyLength;
+    bool m_treeMode;
+};
+
+NAMESPACE_END
+
+#endif

+ 54 - 0
cryptopp/blowfish.h

@@ -0,0 +1,54 @@
+// blowfish.h - originally written and placed in the public domain by Wei Dai
+
+/// \file blowfish.h
+/// \brief Classes for the Blowfish block cipher
+
+#ifndef CRYPTOPP_BLOWFISH_H
+#define CRYPTOPP_BLOWFISH_H
+
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Blowfish block cipher information
+struct Blowfish_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 4, 56>, public FixedRounds<16>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Blowfish";}
+};
+
+// <a href="http://www.cryptopp.com/wiki/Blowfish">Blowfish</a>
+
+/// \brief Blowfish block cipher
+/// \since Crypto++ 1.0
+class Blowfish : public Blowfish_Info, public BlockCipherDocumentation
+{
+	/// \brief Class specific implementation and overrides used to operate the cipher.
+	/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<Blowfish_Info>
+	{
+	public:
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+		void UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs &params);
+
+	private:
+		void crypt_block(const word32 in[2], word32 out[2]) const;
+
+		static const word32 p_init[ROUNDS+2];
+		static const word32 s_init[4*256];
+
+		FixedSizeSecBlock<word32, ROUNDS+2> pbox;
+		FixedSizeSecBlock<word32, 4*256> sbox;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+typedef Blowfish::Encryption BlowfishEncryption;
+typedef Blowfish::Decryption BlowfishDecryption;
+
+NAMESPACE_END
+
+#endif

+ 70 - 0
cryptopp/blumshub.h

@@ -0,0 +1,70 @@
+// blumshub.h - originally written and placed in the public domain by Wei Dai
+
+/// \file blumshub.h
+/// \brief Classes for Blum Blum Shub generator
+
+#ifndef CRYPTOPP_BLUMSHUB_H
+#define CRYPTOPP_BLUMSHUB_H
+
+#include "cryptlib.h"
+#include "modarith.h"
+#include "integer.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief BlumBlumShub without factorization of the modulus
+/// \details You should reseed the generator after a fork() to avoid multiple generators
+///  with the same internal state.
+class PublicBlumBlumShub : public RandomNumberGenerator,
+						   public StreamTransformation
+{
+public:
+	virtual ~PublicBlumBlumShub() {}
+
+	/// \brief Construct a PublicBlumBlumShub
+	/// \param n the modulus
+	/// \param seed the seed for the generator
+	/// \details seed is the secret key and should be about as large as n.
+	PublicBlumBlumShub(const Integer &n, const Integer &seed);
+
+	unsigned int GenerateBit();
+	byte GenerateByte();
+	void GenerateBlock(byte *output, size_t size);
+	void ProcessData(byte *outString, const byte *inString, size_t length);
+
+	bool IsSelfInverting() const {return true;}
+	bool IsForwardTransformation() const {return true;}
+
+protected:
+	ModularArithmetic modn;
+	Integer current;
+	word maxBits, bitsLeft;
+};
+
+/// \brief BlumBlumShub with factorization of the modulus
+/// \details You should reseed the generator after a fork() to avoid multiple generators
+///  with the same internal state.
+class BlumBlumShub : public PublicBlumBlumShub
+{
+public:
+	virtual ~BlumBlumShub() {}
+
+	/// \brief Construct a BlumBlumShub
+	/// \param p the first prime factor
+	/// \param q the second prime factor
+	/// \param seed the seed for the generator
+	/// \details Esure p and q are both primes congruent to 3 mod 4 and at least 512 bits long.
+	///  seed is the secret key and should be about as large as p*q.
+	BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed);
+
+	bool IsRandomAccess() const {return true;}
+	void Seek(lword index);
+
+protected:
+	const Integer p, q;
+	const Integer x0;
+};
+
+NAMESPACE_END
+
+#endif

+ 49 - 0
cryptopp/camellia.h

@@ -0,0 +1,49 @@
+// camellia.h - originally written and placed in the public domain by Wei Dai
+
+/// \file camellia.h
+/// \brief Classes for the Camellia block cipher
+
+#ifndef CRYPTOPP_CAMELLIA_H
+#define CRYPTOPP_CAMELLIA_H
+
+#include "config.h"
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Camellia block cipher information
+struct Camellia_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Camellia";}
+};
+
+/// \brief Camellia block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/Camellia">Camellia</a>
+class Camellia : public Camellia_Info, public BlockCipherDocumentation
+{
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<Camellia_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	protected:
+		CRYPTOPP_ALIGN_DATA(4) static const byte s1[256];
+		static const word32 SP[4][256];
+
+		unsigned int m_rounds;
+		SecBlock<word32> m_key;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+typedef Camellia::Encryption CamelliaEncryption;
+typedef Camellia::Decryption CamelliaDecryption;
+
+NAMESPACE_END
+
+#endif

+ 109 - 0
cryptopp/cast.h

@@ -0,0 +1,109 @@
+// cast.h - originally written and placed in the public domain by Wei Dai
+
+/// \file cast.h
+/// \brief Classes for the CAST-128 and CAST-256 block ciphers
+/// \since Crypto++ 2.2
+
+#ifndef CRYPTOPP_CAST_H
+#define CRYPTOPP_CAST_H
+
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief CAST block cipher base
+/// \since Crypto++ 2.2
+class CAST
+{
+protected:
+	static const word32 S[8][256];
+};
+
+/// \brief CAST128 block cipher information
+/// \since Crypto++ 2.2
+struct CAST128_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 5, 16>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-128";}
+};
+
+/// \brief CAST128 block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/CAST-128">CAST-128</a>
+/// \since Crypto++ 2.2
+class CAST128 : public CAST128_Info, public BlockCipherDocumentation
+{
+	/// \brief CAST128 block cipher default operation
+	class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl<CAST128_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+
+	protected:
+		bool reduced;
+		FixedSizeSecBlock<word32, 32> K;
+		mutable FixedSizeSecBlock<word32, 3> m_t;
+	};
+
+	/// \brief CAST128 block cipher encryption operation
+	class CRYPTOPP_NO_VTABLE Enc : public Base
+	{
+	public:
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+	};
+
+	/// \brief CAST128 block cipher decryption operation
+	class CRYPTOPP_NO_VTABLE Dec : public Base
+	{
+	public:
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Dec> Decryption;
+};
+
+/// \brief CAST256 block cipher information
+/// \since Crypto++ 4.0
+struct CAST256_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 4>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-256";}
+};
+
+/// \brief CAST256 block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/CAST-256">CAST-256</a>
+/// \since Crypto++ 4.0
+class CAST256 : public CAST256_Info, public BlockCipherDocumentation
+{
+	/// \brief CAST256 block cipher default operation
+	class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl<CAST256_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	protected:
+		static const word32 t_m[8][24];
+		static const unsigned int t_r[8][24];
+
+		static void Omega(int i, word32 kappa[8]);
+
+		FixedSizeSecBlock<word32, 8*12> K;
+		mutable FixedSizeSecBlock<word32, 8> kappa;
+		mutable FixedSizeSecBlock<word32, 3> m_t;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+typedef CAST128::Encryption CAST128Encryption;
+typedef CAST128::Decryption CAST128Decryption;
+
+typedef CAST256::Encryption CAST256Encryption;
+typedef CAST256::Decryption CAST256Decryption;
+
+NAMESPACE_END
+
+#endif

+ 63 - 0
cryptopp/cbcmac.h

@@ -0,0 +1,63 @@
+// cbcmac.h - originally written and placed in the public domain by Wei Dai
+
+/// \file
+/// \brief Classes for CBC MAC
+/// \since Crypto++ 3.1
+
+#ifndef CRYPTOPP_CBCMAC_H
+#define CRYPTOPP_CBCMAC_H
+
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief CBC-MAC base class
+/// \since Crypto++ 3.1
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_MAC_Base : public MessageAuthenticationCode
+{
+public:
+	CBC_MAC_Base() : m_counter(0) {}
+
+	void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *mac, size_t size);
+	unsigned int DigestSize() const {return const_cast<CBC_MAC_Base*>(this)->AccessCipher().BlockSize();}
+
+protected:
+	virtual BlockCipher & AccessCipher() =0;
+
+private:
+	void ProcessBuf();
+	SecByteBlock m_reg;
+	unsigned int m_counter;
+};
+
+/// \brief CBC-MAC
+/// \tparam T BlockCipherDocumentation derived class
+/// \details CBC-MAC is compatible with FIPS 113. The MAC is secure only for fixed
+///   length messages. For variable length messages use CMAC or DMAC.
+/// \sa <a href="http://www.weidai.com/scan-mirror/mac.html#CBC-MAC">CBC-MAC</a>
+/// \since Crypto++ 3.1
+template <class T>
+class CBC_MAC : public MessageAuthenticationCodeImpl<CBC_MAC_Base, CBC_MAC<T> >, public SameKeyLengthAs<T>
+{
+public:
+	/// \brief Construct a CBC_MAC
+	CBC_MAC() {}
+	/// \brief Construct a CBC_MAC
+	/// \param key a byte buffer used to key the cipher
+	/// \param length the length of the byte buffer
+	CBC_MAC(const byte *key, size_t length=SameKeyLengthAs<T>::DEFAULT_KEYLENGTH)
+		{this->SetKey(key, length);}
+
+	static std::string StaticAlgorithmName() {return std::string("CBC-MAC(") + T::StaticAlgorithmName() + ")";}
+
+private:
+	BlockCipher & AccessCipher() {return m_cipher;}
+	typename T::Encryption m_cipher;
+};
+
+NAMESPACE_END
+
+#endif

+ 123 - 0
cryptopp/ccm.h

@@ -0,0 +1,123 @@
+// ccm.h - originally written and placed in the public domain by Wei Dai
+
+/// \file ccm.h
+/// \brief CCM block cipher mode of operation
+/// \since Crypto++ 5.6.0
+
+#ifndef CRYPTOPP_CCM_H
+#define CRYPTOPP_CCM_H
+
+#include "authenc.h"
+#include "modes.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief CCM block cipher base implementation
+/// \details Base implementation of the AuthenticatedSymmetricCipher interface
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CCM_Base : public AuthenticatedSymmetricCipherBase
+{
+public:
+	CCM_Base()
+		: m_digestSize(0), m_L(0), m_messageLength(0), m_aadLength(0) {}
+
+	// AuthenticatedSymmetricCipher
+	std::string AlgorithmName() const
+		{return GetBlockCipher().AlgorithmName() + std::string("/CCM");}
+	std::string AlgorithmProvider() const
+		{return GetBlockCipher().AlgorithmProvider();}
+	size_t MinKeyLength() const
+		{return GetBlockCipher().MinKeyLength();}
+	size_t MaxKeyLength() const
+		{return GetBlockCipher().MaxKeyLength();}
+	size_t DefaultKeyLength() const
+		{return GetBlockCipher().DefaultKeyLength();}
+	size_t GetValidKeyLength(size_t keylength) const
+		{return GetBlockCipher().GetValidKeyLength(keylength);}
+	bool IsValidKeyLength(size_t keylength) const
+		{return GetBlockCipher().IsValidKeyLength(keylength);}
+	unsigned int OptimalDataAlignment() const
+		{return GetBlockCipher().OptimalDataAlignment();}
+	IV_Requirement IVRequirement() const
+		{return UNIQUE_IV;}
+	unsigned int IVSize() const
+		{return 8;}
+	unsigned int MinIVLength() const
+		{return 7;}
+	unsigned int MaxIVLength() const
+		{return 13;}
+	unsigned int DigestSize() const
+		{return m_digestSize;}
+	lword MaxHeaderLength() const
+		{return W64LIT(0)-1;}
+	lword MaxMessageLength() const
+		{return m_L<8 ? (W64LIT(1)<<(8*m_L))-1 : W64LIT(0)-1;}
+	bool NeedsPrespecifiedDataLengths() const
+		{return true;}
+	void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength);
+
+protected:
+	// AuthenticatedSymmetricCipherBase
+	bool AuthenticationIsOnPlaintext() const
+		{return true;}
+	unsigned int AuthenticationBlockSize() const
+		{return GetBlockCipher().BlockSize();}
+	void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Resync(const byte *iv, size_t len);
+	size_t AuthenticateBlocks(const byte *data, size_t len);
+	void AuthenticateLastHeaderBlock();
+	void AuthenticateLastConfidentialBlock();
+	void AuthenticateLastFooterBlock(byte *mac, size_t macSize);
+	SymmetricCipher & AccessSymmetricCipher() {return m_ctr;}
+
+	virtual BlockCipher & AccessBlockCipher() =0;
+	virtual int DefaultDigestSize() const =0;
+
+	const BlockCipher & GetBlockCipher() const {return const_cast<CCM_Base *>(this)->AccessBlockCipher();}
+	byte *CBC_Buffer() {return m_buffer+REQUIRED_BLOCKSIZE;}
+
+	enum {REQUIRED_BLOCKSIZE = 16};
+	int m_digestSize, m_L;
+	word64 m_messageLength, m_aadLength;
+	CTR_Mode_ExternalCipher::Encryption m_ctr;
+};
+
+/// \brief CCM block cipher final implementation
+/// \tparam T_BlockCipher block cipher
+/// \tparam T_DefaultDigestSize default digest size, in bytes
+/// \tparam T_IsEncryption direction in which to operate the cipher
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher, int T_DefaultDigestSize, bool T_IsEncryption>
+class CCM_Final : public CCM_Base
+{
+public:
+	static std::string StaticAlgorithmName()
+		{return T_BlockCipher::StaticAlgorithmName() + std::string("/CCM");}
+	bool IsForwardTransformation() const
+		{return T_IsEncryption;}
+
+private:
+	BlockCipher & AccessBlockCipher() {return m_cipher;}
+	int DefaultDigestSize() const {return T_DefaultDigestSize;}
+	typename T_BlockCipher::Encryption m_cipher;
+};
+
+/// \brief CCM block cipher mode of operation
+/// \tparam T_BlockCipher block cipher
+/// \tparam T_DefaultDigestSize default digest size, in bytes
+/// \details \p CCM provides the \p Encryption and \p Decryption typedef. See GCM_Base
+///   and GCM_Final for the AuthenticatedSymmetricCipher implementation.
+/// \sa <a href="http://www.cryptopp.com/wiki/CCM_Mode">CCM Mode</a> and
+///   <A HREF="http://www.cryptopp.com/wiki/Modes_of_Operation">Modes of Operation</A>
+///   on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher, int T_DefaultDigestSize = 16>
+struct CCM : public AuthenticatedSymmetricCipherDocumentation
+{
+	typedef CCM_Final<T_BlockCipher, T_DefaultDigestSize, true> Encryption;
+	typedef CCM_Final<T_BlockCipher, T_DefaultDigestSize, false> Decryption;
+};
+
+NAMESPACE_END
+
+#endif

+ 223 - 0
cryptopp/chacha.h

@@ -0,0 +1,223 @@
+// chacha.h - written and placed in the public domain by Jeffrey Walton.
+//            Based on Wei Dai's Salsa20, Botan's SSE2 implementation,
+//            and Bernstein's reference ChaCha family implementation at
+//            http://cr.yp.to/chacha.html.
+
+// The library added Bernstein's ChaCha classes at Crypto++ 5.6.4. The IETF
+// uses a slightly different implementation than Bernstein, and the IETF
+// ChaCha and XChaCha classes were added at Crypto++ 8.1. We wanted to maintain
+// ABI compatibility at the 8.1 release so the original ChaCha classes were not
+// disturbed. Instead new classes were added for IETF ChaCha. The back-end
+// implementation shares code as expected, however.
+
+/// \file chacha.h
+/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers
+/// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from <a
+///  href="http://cr.yp.to/chacha/chacha-20080128.pdf">ChaCha, a
+///  variant of Salsa20</a> (2008.01.28). Crypto++ also provides the
+///  IETF implementation of ChaCha using the ChaChaTLS name. Bernstein's
+///  implementation is _slightly_ different from the TLS working group's
+///  implementation for cipher suites
+///  <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
+///  <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
+///  and <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>. Finally,
+///  the library provides <a
+///  href="https://tools.ietf.org/html/draft-arciszewski-xchacha">XChaCha:
+///  eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03)</a>.
+/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS and XChaCha20 since Crypto++ 8.1
+
+#ifndef CRYPTOPP_CHACHA_H
+#define CRYPTOPP_CHACHA_H
+
+#include "strciphr.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+////////////////////////////// Bernstein ChaCha //////////////////////////////
+
+/// \brief ChaCha stream cipher information
+/// \since Crypto++ 5.6.4
+struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8>
+{
+    /// \brief The algorithm name
+    /// \return the algorithm name
+    /// \details StaticAlgorithmName returns the algorithm's name as a static
+    ///  member function.
+    /// \details Bernstein named the cipher variants ChaCha8, ChaCha12 and
+    ///  ChaCha20. More generally, Bernstein called the family ChaCha{r}.
+    ///  AlgorithmName() provides the exact name once rounds are set.
+    static const char* StaticAlgorithmName() {
+        return "ChaCha";
+    }
+};
+
+/// \brief ChaCha stream cipher implementation
+/// \since Crypto++ 5.6.4
+class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy<word32, 16>
+{
+public:
+    virtual ~ChaCha_Policy() {}
+    ChaCha_Policy() : m_rounds(ROUNDS) {}
+
+protected:
+    void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
+    void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
+    void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length);
+    bool CipherIsRandomAccess() const {return true;}
+    void SeekToIteration(lword iterationCount);
+    unsigned int GetAlignment() const;
+    unsigned int GetOptimalBlockSize() const;
+
+    std::string AlgorithmName() const;
+    std::string AlgorithmProvider() const;
+
+    CRYPTOPP_CONSTANT(ROUNDS = 20);  // Default rounds
+    FixedSizeAlignedSecBlock<word32, 16> m_state;
+    unsigned int m_rounds;
+};
+
+/// \brief ChaCha stream cipher
+/// \details This is Bernstein and ECRYPT's ChaCha. It is _slightly_ different
+///  from the IETF's version of ChaCha called ChaChaTLS.
+/// \sa <a href="http://cr.yp.to/chacha/chacha-20080208.pdf">ChaCha, a variant
+///  of Salsa20</a> (2008.01.28).
+/// \since Crypto++ 5.6.4
+struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation
+{
+    /// \brief ChaCha Encryption
+    typedef SymmetricCipherFinal<ConcretePolicyHolder<ChaCha_Policy, AdditiveCipherTemplate<> >, ChaCha_Info > Encryption;
+    /// \brief ChaCha Decryption
+    typedef Encryption Decryption;
+};
+
+////////////////////////////// IETF ChaChaTLS //////////////////////////////
+
+/// \brief IETF ChaCha20 stream cipher information
+/// \since Crypto++ 8.1
+struct ChaChaTLS_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 12>, FixedRounds<20>
+{
+    /// \brief The algorithm name
+    /// \return the algorithm name
+    /// \details StaticAlgorithmName returns the algorithm's name as a static
+    ///  member function.
+    /// \details This is the IETF's variant of Bernstein's ChaCha from RFC
+    ///  8439. IETF ChaCha is called ChaChaTLS in the Crypto++ library. It
+    ///  is _slightly_ different from Bernstein's implementation.
+    static const char* StaticAlgorithmName() {
+        return "ChaChaTLS";
+    }
+};
+
+/// \brief IETF ChaCha20 stream cipher implementation
+/// \since Crypto++ 8.1
+class CRYPTOPP_NO_VTABLE ChaChaTLS_Policy : public AdditiveCipherConcretePolicy<word32, 16>
+{
+public:
+    virtual ~ChaChaTLS_Policy() {}
+    ChaChaTLS_Policy() : m_counter(0) {}
+
+protected:
+    void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
+    void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
+    void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length);
+    bool CipherIsRandomAccess() const {return true;}
+    void SeekToIteration(lword iterationCount);
+    unsigned int GetAlignment() const;
+    unsigned int GetOptimalBlockSize() const;
+
+    std::string AlgorithmName() const;
+    std::string AlgorithmProvider() const;
+
+    FixedSizeAlignedSecBlock<word32, 16+8> m_state;
+    unsigned int m_counter;
+    CRYPTOPP_CONSTANT(ROUNDS = ChaChaTLS_Info::ROUNDS);
+    CRYPTOPP_CONSTANT(KEY = 16);  // Index into m_state
+    CRYPTOPP_CONSTANT(CTR = 24);  // Index into m_state
+};
+
+/// \brief IETF ChaCha20 stream cipher
+/// \details This is the IETF's variant of Bernstein's ChaCha from RFC 8439.
+///  IETF ChaCha is called ChaChaTLS in the Crypto++ library. It is
+///  _slightly_ different from the Bernstein implementation. ChaCha-TLS
+///  can be used for cipher suites
+///  <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
+///  <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>, and
+///  <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>.
+/// \sa <a href="https://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and
+///  Poly1305 for IETF Protocols</a>, <A
+///  HREF="https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU">How
+///  to handle block counter wrap in IETF's ChaCha algorithm?</A> and
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/790">Issue
+///  790, ChaChaTLS results when counter block wraps</A>.
+/// \since Crypto++ 8.1
+struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation
+{
+    /// \brief ChaCha-TLS Encryption
+    typedef SymmetricCipherFinal<ConcretePolicyHolder<ChaChaTLS_Policy, AdditiveCipherTemplate<> >, ChaChaTLS_Info > Encryption;
+    /// \brief ChaCha-TLS Decryption
+    typedef Encryption Decryption;
+};
+
+////////////////////////////// IETF XChaCha20 draft //////////////////////////////
+
+/// \brief IETF XChaCha20 stream cipher information
+/// \since Crypto++ 8.1
+struct XChaCha20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24>
+{
+    /// \brief The algorithm name
+    /// \return the algorithm name
+    /// \details StaticAlgorithmName returns the algorithm's name as a static
+    ///  member function.
+    /// \details This is the IETF's XChaCha from draft-arciszewski-xchacha.
+    static const char* StaticAlgorithmName() {
+        return "XChaCha20";
+    }
+};
+
+/// \brief IETF XChaCha20 stream cipher implementation
+/// \since Crypto++ 8.1
+class CRYPTOPP_NO_VTABLE XChaCha20_Policy : public AdditiveCipherConcretePolicy<word32, 16>
+{
+public:
+    virtual ~XChaCha20_Policy() {}
+    XChaCha20_Policy() : m_counter(0), m_rounds(ROUNDS) {}
+
+protected:
+    void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
+    void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
+    void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length);
+    bool CipherIsRandomAccess() const {return false;}
+    void SeekToIteration(lword iterationCount);
+    unsigned int GetAlignment() const;
+    unsigned int GetOptimalBlockSize() const;
+
+    std::string AlgorithmName() const;
+    std::string AlgorithmProvider() const;
+
+    FixedSizeAlignedSecBlock<word32, 16+8> m_state;
+    unsigned int m_counter, m_rounds;
+    CRYPTOPP_CONSTANT(ROUNDS = 20);  // Default rounds
+    CRYPTOPP_CONSTANT(KEY = 16);  // Index into m_state
+};
+
+/// \brief IETF XChaCha20 stream cipher
+/// \details This is the IETF's XChaCha from draft-arciszewski-xchacha.
+/// \sa <a href="https://tools.ietf.org/html/draft-arciszewski-xchacha">XChaCha:
+///  eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03)</a>, <A
+///  HREF="https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU">How
+///  to handle block counter wrap in IETF's ChaCha algorithm?</A> and
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/790">Issue
+///  790, ChaCha20 results when counter block wraps</A>.
+/// \since Crypto++ 8.1
+struct XChaCha20 : public XChaCha20_Info, public SymmetricCipherDocumentation
+{
+    /// \brief XChaCha Encryption
+    typedef SymmetricCipherFinal<ConcretePolicyHolder<XChaCha20_Policy, AdditiveCipherTemplate<> >, XChaCha20_Info > Encryption;
+    /// \brief XChaCha Decryption
+    typedef Encryption Decryption;
+};
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_CHACHA_H

+ 322 - 0
cryptopp/chachapoly.h

@@ -0,0 +1,322 @@
+// chachapoly.h - written and placed in the public domain by Jeffrey Walton
+//                RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc8439
+
+/// \file chachapoly.h
+/// \brief IETF ChaCha20/Poly1305 AEAD scheme
+/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines
+///  ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8,
+///  AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20
+///  and Poly1305.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and Poly1305
+///  for IETF Protocols</A>.
+/// \since Crypto++ 8.1
+
+#ifndef CRYPTOPP_CHACHA_POLY1305_H
+#define CRYPTOPP_CHACHA_POLY1305_H
+
+#include "cryptlib.h"
+#include "authenc.h"
+#include "chacha.h"
+#include "poly1305.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+////////////////////////////// IETF ChaChaTLS //////////////////////////////
+
+/// \brief IETF ChaCha20Poly1305 cipher base implementation
+/// \details Base implementation of the AuthenticatedSymmetricCipher interface
+/// \since Crypto++ 8.1
+class ChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase
+{
+public:
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName()
+		{return "ChaCha20/Poly1305";}
+
+	virtual ~ChaCha20Poly1305_Base() {}
+
+	// AuthenticatedSymmetricCipher
+	std::string AlgorithmName() const
+		{return std::string("ChaCha20/Poly1305");}
+	std::string AlgorithmProvider() const
+		{return GetSymmetricCipher().AlgorithmProvider();}
+	size_t MinKeyLength() const
+		{return 32;}
+	size_t MaxKeyLength() const
+		{return 32;}
+	size_t DefaultKeyLength() const
+		{return 32;}
+	size_t GetValidKeyLength(size_t n) const
+		{CRYPTOPP_UNUSED(n); return 32;}
+	bool IsValidKeyLength(size_t n) const
+		{return n==32;}
+	unsigned int OptimalDataAlignment() const
+		{return GetSymmetricCipher().OptimalDataAlignment();}
+	IV_Requirement IVRequirement() const
+		{return UNIQUE_IV;}
+	unsigned int IVSize() const
+		{return 12;}
+	unsigned int MinIVLength() const
+		{return 12;}
+	unsigned int MaxIVLength() const
+		{return 12;}
+	unsigned int DigestSize() const
+		{return 16;}
+	lword MaxHeaderLength() const
+		{return LWORD_MAX;}  // 2^64-1 bytes
+	lword MaxMessageLength() const
+		{return W64LIT(274877906880);}  // 2^38-1 blocks
+	lword MaxFooterLength() const
+		{return 0;}
+
+	/// \brief Encrypts and calculates a MAC in one call
+	/// \param ciphertext the encryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param aad the AAD buffer
+	/// \param aadLength the size of the AAD buffer, in bytes
+	/// \param message the message buffer
+	/// \param messageLength the size of the messagetext buffer, in bytes
+	/// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function
+	///   truncates the MAC if <tt>macSize < TagSize()</tt>.
+	virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength);
+
+	/// \brief Decrypts and verifies a MAC in one call
+	/// \param message the decryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param aad the AAD buffer
+	/// \param aadLength the size of the AAD buffer, in bytes
+	/// \param ciphertext the cipher buffer
+	/// \param ciphertextLength the size of the ciphertext buffer, in bytes
+	/// \return true if the MAC is valid and the decoding succeeded, false otherwise
+	/// \details DecryptAndVerify() decrypts and verifies the MAC in one call.
+	/// <tt>message</tt> is a decryption buffer and should be at least as large as the ciphertext buffer.
+	/// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC
+	///  is truncated if <tt>macLength < TagSize()</tt>.
+	virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength);
+
+protected:
+	// AuthenticatedSymmetricCipherBase
+	bool AuthenticationIsOnPlaintext() const {return false;}
+	unsigned int AuthenticationBlockSize() const {return 1;}
+	void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Resync(const byte *iv, size_t len);
+	size_t AuthenticateBlocks(const byte *data, size_t len);
+	void AuthenticateLastHeaderBlock();
+	void AuthenticateLastConfidentialBlock();
+	void AuthenticateLastFooterBlock(byte *mac, size_t macSize);
+
+	// See comments in chachapoly.cpp
+	void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs &params);
+
+	virtual const MessageAuthenticationCode & GetMAC() const = 0;
+	virtual MessageAuthenticationCode & AccessMAC() = 0;
+
+private:
+	SecByteBlock m_userKey;
+};
+
+/// \brief IETF ChaCha20Poly1305 cipher final implementation
+/// \tparam T_IsEncryption flag indicating cipher direction
+/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines
+///  ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8,
+///  AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20
+///  and Poly1305.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and Poly1305
+///  for IETF Protocols</A>.
+/// \since Crypto++ 8.1
+template <bool T_IsEncryption>
+class ChaCha20Poly1305_Final : public ChaCha20Poly1305_Base
+{
+public:
+	virtual ~ChaCha20Poly1305_Final() {}
+
+protected:
+	const SymmetricCipher & GetSymmetricCipher()
+		{return const_cast<ChaCha20Poly1305_Final *>(this)->AccessSymmetricCipher();}
+	SymmetricCipher & AccessSymmetricCipher()
+		{return m_cipher;}
+	bool IsForwardTransformation() const
+		{return T_IsEncryption;}
+
+	const MessageAuthenticationCode & GetMAC() const
+		{return const_cast<ChaCha20Poly1305_Final *>(this)->AccessMAC();}
+	MessageAuthenticationCode & AccessMAC()
+		{return m_mac;}
+
+private:
+	ChaChaTLS::Encryption m_cipher;
+	Poly1305TLS m_mac;
+};
+
+/// \brief IETF ChaCha20/Poly1305 AEAD scheme
+/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines
+///  ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8,
+///  AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20
+///  and Poly1305.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and Poly1305
+///  for IETF Protocols</A>.
+/// \since Crypto++ 8.1
+struct ChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation
+{
+	/// \brief ChaCha20Poly1305 encryption
+	typedef ChaCha20Poly1305_Final<true> Encryption;
+	/// \brief ChaCha20Poly1305 decryption
+	typedef ChaCha20Poly1305_Final<false> Decryption;
+};
+
+////////////////////////////// IETF XChaCha20 draft //////////////////////////////
+
+/// \brief IETF XChaCha20Poly1305 cipher base implementation
+/// \details Base implementation of the AuthenticatedSymmetricCipher interface
+/// \since Crypto++ 8.1
+class XChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase
+{
+public:
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName()
+		{return "XChaCha20/Poly1305";}
+
+	virtual ~XChaCha20Poly1305_Base() {}
+
+	// AuthenticatedSymmetricCipher
+	std::string AlgorithmName() const
+		{return std::string("XChaCha20/Poly1305");}
+	std::string AlgorithmProvider() const
+		{return GetSymmetricCipher().AlgorithmProvider();}
+	size_t MinKeyLength() const
+		{return 32;}
+	size_t MaxKeyLength() const
+		{return 32;}
+	size_t DefaultKeyLength() const
+		{return 32;}
+	size_t GetValidKeyLength(size_t n) const
+		{CRYPTOPP_UNUSED(n); return 32;}
+	bool IsValidKeyLength(size_t n) const
+		{return n==32;}
+	unsigned int OptimalDataAlignment() const
+		{return GetSymmetricCipher().OptimalDataAlignment();}
+	IV_Requirement IVRequirement() const
+		{return UNIQUE_IV;}
+	unsigned int IVSize() const
+		{return 24;}
+	unsigned int MinIVLength() const
+		{return 24;}
+	unsigned int MaxIVLength() const
+		{return 24;}
+	unsigned int DigestSize() const
+		{return 16;}
+	lword MaxHeaderLength() const
+		{return LWORD_MAX;}  // 2^64-1 bytes
+	lword MaxMessageLength() const
+		{return W64LIT(274877906880);}  // 2^38-1 blocks
+	lword MaxFooterLength() const
+		{return 0;}
+
+	/// \brief Encrypts and calculates a MAC in one call
+	/// \param ciphertext the encryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param aad the AAD buffer
+	/// \param aadLength the size of the AAD buffer, in bytes
+	/// \param message the message buffer
+	/// \param messageLength the size of the messagetext buffer, in bytes
+	/// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function
+	///   truncates the MAC if <tt>macSize < TagSize()</tt>.
+	virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength);
+
+	/// \brief Decrypts and verifies a MAC in one call
+	/// \param message the decryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param aad the AAD buffer
+	/// \param aadLength the size of the AAD buffer, in bytes
+	/// \param ciphertext the cipher buffer
+	/// \param ciphertextLength the size of the ciphertext buffer, in bytes
+	/// \return true if the MAC is valid and the decoding succeeded, false otherwise
+	/// \details DecryptAndVerify() decrypts and verifies the MAC in one call.
+	/// <tt>message</tt> is a decryption buffer and should be at least as large as the ciphertext buffer.
+	/// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC
+	///  is truncated if <tt>macLength < TagSize()</tt>.
+	virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength);
+
+protected:
+	// AuthenticatedSymmetricCipherBase
+	bool AuthenticationIsOnPlaintext() const {return false;}
+	unsigned int AuthenticationBlockSize() const {return 1;}
+	void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Resync(const byte *iv, size_t len);
+	size_t AuthenticateBlocks(const byte *data, size_t len);
+	void AuthenticateLastHeaderBlock();
+	void AuthenticateLastConfidentialBlock();
+	void AuthenticateLastFooterBlock(byte *mac, size_t macSize);
+
+	// See comments in chachapoly.cpp
+	void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs &params);
+
+	virtual const MessageAuthenticationCode & GetMAC() const = 0;
+	virtual MessageAuthenticationCode & AccessMAC() = 0;
+
+private:
+	SecByteBlock m_userKey;
+};
+
+/// \brief IETF XChaCha20Poly1305 cipher final implementation
+/// \tparam T_IsEncryption flag indicating cipher direction
+/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines
+///  XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8,
+///  AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20
+///  and Poly1305.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and Poly1305
+///  for IETF Protocols</A>.
+/// \since Crypto++ 8.1
+template <bool T_IsEncryption>
+class XChaCha20Poly1305_Final : public XChaCha20Poly1305_Base
+{
+public:
+	virtual ~XChaCha20Poly1305_Final() {}
+
+protected:
+	const SymmetricCipher & GetSymmetricCipher()
+		{return const_cast<XChaCha20Poly1305_Final *>(this)->AccessSymmetricCipher();}
+	SymmetricCipher & AccessSymmetricCipher()
+		{return m_cipher;}
+	bool IsForwardTransformation() const
+		{return T_IsEncryption;}
+
+	const MessageAuthenticationCode & GetMAC() const
+		{return const_cast<XChaCha20Poly1305_Final *>(this)->AccessMAC();}
+	MessageAuthenticationCode & AccessMAC()
+		{return m_mac;}
+
+private:
+	XChaCha20::Encryption m_cipher;
+	Poly1305TLS m_mac;
+};
+
+/// \brief IETF XChaCha20/Poly1305 AEAD scheme
+/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines
+///  XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8,
+///  AEAD_XCHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20
+///  and Poly1305.
+/// \sa <A HREF="http://tools.ietf.org/html/rfc8439">RFC 8439, ChaCha20 and Poly1305
+///  for IETF Protocols</A>.
+/// \since Crypto++ 8.1
+struct XChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation
+{
+	/// \brief XChaCha20Poly1305 encryption
+	typedef XChaCha20Poly1305_Final<true> Encryption;
+	/// \brief XChaCha20Poly1305 decryption
+	typedef XChaCha20Poly1305_Final<false> Decryption;
+};
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_CHACHA_POLY1305_H

+ 179 - 0
cryptopp/cham.h

@@ -0,0 +1,179 @@
+// cham.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton
+//          Based on "CHAM: A Family of Lightweight Block Ciphers for
+//          Resource-Constrained Devices" by Bonwook Koo, Dongyoung Roh,
+//          Hyeonjin Kim, Younghoon Jung, Dong-Geon Lee, and Daesung Kwon
+
+/// \file cham.h
+/// \brief Classes for the CHAM block cipher
+/// \since Crypto++ 8.0
+
+#ifndef CRYPTOPP_CHAM_H
+#define CRYPTOPP_CHAM_H
+
+#include "config.h"
+#include "seckey.h"
+#include "secblock.h"
+#include "algparam.h"
+
+#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86)
+# define CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS 1
+#endif
+
+// Yet another SunStudio/SunCC workaround. Failed self tests
+// in SSE code paths on i386 for SunStudio 12.3 and below.
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120)
+# undef CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief CHAM block cipher information
+/// \since Crypto++ 8.0
+struct CHAM64_Info : public FixedBlockSize<8>, public FixedKeyLength<16>
+{
+    /// \brief The algorithm name
+    /// \return the algorithm name
+    /// \details StaticAlgorithmName returns the algorithm's name as a static
+    ///   member function.
+    static const std::string StaticAlgorithmName()
+    {
+        // Format is Cipher-Blocksize
+        return "CHAM-64";
+    }
+};
+
+/// \brief CHAM block cipher information
+/// \since Crypto++ 8.0
+struct CHAM128_Info : public FixedBlockSize<16>, public VariableKeyLength<16,16,32,16>
+{
+    /// \brief The algorithm name
+    /// \return the algorithm name
+    /// \details StaticAlgorithmName returns the algorithm's name as a static
+    ///   member function.
+    static const std::string StaticAlgorithmName()
+    {
+        // Format is Cipher-Blocksize
+        return "CHAM-128";
+    }
+};
+
+/// \brief CHAM 64-bit block cipher
+/// \details CHAM64 provides 64-bit block size. The valid key size is 128-bit.
+/// \note Crypto++ provides a byte oriented implementation
+/// \sa CHAM128, <a href="http://www.cryptopp.com/wiki/CHAM">CHAM</a>,
+///   <a href="https://pdfs.semanticscholar.org/2f57/61b5c2614cffd58a09cc83c375a2b32a2ed3.pdf">
+///   CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices</a>
+/// \since Crypto++ 8.0
+class CRYPTOPP_NO_VTABLE CHAM64 : public CHAM64_Info, public BlockCipherDocumentation
+{
+public:
+    /// \brief CHAM block cipher transformation functions
+    /// \details Provides implementation common to encryption and decryption
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<CHAM64_Info>
+    {
+    protected:
+        void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params);
+
+        SecBlock<word16> m_rk;
+        mutable FixedSizeSecBlock<word16, 4> m_x;
+        unsigned int m_kw;
+    };
+
+    /// \brief Encryption transformation
+    /// \details Enc provides implementation for encryption transformation. All key and block
+    ///   sizes are supported.
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Enc : public Base
+    {
+    public:
+        void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+    };
+
+    /// \brief Decryption transformation
+    /// \details Dec provides implementation for decryption transformation. All key and block
+    ///   sizes are supported.
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Dec : public Base
+    {
+    public:
+        void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+    };
+
+    /// \brief CHAM64 encryption
+    typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
+    /// \brief CHAM64 decryption
+    typedef BlockCipherFinal<DECRYPTION, Dec> Decryption;
+};
+
+/// \brief CHAM64 encryption
+typedef CHAM64::Encryption CHAM64Encryption;
+/// \brief CHAM64 decryption
+typedef CHAM64::Decryption CHAM64Decryption;
+
+/// \brief CHAM 128-bit block cipher
+/// \details CHAM128 provides 128-bit block size. The valid key size is 128-bit and 256-bit.
+/// \note Crypto++ provides a byte oriented implementation
+/// \sa CHAM64, <a href="http://www.cryptopp.com/wiki/CHAM">CHAM</a>,
+///   <a href="https://pdfs.semanticscholar.org/2f57/61b5c2614cffd58a09cc83c375a2b32a2ed3.pdf">
+///   CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices</a>
+/// \since Crypto++ 8.0
+class CRYPTOPP_NO_VTABLE CHAM128 : public CHAM128_Info, public BlockCipherDocumentation
+{
+public:
+    /// \brief CHAM block cipher transformation functions
+    /// \details Provides implementation common to encryption and decryption
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<CHAM128_Info>
+    {
+    protected:
+        void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params);
+        std::string AlgorithmProvider() const;
+
+        SecBlock<word32> m_rk;
+        mutable FixedSizeSecBlock<word32, 4> m_x;
+        unsigned int m_kw;
+    };
+
+    /// \brief Encryption transformation
+    /// \details Enc provides implementation for encryption transformation. All key and block
+    ///   sizes are supported.
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Enc : public Base
+    {
+    public:
+        void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS
+        size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const;
+#endif
+    };
+
+    /// \brief Decryption transformation
+    /// \details Dec provides implementation for decryption transformation. All key and block
+    ///   sizes are supported.
+    /// \since Crypto++ 8.0
+    class CRYPTOPP_NO_VTABLE Dec : public Base
+    {
+    public:
+        void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS
+        size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const;
+#endif
+    };
+
+    /// \brief CHAM128 encryption
+    typedef BlockCipherFinal<ENCRYPTION, Enc> Encryption;
+    /// \brief CHAM128 decryption
+    typedef BlockCipherFinal<DECRYPTION, Dec> Decryption;
+};
+
+/// \brief CHAM128 encryption
+typedef CHAM128::Encryption CHAM128Encryption;
+/// \brief CHAM128 decryption
+typedef CHAM128::Decryption CHAM128Decryption;
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_CHAM_H

+ 142 - 0
cryptopp/channels.h

@@ -0,0 +1,142 @@
+// channels.h - originally written and placed in the public domain by Wei Dai
+
+/// \file channels.h
+/// \brief Classes for multiple named channels
+
+#ifndef CRYPTOPP_CHANNELS_H
+#define CRYPTOPP_CHANNELS_H
+
+#include "cryptlib.h"
+#include "simple.h"
+#include "smartptr.h"
+#include "stdcpp.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4355)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+#if 0
+/// Route input on default channel to different and/or multiple channels based on message sequence number
+class MessageSwitch : public Sink
+{
+public:
+	void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel);
+	void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel);
+
+	void Put(byte inByte);
+	void Put(const byte *inString, unsigned int length);
+
+	void Flush(bool completeFlush, int propagation=-1);
+	void MessageEnd(int propagation=-1);
+	void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1);
+	void MessageSeriesEnd(int propagation=-1);
+
+private:
+	typedef std::pair<BufferedTransformation *, std::string> Route;
+	struct RangeRoute
+	{
+		RangeRoute(unsigned int begin, unsigned int end, const Route &route)
+			: begin(begin), end(end), route(route) {}
+		bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;}
+		unsigned int begin, end;
+		Route route;
+	};
+
+	typedef std::list<RangeRoute> RouteList;
+	typedef std::list<Route> DefaultRouteList;
+
+	RouteList m_routes;
+	DefaultRouteList m_defaultRoutes;
+	unsigned int m_nCurrentMessage;
+};
+#endif
+
+class ChannelSwitchTypedefs
+{
+public:
+	typedef std::pair<BufferedTransformation *, std::string> Route;
+	typedef std::multimap<std::string, Route> RouteMap;
+
+	typedef std::pair<BufferedTransformation *, value_ptr<std::string> > DefaultRoute;
+	typedef std::list<DefaultRoute> DefaultRouteList;
+
+	// SunCC workaround: can't use const_iterator here
+	typedef RouteMap::iterator MapIterator;
+	typedef DefaultRouteList::iterator ListIterator;
+};
+
+class ChannelSwitch;
+
+class ChannelRouteIterator : public ChannelSwitchTypedefs
+{
+public:
+	ChannelRouteIterator(ChannelSwitch &cs) : m_cs(cs), m_useDefault(false) {}
+
+	void Reset(const std::string &channel);
+	bool End() const;
+	void Next();
+	BufferedTransformation & Destination();
+	const std::string & Channel();
+
+	ChannelSwitch& m_cs;
+	std::string m_channel;
+	bool m_useDefault;
+	MapIterator m_itMapCurrent, m_itMapEnd;
+	ListIterator m_itListCurrent, m_itListEnd;
+
+protected:
+	// Hide this to see if we break something...
+	ChannelRouteIterator();
+};
+
+/// Route input to different and/or multiple channels based on channel ID
+class CRYPTOPP_DLL ChannelSwitch : public Multichannel<Sink>, public ChannelSwitchTypedefs
+{
+public:
+	ChannelSwitch() : m_it(*this), m_blocked(false) {}
+	ChannelSwitch(BufferedTransformation &destination) : m_it(*this), m_blocked(false)
+	{
+		AddDefaultRoute(destination);
+	}
+	ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) : m_it(*this), m_blocked(false)
+	{
+		AddDefaultRoute(destination, outChannel);
+	}
+
+	void IsolatedInitialize(const NameValuePairs &parameters=g_nullNameValuePairs);
+
+	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking);
+	size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking);
+
+	bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true);
+	bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true);
+
+	byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
+
+	void AddDefaultRoute(BufferedTransformation &destination);
+	void RemoveDefaultRoute(BufferedTransformation &destination);
+	void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel);
+	void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel);
+	void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel);
+	void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel);
+
+private:
+	RouteMap m_routeMap;
+	DefaultRouteList m_defaultRoutes;
+
+	ChannelRouteIterator m_it;
+	bool m_blocked;
+
+	friend class ChannelRouteIterator;
+};
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 76 - 0
cryptopp/cmac.h

@@ -0,0 +1,76 @@
+// cmac.h - originally written and placed in the public domain by Wei Dai
+
+/// \file cmac.h
+/// \brief Classes for CMAC message authentication code
+/// \since Crypto++ 5.6.0
+
+#ifndef CRYPTOPP_CMAC_H
+#define CRYPTOPP_CMAC_H
+
+#include "seckey.h"
+#include "secblock.h"
+
+/// \brief Enable CMAC and wide block ciphers
+/// \details CMAC is only defined for AES. The library can support wide
+///  block ciphers like Kaylna and Threefish since we know the polynomials.
+#ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
+# define CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS 1
+#endif  // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief CMAC base implementation
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CMAC_Base : public MessageAuthenticationCode
+{
+public:
+
+	virtual ~CMAC_Base() {}
+	CMAC_Base() : m_counter(0) {}
+
+	void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *mac, size_t size);
+	unsigned int DigestSize() const {return GetCipher().BlockSize();}
+	unsigned int OptimalBlockSize() const {return GetCipher().BlockSize();}
+	unsigned int OptimalDataAlignment() const {return GetCipher().OptimalDataAlignment();}
+	std::string AlgorithmProvider() const {return GetCipher().AlgorithmProvider();}
+
+protected:
+	friend class EAX_Base;
+
+	const BlockCipher & GetCipher() const {return const_cast<CMAC_Base*>(this)->AccessCipher();}
+	virtual BlockCipher & AccessCipher() =0;
+
+	void ProcessBuf();
+	SecByteBlock m_reg;
+	unsigned int m_counter;
+};
+
+/// \brief CMAC message authentication code
+/// \tparam T block cipher
+/// \details Template parameter T should be a class derived from BlockCipherDocumentation, for example AES, with a block size of 8, 16, or 32.
+/// \sa <a href="http://www.cryptolounge.org/wiki/CMAC">CMAC</a>
+/// \since Crypto++ 5.6.0
+template <class T>
+class CMAC : public MessageAuthenticationCodeImpl<CMAC_Base, CMAC<T> >, public SameKeyLengthAs<T>
+{
+public:
+	/// \brief Construct a CMAC
+	CMAC() {}
+	/// \brief Construct a CMAC
+	/// \param key the MAC key
+	/// \param length the key size, in bytes
+	CMAC(const byte *key, size_t length=SameKeyLengthAs<T>::DEFAULT_KEYLENGTH)
+		{this->SetKey(key, length);}
+
+	static std::string StaticAlgorithmName() {return std::string("CMAC(") + T::StaticAlgorithmName() + ")";}
+
+private:
+	BlockCipher & AccessCipher() {return m_cipher;}
+	typename T::Encryption m_cipher;
+};
+
+NAMESPACE_END
+
+#endif

+ 33 - 0
cryptopp/config.h

@@ -0,0 +1,33 @@
+// config.h - originally written and placed in the public domain by Wei Dai
+
+/// \file config.h
+/// \brief Library configuration file
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+/// \file config.h
+/// \brief Library configuration file
+
+#ifndef CRYPTOPP_CONFIG_H
+#define CRYPTOPP_CONFIG_H
+
+#include "config_align.h"
+#include "config_asm.h"
+#include "config_cpu.h"
+#include "config_cxx.h"
+#include "config_dll.h"
+#include "config_int.h"
+#include "config_misc.h"
+#include "config_ns.h"
+#include "config_os.h"
+#include "config_ver.h"
+
+#endif // CRYPTOPP_CONFIG_H

+ 72 - 0
cryptopp/config_align.h

@@ -0,0 +1,72 @@
+// config_align.h - written and placed in public domain by Jeffrey Walton
+//                  the bits that make up this source file are from the
+//                  library's monolithic config.h.
+
+/// \file config_align.h
+/// \brief Library configuration file
+/// \details <tt>config_align.h</tt> provides defines for aligned memory
+///  allocations.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_align.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_ALIGN_H
+#define CRYPTOPP_CONFIG_ALIGN_H
+
+#include "config_asm.h"  // CRYPTOPP_DISABLE_ASM
+#include "config_cpu.h"  // X86, X32, X64, ARM32, ARM64, etc
+#include "config_cxx.h"  // CRYPTOPP_CXX11_ALIGNAS
+#include "config_ver.h"  // Compiler versions
+
+// Nearly all Intel's and AMD's have SSE. Enable it independent of SSE ASM and intrinsics.
+// ARM NEON and ARMv8 ASIMD only need natural alignment of an element in the vector.
+// Altivec through POWER7 need vector alignment. POWER8 and POWER9 relax the requirement.
+#if defined(CRYPTOPP_DISABLE_ASM)
+	#define CRYPTOPP_BOOL_ALIGN16 0
+#elif (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || \
+       CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
+	#define CRYPTOPP_BOOL_ALIGN16 1
+#else
+	#define CRYPTOPP_BOOL_ALIGN16 0
+#endif
+
+// How to allocate 16-byte aligned memory (for SSE2)
+// posix_memalign see https://forum.kde.org/viewtopic.php?p=66274
+#if defined(CRYPTOPP_MSC_VERSION)
+	#define CRYPTOPP_MM_MALLOC_AVAILABLE
+#elif defined(__linux__) || defined(__sun__) || defined(__CYGWIN__)
+	#define CRYPTOPP_MEMALIGN_AVAILABLE
+#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+	#define CRYPTOPP_MALLOC_ALIGNMENT_IS_16
+#elif (defined(_GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600)) && (_POSIX_ADVISORY_INFO > 0)
+	#define CRYPTOPP_POSIX_MEMALIGN_AVAILABLE
+#else
+	#define CRYPTOPP_NO_ALIGNED_ALLOC
+#endif
+
+// Sun Studio Express 3 (December 2006) provides GCC-style attributes.
+// IBM XL C/C++ alignment modifier per Optimization Guide, pp. 19-20.
+// __IBM_ATTRIBUTES per XLC 12.1 AIX Compiler Manual, p. 473.
+// CRYPTOPP_ALIGN_DATA may not be reliable on AIX.
+#if defined(CRYPTOPP_CXX11_ALIGNAS)
+	#define CRYPTOPP_ALIGN_DATA(x) alignas(x)
+#elif defined(CRYPTOPP_MSC_VERSION)
+	#define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x))
+#elif defined(__GNUC__) || defined(__clang__) || (__SUNPRO_CC >= 0x5100)
+	#define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x)))
+#elif defined(__xlc__) || defined(__xlC__)
+	#define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x)))
+#else
+	#define CRYPTOPP_ALIGN_DATA(x)
+#endif
+
+#endif  // CRYPTOPP_CONFIG_ALIGN_H

+ 492 - 0
cryptopp/config_asm.h

@@ -0,0 +1,492 @@
+// config_asm.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_asm.h
+/// \brief Library configuration file
+/// \details <tt>config_asm.h</tt> provides defines for instruction set
+///  architectures
+///  and inline assembly.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_asm.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_ASM_H
+#define CRYPTOPP_CONFIG_ASM_H
+
+#include "config_os.h"
+#include "config_cpu.h"
+#include "config_ver.h"
+
+// Define this to disable ASM, intrinsics and built-ins. The library code will
+// not explicitly include SSE2 (and above), NEON, Aarch32, Aarch64, or Altivec
+// (and above). Note the compiler may use higher ISAs depending on compiler
+// options, but the library will not explicitly use the ISAs. When disabling ASM,
+// it is best to do it from config_asm.h to ensure the library and all programs
+// share the setting.
+// #define CRYPTOPP_DISABLE_ASM 1
+
+// https://github.com/weidai11/cryptopp/issues/719
+#if defined(__native_client__)
+# undef CRYPTOPP_DISABLE_ASM
+# define CRYPTOPP_DISABLE_ASM 1
+#endif
+
+// Some Clang and SunCC cannot handle mixed asm with positional arguments,
+// where the body is Intel style with no prefix and the templates are
+// AT&T style. Define this if the Makefile misdetects the configuration.
+// Also see https://bugs.llvm.org/show_bug.cgi?id=39895 .
+// #define CRYPTOPP_DISABLE_MIXED_ASM 1
+
+#if defined(__clang__) || (defined(__APPLE__) && defined(__GNUC__)) || defined(__SUNPRO_CC)
+# undef CRYPTOPP_DISABLE_MIXED_ASM
+# define CRYPTOPP_DISABLE_MIXED_ASM 1
+#endif
+
+// Define this if you need to disable Android advanced ISAs.
+// The problem is, Android-mk does not allow us to specify an
+// ISA option, like -maes or -march=armv8-a+crypto for AES.
+// Lack of an option results in a compile failure. To avoid
+// the compile failure, set this define. Also see
+// https://github.com/weidai11/cryptopp/issues/1015
+// CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA 1
+
+// ***************** IA32 CPU features ********************
+
+#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
+
+// Apple Clang prior to 5.0 cannot handle SSE2
+#if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 50000)
+# define CRYPTOPP_DISABLE_ASM 1
+#endif
+
+// Sun Studio 12.1 provides GCC inline assembly
+// http://blogs.oracle.com/x86be/entry/gcc_style_asm_inlining_support
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5100)
+# define CRYPTOPP_DISABLE_ASM 1
+#endif
+
+// Guard everything in CRYPTOPP_DISABLE_ASM
+#if !defined(CRYPTOPP_DISABLE_ASM)
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || ((defined(__GNUC__) && (defined(__i386__)) || defined(__x86_64__)))
+	// C++Builder 2010 does not allow "call label" where label is defined within inline assembly
+	#define CRYPTOPP_X86_ASM_AVAILABLE 1
+
+	#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__))
+		#define CRYPTOPP_SSE2_ASM_AVAILABLE 1
+	#endif
+
+	#if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1500 || CRYPTOPP_GCC_VERSION >= 40300 || defined(__SSSE3__))
+		#define CRYPTOPP_SSSE3_ASM_AVAILABLE 1
+	#endif
+#endif
+
+#if defined(_MSC_VER) && defined(_M_X64)
+	#define CRYPTOPP_X64_MASM_AVAILABLE 1
+#endif
+
+#if defined(__GNUC__) && defined(__x86_64__)
+	#define CRYPTOPP_X64_ASM_AVAILABLE 1
+#endif
+
+// 32-bit SunCC does not enable SSE2 by default.
+#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(CRYPTOPP_MSC_VERSION) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__) || (__SUNPRO_CC >= 0x5100))
+	#define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1
+#endif
+
+#if !defined(CRYPTOPP_DISABLE_SSSE3)
+# if defined(__SSSE3__) || (CRYPTOPP_MSC_VERSION >= 1500) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)
+	#define CRYPTOPP_SSSE3_AVAILABLE 1
+# endif
+#endif
+
+// Intrinsics available in GCC 4.3 (http://gcc.gnu.org/gcc-4.3/changes.html) and
+// MSVC 2008 (http://msdn.microsoft.com/en-us/library/bb892950%28v=vs.90%29.aspx)
+// SunCC could generate SSE4 at 12.1, but the intrinsics are missing until 12.4.
+#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \
+	(defined(__SSE4_1__) || (CRYPTOPP_MSC_VERSION >= 1500) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000))
+	#define CRYPTOPP_SSE41_AVAILABLE 1
+#endif
+
+#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \
+	(defined(__SSE4_2__) || (CRYPTOPP_MSC_VERSION >= 1500) || (__SUNPRO_CC >= 0x5110) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000))
+	#define CRYPTOPP_SSE42_AVAILABLE 1
+#endif
+
+// Couple to CRYPTOPP_DISABLE_AESNI, but use CRYPTOPP_CLMUL_AVAILABLE so we can selectively
+//  disable for misbehaving platforms and compilers, like Solaris or some Clang.
+#if defined(CRYPTOPP_DISABLE_AESNI)
+	#define CRYPTOPP_DISABLE_CLMUL 1
+#endif
+
+// Requires Sun Studio 12.3 (SunCC 0x5120) in theory.
+#if !defined(CRYPTOPP_DISABLE_CLMUL) && defined(CRYPTOPP_SSE42_AVAILABLE) && \
+	(defined(__PCLMUL__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300))
+	#define CRYPTOPP_CLMUL_AVAILABLE 1
+#endif
+
+// Requires Sun Studio 12.3 (SunCC 0x5120)
+#if !defined(CRYPTOPP_DISABLE_AESNI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \
+	(defined(__AES__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300))
+	#define CRYPTOPP_AESNI_AVAILABLE 1
+#endif
+
+// Requires Binutils 2.24
+#if !defined(CRYPTOPP_DISABLE_AVX) && defined(CRYPTOPP_SSE42_AVAILABLE) && \
+	(defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \
+	(CRYPTOPP_GCC_VERSION >= 40700) || (__INTEL_COMPILER >= 1400) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600))
+#define CRYPTOPP_AVX_AVAILABLE 1
+#endif
+
+// Requires Binutils 2.24
+#if !defined(CRYPTOPP_DISABLE_AVX2) && defined(CRYPTOPP_AVX_AVAILABLE) && \
+	(defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \
+	(CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1400) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600))
+#define CRYPTOPP_AVX2_AVAILABLE 1
+#endif
+
+// Guessing at SHA for SunCC. Its not in Sun Studio 12.6. Also see
+// http://stackoverflow.com/questions/45872180/which-xarch-for-sha-extensions-on-solaris
+// Guessing for Intel ICPC. A slide deck says SHA support is in version 16.0-beta
+// https://www.alcf.anl.gov/files/ken_intel_compiler_optimization.pdf
+#if !defined(CRYPTOPP_DISABLE_SHANI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \
+	(defined(__SHA__) || (CRYPTOPP_MSC_VERSION >= 1900) || (__SUNPRO_CC >= 0x5160) || \
+	(CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1600) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 30400) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50100))
+	#define CRYPTOPP_SHANI_AVAILABLE 1
+#endif
+
+// RDRAND uses byte codes. All we need is x86 ASM for it.
+// However tie it to AES-NI since SecureKey was available with it.
+#if !defined(CRYPTOPP_DISABLE_RDRAND) && defined(CRYPTOPP_AESNI_AVAILABLE)
+	#define CRYPTOPP_RDRAND_AVAILABLE 1
+#endif
+
+// RDSEED uses byte codes. All we need is x86 ASM for it.
+// However tie it to AES-NI since SecureKey was available with it.
+#if !defined(CRYPTOPP_DISABLE_RDSEED) && defined(CRYPTOPP_AESNI_AVAILABLE)
+	#define CRYPTOPP_RDSEED_AVAILABLE 1
+#endif
+
+// PadlockRNG uses byte codes. All we need is x86 ASM for it.
+#if !defined(CRYPTOPP_DISABLE_PADLOCK) && \
+	!(defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__)) && \
+	defined(CRYPTOPP_X86_ASM_AVAILABLE)
+	#define CRYPTOPP_PADLOCK_AVAILABLE 1
+	#define CRYPTOPP_PADLOCK_RNG_AVAILABLE 1
+	#define CRYPTOPP_PADLOCK_ACE_AVAILABLE 1
+	#define CRYPTOPP_PADLOCK_ACE2_AVAILABLE 1
+	#define CRYPTOPP_PADLOCK_PHE_AVAILABLE 1
+	#define CRYPTOPP_PADLOCK_PMM_AVAILABLE 1
+#endif
+
+// Fixup for SunCC 12.1-12.4. Bad code generation in AES_Encrypt and friends.
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5130)
+# undef CRYPTOPP_AESNI_AVAILABLE
+#endif
+
+// Fixup for SunCC 12.1-12.6. Compiler crash on GCM_Reduce_CLMUL.
+// http://github.com/weidai11/cryptopp/issues/226
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5150)
+# undef CRYPTOPP_CLMUL_AVAILABLE
+#endif
+
+// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670
+#define M128_CAST(x) ((__m128i *)(void *)(x))
+#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x))
+#define M256_CAST(x) ((__m256i *)(void *)(x))
+#define CONST_M256_CAST(x) ((const __m256i *)(const void *)(x))
+
+#endif  // CRYPTOPP_DISABLE_ASM
+
+#endif  // X86, X32, X64
+
+// ***************** ARM CPU features ********************
+
+#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8)
+
+// We don't have an ARM big endian test rig. Disable
+// ARM-BE ASM and instrinsics until we can test it.
+#if (CRYPTOPP_BIG_ENDIAN)
+# define CRYPTOPP_DISABLE_ASM 1
+#endif
+
+// Guard everything in CRYPTOPP_DISABLE_ASM
+#if !defined(CRYPTOPP_DISABLE_ASM)
+
+// Requires ACLE 1.0. -mfpu=neon or above must be present
+// Requires GCC 4.3, Clang 2.8 or Visual Studio 2012
+// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead.
+#if !defined(CRYPTOPP_ARM_NEON_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_NEON)
+# if defined(__arm__) || defined(__ARM_NEON) || defined(__ARM_FEATURE_NEON) || defined(_M_ARM)
+#  if (CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || \
+      (CRYPTOPP_APPLE_CLANG_VERSION >= 30200) || (CRYPTOPP_MSC_VERSION >= 1700)
+#   define CRYPTOPP_ARM_NEON_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and ASIMD. -march=armv8-a or above must be present
+// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017
+// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead.
+#if !defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_ASIMD)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
+#  if defined(__ARM_NEON) || defined(__ARM_ASIMD) || defined(__ARM_FEATURE_NEON) || defined(__ARM_FEATURE_ASIMD) || \
+      (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \
+      (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (CRYPTOPP_MSC_VERSION >= 1916)
+#   define CRYPTOPP_ARM_NEON_AVAILABLE 1
+#   define CRYPTOPP_ARM_ASIMD_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and ASIMD. -march=armv8-a+crc or above must be present
+// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017
+#if !defined(CRYPTOPP_ARM_CRC32_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_CRC32)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_CRC32) || (CRYPTOPP_GCC_VERSION >= 40800) || \
+      (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \
+      (CRYPTOPP_MSC_VERSION >= 1916)
+#   define CRYPTOPP_ARM_CRC32_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and AES. -march=armv8-a+crypto or above must be present
+// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017
+#if !defined(CRYPTOPP_ARM_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_AES)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \
+      (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \
+      (CRYPTOPP_MSC_VERSION >= 1916)
+#   define CRYPTOPP_ARM_AES_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and PMULL. -march=armv8-a+crypto or above must be present
+// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017
+#if !defined(CRYPTOPP_ARM_PMULL_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_PMULL)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \
+      (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \
+      (CRYPTOPP_MSC_VERSION >= 1916)
+#   define CRYPTOPP_ARM_PMULL_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and SHA-1, SHA-256. -march=armv8-a+crypto or above must be present
+// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017
+#if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \
+      (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \
+      (CRYPTOPP_MSC_VERSION >= 1916)
+#   define CRYPTOPP_ARM_SHA1_AVAILABLE 1
+#   define CRYPTOPP_ARM_SHA2_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// Buggy Microsoft compiler, https://github.com/weidai11/cryptopp/issues/1096
+#if defined(CRYPTOPP_MSC_VERSION)
+# undef CRYPTOPP_ARM_SHA1_AVAILABLE
+# undef CRYPTOPP_ARM_SHA2_AVAILABLE
+#endif
+
+// ARMv8 and SHA-512, SHA-3. -march=armv8.2-a+crypto or above must be present
+// Requires GCC 8.0, Clang 11.0, Apple Clang 12.0 or Visual Studio 20??
+#if !defined(CRYPTOPP_ARM_SHA3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_SHA3) || (CRYPTOPP_GCC_VERSION >= 80000) || \
+      (CRYPTOPP_APPLE_CLANG_VERSION >= 120000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 110000)
+#   define CRYPTOPP_ARM_SHA512_AVAILABLE 1
+#   define CRYPTOPP_ARM_SHA3_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// ARMv8 and SM3, SM4. -march=armv8.2-a+crypto or above must be present
+// Requires GCC 8.0, Clang ??? or Visual Studio 20??
+// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead.
+#if !defined(CRYPTOPP_ARM_SM3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SM3)
+# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+#  if defined(__ARM_FEATURE_SM3) || (CRYPTOPP_GCC_VERSION >= 80000)
+#   define CRYPTOPP_ARM_SM3_AVAILABLE 1
+#   define CRYPTOPP_ARM_SM4_AVAILABLE 1
+#  endif  // Compilers
+# endif  // Platforms
+#endif
+
+// Limit the <arm_neon.h> include.
+#if !defined(CRYPTOPP_ARM_NEON_HEADER)
+# if defined(CRYPTOPP_ARM_NEON_AVAILABLE) || defined (CRYPTOPP_ARM_ASIMD_AVAILABLE)
+#  if !defined(_M_ARM64)
+#   define CRYPTOPP_ARM_NEON_HEADER 1
+#  endif
+# endif
+#endif
+
+// Limit the <arm_acle.h> include.
+#if !defined(CRYPTOPP_ARM_ACLE_HEADER)
+# if defined(__aarch32__) || defined(__aarch64__) || (__ARM_ARCH >= 8) || defined(__ARM_ACLE)
+#  define CRYPTOPP_ARM_ACLE_HEADER 1
+# endif
+#endif
+
+// Apple M1 hack. Xcode cross-compiles for iOS lack
+// arm_acle.h. Apple M1 needs arm_acle.h. The problem
+// in practice is, we can't get CRYPTOPP_ARM_ACLE_HEADER
+// quite right based on ARM preprocessor macros.
+#if defined(__APPLE__) && !defined(__ARM_FEATURE_CRC32)
+# undef CRYPTOPP_ARM_ACLE_HEADER
+#endif
+
+// Cryptogams offers an ARM asm implementations for AES and SHA. Crypto++ does
+// not provide an asm implementation. The Cryptogams AES implementation is
+// about 50% faster than C/C++, and SHA implementation is about 30% faster
+// than C/C++. Define this to use the Cryptogams AES and SHA implementations
+// on GNU Linux systems. When defined, Crypto++ will use aes_armv4.S,
+// sha1_armv4.S and sha256_armv4.S. https://www.cryptopp.com/wiki/Cryptogams.
+#if !defined(CRYPTOPP_DISABLE_ARM_NEON)
+# if defined(__arm__) && defined(__linux__)
+#  if defined(__GNUC__) || defined(__clang__)
+#   define CRYPTOGAMS_ARM_AES      1
+#   define CRYPTOGAMS_ARM_SHA1     1
+#   define CRYPTOGAMS_ARM_SHA256   1
+#   define CRYPTOGAMS_ARM_SHA512   1
+#  endif
+# endif
+#endif
+
+// We are still having trouble with integrating Cryptogams AES. Ugh...
+// https://github.com/weidai11/cryptopp/issues/1236
+#undef CRYPTOGAMS_ARM_AES
+
+// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670
+#define UINT64_CAST(x) ((uint64_t *)(void *)(x))
+#define CONST_UINT64_CAST(x) ((const uint64_t *)(const void *)(x))
+
+#endif  // CRYPTOPP_DISABLE_ASM
+
+#endif  // ARM32, ARM64
+
+// ***************** AltiVec and Power8 ********************
+
+#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
+
+// Guard everything in CRYPTOPP_DISABLE_ASM
+#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_ALTIVEC)
+
+// An old Apple G5 with GCC 4.01 has AltiVec, but its only Power4 or so.
+#if !defined(CRYPTOPP_ALTIVEC_AVAILABLE)
+# if defined(_ARCH_PWR4) || defined(__ALTIVEC__) || \
+	(CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40001) || \
+    (CRYPTOPP_LLVM_CLANG_VERSION >= 20900)
+#  define CRYPTOPP_ALTIVEC_AVAILABLE 1
+# endif
+#endif
+
+#if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
+
+// We need Power7 for unaligned loads and stores
+#if !defined(CRYPTOPP_POWER7_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER7)
+# if defined(_ARCH_PWR7) || (CRYPTOPP_XLC_VERSION >= 100000) || \
+    (CRYPTOPP_GCC_VERSION >= 40100) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100)
+#  define CRYPTOPP_POWER7_AVAILABLE 1
+# endif
+#endif
+
+#if defined(CRYPTOPP_POWER7_AVAILABLE)
+
+// We need Power8 for in-core crypto and 64-bit vector types
+#if !defined(CRYPTOPP_POWER8_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8)
+# if defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \
+    (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000)
+#  define CRYPTOPP_POWER8_AVAILABLE 1
+# endif
+#endif
+
+#if !defined(CRYPTOPP_POWER8_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8_AES) && defined(CRYPTOPP_POWER8_AVAILABLE)
+# if defined(__CRYPTO__) || defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \
+    (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000)
+//#  define CRYPTOPP_POWER8_CRC_AVAILABLE 1
+#  define CRYPTOPP_POWER8_AES_AVAILABLE 1
+#  define CRYPTOPP_POWER8_VMULL_AVAILABLE 1
+#  define CRYPTOPP_POWER8_SHA_AVAILABLE 1
+# endif
+#endif
+
+#if defined(CRYPTOPP_POWER8_AVAILABLE)
+
+// Power9 for random numbers
+#if !defined(CRYPTOPP_POWER9_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER9)
+# if defined(_ARCH_PWR9) || (CRYPTOPP_XLC_VERSION >= 130200) || \
+    (CRYPTOPP_GCC_VERSION >= 70000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 80000)
+#  define CRYPTOPP_POWER9_AVAILABLE 1
+# endif
+#endif
+
+#endif  // CRYPTOPP_POWER8_AVAILABLE
+#endif  // CRYPTOPP_POWER7_AVAILABLE
+#endif  // CRYPTOPP_ALTIVEC_AVAILABLE
+#endif  // CRYPTOPP_DISABLE_ASM
+#endif  // PPC32, PPC64
+
+// https://github.com/weidai11/cryptopp/issues/1015
+#if defined(CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA)
+# if defined(__ANDROID__) || defined(ANDROID)
+#  if (CRYPTOPP_BOOL_X86)
+#   undef CRYPTOPP_SSE41_AVAILABLE
+#   undef CRYPTOPP_SSE42_AVAILABLE
+#   undef CRYPTOPP_CLMUL_AVAILABLE
+#   undef CRYPTOPP_AESNI_AVAILABLE
+#   undef CRYPTOPP_SHANI_AVAILABLE
+#   undef CRYPTOPP_RDRAND_AVAILABLE
+#   undef CRYPTOPP_RDSEED_AVAILABLE
+#   undef CRYPTOPP_AVX_AVAILABLE
+#   undef CRYPTOPP_AVX2_AVAILABLE
+#  endif
+#  if (CRYPTOPP_BOOL_X64)
+#   undef CRYPTOPP_CLMUL_AVAILABLE
+#   undef CRYPTOPP_AESNI_AVAILABLE
+#   undef CRYPTOPP_SHANI_AVAILABLE
+#   undef CRYPTOPP_RDRAND_AVAILABLE
+#   undef CRYPTOPP_RDSEED_AVAILABLE
+#   undef CRYPTOPP_AVX_AVAILABLE
+#   undef CRYPTOPP_AVX2_AVAILABLE
+#  endif
+#  if (CRYPTOPP_BOOL_ARMV8)
+#   undef CRYPTOPP_ARM_CRC32_AVAILABLE
+#   undef CRYPTOPP_ARM_PMULL_AVAILABLE
+#   undef CRYPTOPP_ARM_AES_AVAILABLE
+#   undef CRYPTOPP_ARM_SHA1_AVAILABLE
+#   undef CRYPTOPP_ARM_SHA2_AVAILABLE
+#  endif
+# endif  // ANDROID
+#endif   // CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA
+
+#endif  // CRYPTOPP_CONFIG_ASM_H

+ 212 - 0
cryptopp/config_cpu.h

@@ -0,0 +1,212 @@
+// config_cpu.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_cpu.h
+/// \brief Library configuration file
+/// \details <tt>config_cpu.h</tt> provides defines for the cpu and machine
+///  architecture.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_cpu.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki,
+///  <A HREF="https://sourceforge.net/p/predef/wiki/Architectures/">Sourceforge
+///  Pre-defined Compiler Macros</A>
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_CPU_H
+#define CRYPTOPP_CONFIG_CPU_H
+
+#include "config_ver.h"
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief 32-bit x32 platform
+	/// \details CRYPTOPP_BOOL_X32 is defined to 1 when building the library
+	///  for a 32-bit x32 platform. Otherwise, the macro is not defined.
+	/// \details x32 is sometimes referred to as x86_32. x32 is the ILP32 data
+	///  model on a 64-bit cpu. Integers, longs and pointers are 32-bit but the
+	///  program runs on a 64-bit cpu.
+	/// \details The significance of x32 is, inline assembly must operate on
+	///  64-bit registers, not 32-bit registers. That means, for example,
+	///  function prologues and epilogues must push and pop RSP, not ESP.
+	/// \note: Clang defines __ILP32__ on any 32-bit platform. Therefore,
+	///  CRYPTOPP_BOOL_X32 depends upon both __ILP32__ and __x86_64__.
+	/// \sa <A HREF="https://wiki.debian.org/X32Port">Debian X32 Port</A>,
+	///  <A HREF="https://wiki.gentoo.org/wiki/Project:Multilib/Concepts">Gentoo
+	///  Multilib Concepts</A>
+	#define CRYPTOPP_BOOL_X32 ...
+	/// \brief 32-bit x86 platform
+	/// \details CRYPTOPP_BOOL_X64 is defined to 1 when building the library
+	///  for a 64-bit x64 platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_X64 ...
+	/// \brief 32-bit x86 platform
+	/// \details CRYPTOPP_BOOL_X86 is defined to 1 when building the library
+	///  for a 32-bit x86 platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_X86 ...
+#elif (defined(__ILP32__) || defined(_ILP32)) && defined(__x86_64__)
+	#define CRYPTOPP_BOOL_X32 1
+#elif (defined(_M_X64) || defined(__x86_64__))
+	#define CRYPTOPP_BOOL_X64 1
+#elif (defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_X86_) || defined(__I86__) || defined(__INTEL__))
+	#define CRYPTOPP_BOOL_X86 1
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief ARMv8 platform
+	/// \details CRYPTOPP_BOOL_ARMV8 is defined to 1 when building the library
+	///  for an ARMv8 platform. Otherwise, the macro is not defined.
+	/// \details ARMv8 includes both Aarch32 and Aarch64. Aarch32 is a 32-bit
+	///  execution environment on Aarch64.
+	#define CRYPTOPP_BOOL_ARMV8 ...
+	/// \brief 64-bit ARM platform
+	/// \details CRYPTOPP_BOOL_ARM64 is defined to 1 when building the library
+	///  for a 64-bit x64 platform. Otherwise, the macro is not defined.
+	/// \details Currently the macro indicates an ARM 64-bit architecture.
+	#define CRYPTOPP_BOOL_ARM64 ...
+	/// \brief 32-bit ARM platform
+	/// \details CRYPTOPP_BOOL_ARM32 is defined to 1 when building the library
+	///  for a 32-bit ARM platform. Otherwise, the macro is not defined.
+	/// \details Currently the macro indicates an ARM A-32 architecture.
+	#define CRYPTOPP_BOOL_ARM32 ...
+#elif defined(__arm64__) || defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
+	// Microsoft added ARM64 define December 2017.
+	#define CRYPTOPP_BOOL_ARMV8 1
+#endif
+#if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
+	#define CRYPTOPP_BOOL_ARM64 1
+#elif defined(__arm__) || defined(_M_ARM)
+	#define CRYPTOPP_BOOL_ARM32 1
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief 64-bit PowerPC platform
+	/// \details CRYPTOPP_BOOL_PPC64 is defined to 1 when building the library
+	///  for a 64-bit PowerPC platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_PPC64 ...
+	/// \brief 32-bit PowerPC platform
+	/// \details CRYPTOPP_BOOL_PPC32 is defined to 1 when building the library
+	///  for a 32-bit PowerPC platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_PPC32 ...
+#elif defined(__ppc64__) || defined(__powerpc64__) || defined(__PPC64__) || defined(_ARCH_PPC64)
+	#define CRYPTOPP_BOOL_PPC64 1
+#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
+	#define CRYPTOPP_BOOL_PPC32 1
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief 64-bit MIPS platform
+	/// \details CRYPTOPP_BOOL_MIPS64 is defined to 1 when building the library
+	///  for a 64-bit MIPS platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_MIPS64 ...
+	/// \brief 64-bit MIPS platform
+	/// \details CRYPTOPP_BOOL_MIPS32 is defined to 1 when building the library
+	///  for a 32-bit MIPS platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_MIPS32 ...
+#elif defined(__mips64__)
+	#define CRYPTOPP_BOOL_MIPS64 1
+#elif defined(__mips__)
+	#define CRYPTOPP_BOOL_MIPS32 1
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief 64-bit SPARC platform
+	/// \details CRYPTOPP_BOOL_SPARC64 is defined to 1 when building the library
+	///  for a 64-bit SPARC platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_SPARC64 ...
+	/// \brief 32-bit SPARC platform
+	/// \details CRYPTOPP_BOOL_SPARC32 is defined to 1 when building the library
+	///  for a 32-bit SPARC platform. Otherwise, the macro is not defined.
+	#define CRYPTOPP_BOOL_SPARC32 ...
+#elif defined(__sparc64__) || defined(__sparc64) || defined(__sparcv9) || defined(__sparc_v9__)
+	#define CRYPTOPP_BOOL_SPARC64 1
+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) || defined(__sparc_v8__)
+	#define CRYPTOPP_BOOL_SPARC32 1
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief L1 data cache line size
+	/// \details CRYPTOPP_L1_CACHE_LINE_SIZE should be a lower bound on the L1
+	///  data cache line size. It is used for defense against some timing attacks.
+	/// \details CRYPTOPP_L1_CACHE_LINE_SIZE default value on 32-bit platforms
+	///  is 32, and the default value on 64-bit platforms is 64. On PowerPC the
+	///  default value is 128 since all PowerPC cpu's starting at PPC 970 provide
+	///  it.
+	/// \note The runtime library on some PowerPC platforms misreport the size
+	///  of the cache line size. The runtime library reports 64, while the cpu
+	///  has a cache line size of 128.
+	/// \sa <A HREF="https://bugs.centos.org/view.php?id=14599">CentOS Issue
+	///  14599: sysconf(_SC_LEVEL1_DCACHE_LINESIZE) returns 0 instead of 128</A>
+	/// \since Crypto++ 5.3
+	#define CRYPTOPP_L1_CACHE_LINE_SIZE ...
+#else
+	#ifndef CRYPTOPP_L1_CACHE_LINE_SIZE
+		#if defined(CRYPTOPP_BOOL_X32) || defined(CRYPTOPP_BOOL_X64) || defined(CRYPTOPP_BOOL_ARMV8) || \
+		    defined(CRYPTOPP_BOOL_MIPS64) || defined(CRYPTOPP_BOOL_SPARC64)
+			#define CRYPTOPP_L1_CACHE_LINE_SIZE 64
+		#elif defined(CRYPTOPP_BOOL_PPC32) || defined(CRYPTOPP_BOOL_PPC64)
+			// http://lists.llvm.org/pipermail/llvm-dev/2017-March/110982.html
+			#define CRYPTOPP_L1_CACHE_LINE_SIZE 128
+		#else
+			// L1 cache line size is 32 on Pentium III and earlier
+			#define CRYPTOPP_L1_CACHE_LINE_SIZE 32
+		#endif
+	#endif
+#endif
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief Initialized data section
+	/// \details CRYPTOPP_SECTION_INIT is added to variables to place them in the
+	///  initialized data section (sometimes denoted <tt>.data</tt>). The placement
+	///  helps avoid "uninitialized variable" warnings from Valgrind and other tools.
+	#define CRYPTOPP_SECTION_INIT ...
+#else
+	// The section attribute attempts to initialize CPU flags to avoid Valgrind findings above -O1
+	#if ((defined(__MACH__) && defined(__APPLE__)) && ((CRYPTOPP_LLVM_CLANG_VERSION >= 30600) || \
+	    (CRYPTOPP_APPLE_CLANG_VERSION >= 70100) || (CRYPTOPP_GCC_VERSION >= 40300)))
+		#define CRYPTOPP_SECTION_INIT __attribute__((section ("__DATA,__data")))
+	#elif (defined(__ELF__) && (CRYPTOPP_GCC_VERSION >= 40300))
+		#define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon")))
+	#elif defined(__ELF__) && (defined(__xlC__) || defined(__ibmxl__))
+		#define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon")))
+	#else
+		#define CRYPTOPP_SECTION_INIT
+	#endif
+#endif
+
+// How to disable CPU feature probing. We determine machine
+// capabilities by performing an os/platform *query* first,
+// like getauxv(). If the *query* fails, we move onto a
+// cpu *probe*. The cpu *probe* tries to exeute an instruction
+// and then catches a SIGILL on Linux or the exception
+// EXCEPTION_ILLEGAL_INSTRUCTION on Windows. Some OSes
+// fail to hangle a SIGILL gracefully, like Apple OSes. Apple
+// machines corrupt memory and variables around the probe.
+#if defined(__APPLE__)
+	#define CRYPTOPP_NO_CPU_FEATURE_PROBES 1
+#endif
+
+// Flavor of inline assembly language
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief Microsoft style inline assembly
+	/// \details CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY is defined when either
+	///  <tt>_MSC_VER</tt> or <tt>__BORLANDC__</tt> are defined.
+	#define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY ...
+	/// \brief GNU style inline assembly
+	/// \details CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY is defined when neither
+	///  <tt>_MSC_VER</tt> nor <tt>__BORLANDC__</tt> are defined.
+	#define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY ...
+#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__) || \
+	defined(CRYPTOPP_MSVC_CLANG_VERSION)
+	#define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY 1
+#else
+	#define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY 1
+#endif
+
+#endif  // CRYPTOPP_CONFIG_CPU_H

+ 250 - 0
cryptopp/config_cxx.h

@@ -0,0 +1,250 @@
+// config_cxx.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_cxx.h
+/// \brief Library configuration file
+/// \details <tt>config_cxx.h</tt> provides defines for C++ language and
+///  runtime library
+///  features.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_cxx.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+// Visual Studio began at VS2010, http://msdn.microsoft.com/en-us/library/hh567368%28v=vs.110%29.aspx
+//   and https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance
+// Intel, http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler
+// GCC, http://gcc.gnu.org/projects/cxx0x.html
+// Clang, http://clang.llvm.org/cxx_status.html
+
+#ifndef CRYPTOPP_CONFIG_CXX_H
+#define CRYPTOPP_CONFIG_CXX_H
+
+#include "config_os.h"
+#include "config_cpu.h"
+#include "config_ver.h"
+
+// https://github.com/weidai11/cryptopp/issues/960
+#include <string>
+#include <exception>
+
+// You may need to force include a C++ header on Android when using STLPort
+// to ensure _STLPORT_VERSION is defined
+#if (defined(CRYPTOPP_MSC_VERSION) && CRYPTOPP_MSC_VERSION <= 1300) || \
+	defined(__MWERKS__) || \
+	(defined(_STLPORT_VERSION) && ((_STLPORT_VERSION < 0x450) || defined(_STLP_NO_UNCAUGHT_EXCEPT_SUPPORT)) || \
+	(__cplusplus >= 202002L))
+#define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION
+#endif
+
+// Ancient Crypto++ define, dating back to C++98.
+#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION
+# define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE 1
+# define CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION 1
+#endif
+
+// Compatibility with non-clang compilers.
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+// C++11 macro version, https://stackoverflow.com/q/7223991/608639
+#if ((CRYPTOPP_MSC_VERSION >= 1600) || (__cplusplus >= 201103L)) && !defined(_STLPORT_VERSION)
+#  define CRYPTOPP_CXX11 1
+#endif
+
+// Hack ahead. Apple's standard library does not have C++'s unique_ptr in C++11.
+// We can't test for unique_ptr directly because some of the non-Apple Clangs
+// on OS X fail the same way. However, modern standard libraries have
+// <forward_list>, so we test for it instead. Thanks to Jonathan Wakely for
+// devising the clever test for modern/ancient versions. TODO: test under
+// Xcode 3, where g++ is really g++.
+#if defined(__APPLE__) && defined(__clang__)
+#  if !(defined(__has_include) && __has_include(<forward_list>))
+#    undef CRYPTOPP_CXX11
+#  endif
+#endif
+
+// C++14 macro version, https://stackoverflow.com/q/26089319/608639
+#if defined(CRYPTOPP_CXX11) && !defined(CRYPTOPP_NO_CXX14)
+#  if ((CRYPTOPP_MSC_VERSION >= 1900) || (__cplusplus >= 201402L)) && !defined(_STLPORT_VERSION)
+#    define CRYPTOPP_CXX14 1
+#  endif
+#endif
+
+// C++17 macro version, https://stackoverflow.com/q/38456127/608639
+#if defined(CRYPTOPP_CXX14) && !defined(CRYPTOPP_NO_CXX17)
+#  if ((CRYPTOPP_MSC_VERSION >= 1900) || (__cplusplus >= 201703L)) && !defined(_STLPORT_VERSION)
+#    define CRYPTOPP_CXX17 1
+#  endif
+#endif
+
+// ***************** C++11 and above ********************
+
+#if defined(CRYPTOPP_CXX11)
+
+// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14.
+#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_atomic) || \
+	(__INTEL_COMPILER >= 1300) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5140)
+# define CRYPTOPP_CXX11_ATOMIC 1
+#endif // atomics
+
+// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13.
+// TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang
+#if (CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \
+	(CRYPTOPP_APPLE_CLANG_VERSION >= 50000) || (__INTEL_COMPILER >= 1200) || \
+	(CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130)
+// Hack ahead. New GCC compilers like GCC 6 on AIX 7.0 or earlier as well as original MinGW
+// don't have the synchronization gear. However, Wakely's test used for Apple does not work
+// on the GCC/AIX combination. Another twist is we need other stuff from C++11,
+// like no-except destructors. Dumping preprocessors shows the following may
+// apply: http://stackoverflow.com/q/14191566/608639.
+# include <cstddef>
+# if !defined(__GLIBCXX__) || defined(_GLIBCXX_HAS_GTHREADS)
+#  define CRYPTOPP_CXX11_SYNCHRONIZATION 1
+# endif
+#endif // synchronization
+
+// Dynamic Initialization and Destruction with Concurrency ("Magic Statics")
+// MS at VS2015 with Vista (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13.
+// Microsoft's implementation only works for Vista and above, so its further
+// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709
+// Clang may not support this as early as we indicate. Also see https://bugs.llvm.org/show_bug.cgi?id=47012.
+#if (__cpp_threadsafe_static_init >= 200806) || \
+	(CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600) || (_WIN32_WINNT >= 0x0600)) || \
+	(CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)  || \
+	(__INTEL_COMPILER >= 1110) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130)
+# define CRYPTOPP_CXX11_STATIC_INIT 1
+#endif // Dynamic Initialization compilers
+
+// deleted functions: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || \
+	(CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1210) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130)
+# define CRYPTOPP_CXX11_DELETED_FUNCTIONS 1
+#endif // deleted functions
+
+// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignas) || \
+	(__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40800) || (__SUNPRO_CC >= 0x5130)
+#  define CRYPTOPP_CXX11_ALIGNAS 1
+#endif // alignas
+
+// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignof) || \
+	(__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40500) || (__SUNPRO_CC >= 0x5130)
+#  define CRYPTOPP_CXX11_ALIGNOF 1
+#endif // alignof
+
+// initializer lists: MS at VS2013 (18.00); GCC at 4.4; Clang at 3.1; Intel 14.0; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || \
+	(CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1400) || \
+	(CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130)
+#  define CRYPTOPP_CXX11_INITIALIZER_LIST 1
+#endif // alignas
+
+// lambdas: MS at VS2012 (17.00); GCC at 4.9; Clang at 3.3; Intel 12.0; SunCC 5.14.
+#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_lambdas) || \
+	(__INTEL_COMPILER >= 1200) || (CRYPTOPP_GCC_VERSION >= 40900) || (__SUNPRO_CC >= 0x5140)
+#  define CRYPTOPP_CXX11_LAMBDA 1
+#endif // lambdas
+
+// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_noexcept) || \
+	(__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130)
+# define CRYPTOPP_CXX11_NOEXCEPT 1
+#endif // noexcept compilers
+
+// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13.
+#if (__cpp_variadic_templates >= 200704) || __has_feature(cxx_variadic_templates) || \
+	(CRYPTOPP_MSC_VERSION >= 1800) || (__INTEL_COMPILER >= 1210) || \
+	(CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130)
+# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1
+#endif // variadic templates
+
+// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13.
+// Intel has mis-supported the feature since at least ICPC 13.00
+#if (__cpp_constexpr >= 200704) || __has_feature(cxx_constexpr) || \
+	(CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1600) || \
+	(CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130)
+# define CRYPTOPP_CXX11_CONSTEXPR 1
+#endif // constexpr compilers
+
+// strong typed enums: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Intel 14.0; SunCC 5.12.
+// Mircorosft and Intel had partial support earlier, but we require full support.
+#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_strong_enums) || \
+	(__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5120)
+# define CRYPTOPP_CXX11_STRONG_ENUM 1
+#endif // constexpr compilers
+
+// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13.
+#if (CRYPTOPP_MSC_VERSION >= 1600) || __has_feature(cxx_nullptr) || \
+	(__INTEL_COMPILER >= 1000) || (CRYPTOPP_GCC_VERSION >= 40600) || \
+    (__SUNPRO_CC >= 0x5130) || defined(__IBMCPP_NULLPTR)
+# define CRYPTOPP_CXX11_NULLPTR 1
+#endif // nullptr_t compilers
+
+#endif // CRYPTOPP_CXX11
+
+// ***************** C++14 and above ********************
+
+#if defined(CRYPTOPP_CXX14)
+
+// Extended static_assert with one argument
+// Microsoft cannot handle the single argument static_assert as of VS2019 (cl.exe 19.00)
+#if (__cpp_static_assert >= 201411)
+# define CRYPTOPP_CXX17_STATIC_ASSERT 1
+#endif // static_assert
+
+#endif
+
+// ***************** C++17 and above ********************
+
+// C++17 is available
+#if defined(CRYPTOPP_CXX17)
+
+// C++17 uncaught_exceptions: MS at VS2015 (19.00); GCC at 6.0; Clang at 3.5; Intel 18.0.
+// Clang and __EXCEPTIONS see http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html
+// Also see https://github.com/weidai11/cryptopp/issues/980. I'm not sure what
+// to do when the compiler defines __cpp_lib_uncaught_exceptions but the platform
+// does not support std::uncaught_exceptions. What was Apple thinking???
+#if defined(__clang__)
+# if __EXCEPTIONS && __has_feature(cxx_exceptions)
+#  if __cpp_lib_uncaught_exceptions >= 201411L
+#   define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1
+#  endif
+# endif
+#elif (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1800) || \
+      (CRYPTOPP_GCC_VERSION >= 60000) || (__cpp_lib_uncaught_exceptions >= 201411L)
+# define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1
+#endif // uncaught_exceptions compilers
+
+#endif  // CRYPTOPP_CXX17
+
+// ***************** C++ fixups ********************
+
+#if defined(CRYPTOPP_CXX11_NOEXCEPT)
+#  define CRYPTOPP_THROW noexcept(false)
+#  define CRYPTOPP_NO_THROW noexcept(true)
+#else
+#  define CRYPTOPP_THROW
+#  define CRYPTOPP_NO_THROW
+#endif // CRYPTOPP_CXX11_NOEXCEPT
+
+// Hack... C++11 nullptr_t type safety and analysis
+#if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR)
+# define NULLPTR nullptr
+#elif !defined(NULLPTR)
+# define NULLPTR NULL
+#endif // CRYPTOPP_CXX11_NULLPTR
+
+#endif  // CRYPTOPP_CONFIG_CXX_H

+ 178 - 0
cryptopp/config_dll.h

@@ -0,0 +1,178 @@
+// config_dll.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_dll.h
+/// \brief Library configuration file
+/// \details <tt>config_dll.h</tt> provides defines for shared objects and
+///  dynamic libraries. Generally speaking the macros are used to export
+///  classes and template classes from the Win32 dynamic link library.
+///  When not building the Win32 dynamic link library they are mostly an extern
+///  template declaration.
+/// \details In practice they are a furball coughed up by a cat and then peed
+///  on by a dog. They are awful to get just right because of inconsistent
+///  compiler support for extern templates, manual instantiation and the FIPS DLL.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_dll.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_DLL_H
+#define CRYPTOPP_CONFIG_DLL_H
+
+#include "config_os.h"
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+
+	/// \brief Win32 define for dynamic link libraries
+	/// \details CRYPTOPP_IMPORTS is set in the Visual Studio project files.
+	///  When the macro is set, <tt>CRYPTOPP_DLL</tt> is defined to
+	///  <tt>__declspec(dllimport)</tt>.
+	/// \details This macro has no effect on Unix &amp; Linux.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_IMPORTS ...
+
+	/// \brief Win32 define for dynamic link libraries
+	/// \details CRYPTOPP_EXPORTS is set in the Visual Studio project files.
+	///  When the macro is set, <tt>CRYPTOPP_DLL</tt> is defined to
+	///  <tt>__declspec(dllexport)</tt>.
+	/// \details This macro has no effect on Unix &amp; Linux.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_EXPORTS ...
+
+	/// \brief Win32 define for dynamic link libraries
+	/// \details CRYPTOPP_IS_DLL is set in the Visual Studio project files.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_IS_DLL
+
+	/// \brief Instantiate templates in a dynamic library
+	/// \details CRYPTOPP_DLL_TEMPLATE_CLASS decoration should be used
+	///  for classes intended to be exported from dynamic link libraries.
+	/// \details This macro is primarily used on Win32, but sees some
+	///  action on Unix &amp; Linux due to the source file <tt>dll.cpp</tt>.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_DLL_TEMPLATE_CLASS ...
+
+	/// \brief Instantiate templates in a dynamic library
+	/// \details CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS decoration should be used
+	///  for template classes intended to be exported from dynamic link libraries.
+	/// \details This macro is primarily used on Win32, but sees some
+	///  action on Unix &amp; Linux due to the source file <tt>dll.cpp</tt>.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS ...
+
+	/// \brief Instantiate templates in a dynamic library
+	/// \details CRYPTOPP_STATIC_TEMPLATE_CLASS decoration should be used
+	///  for template classes intended to be exported from dynamic link libraries.
+	/// \details This macro is primarily used on Win32, but sees some
+	///  action on Unix &amp; Linux due to the source file <tt>dll.cpp</tt>.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_STATIC_TEMPLATE_CLASS ...
+
+	/// \brief Instantiate templates in a dynamic library
+	/// \details CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS decoration should be used
+	///  for template classes intended to be exported from dynamic link libraries.
+	/// \details This macro is primarily used on Win32, but sees some
+	///  action on Unix &amp; Linux due to the source file <tt>dll.cpp</tt>.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>,
+	///  and <A HREF="https://www.cryptopp.com/wiki/FIPS_DLL">FIPS DLL</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS ...
+
+	/// \brief Override for internal linkage
+	/// \details CRYPTOPP_TABLE can be used to override internal linkage
+	///  on tables with the <tt>const</tt> qualifier. According to C++ rules
+	///  a declaration with <tt>const</tt> qualifier is internal linkage.
+	/// \note The name CRYPTOPP_TABLE was chosen because it is often used to
+	///  export a table, like AES or SHA constants. The name avoids collisions
+	///  with the DLL gear macros, like CRYPTOPP_EXPORTS and CRYPTOPP_EXTERN.
+	#define CRYPTOPP_TABLE extern
+
+	/// \brief Win32 calling convention
+	/// \details CRYPTOPP_API sets the calling convention on Win32.
+	///  On Win32 CRYPTOPP_API is <tt>__cedcl</tt>. On Unix &amp; Linux
+	///  CRYPTOPP_API is defined to nothing.
+	/// \sa <A HREF="https://www.cryptopp.com/wiki/Visual_Studio">Visual Studio</A>
+	///  on the Crypto++ wiki
+	#define CRYPTOPP_API ...
+
+#else  // CRYPTOPP_DOXYGEN_PROCESSING
+
+#if defined(CRYPTOPP_WIN32_AVAILABLE)
+
+	#if defined(CRYPTOPP_EXPORTS)
+	#  define CRYPTOPP_IS_DLL
+	#  define CRYPTOPP_DLL __declspec(dllexport)
+	#elif defined(CRYPTOPP_IMPORTS)
+	#  define CRYPTOPP_IS_DLL
+	#  define CRYPTOPP_DLL __declspec(dllimport)
+	#else
+	#  define CRYPTOPP_DLL
+	#endif
+
+	// C++ makes const internal linkage
+	#define CRYPTOPP_TABLE extern
+	#define CRYPTOPP_API __cdecl
+
+#else	// not CRYPTOPP_WIN32_AVAILABLE
+
+	// C++ makes const internal linkage
+	#define CRYPTOPP_TABLE extern
+	#define CRYPTOPP_DLL
+	#define CRYPTOPP_API
+
+#endif	// CRYPTOPP_WIN32_AVAILABLE
+
+#if defined(__MWERKS__)
+#  define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL
+#elif defined(__BORLANDC__) || defined(__SUNPRO_CC)
+#  define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL
+#else
+#  define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL
+#endif
+
+#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS)
+#  define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL
+#else
+#  define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS
+#endif
+
+#if defined(__MWERKS__)
+#  define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class
+#elif defined(__BORLANDC__) || defined(__SUNPRO_CC)
+#  define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class
+#else
+#  define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class
+#endif
+
+#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS)
+#  define CRYPTOPP_STATIC_TEMPLATE_CLASS template class
+#else
+#  define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS
+#endif
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+
+#endif  // CRYPTOPP_CONFIG_DLL_H

+ 268 - 0
cryptopp/config_int.h

@@ -0,0 +1,268 @@
+// config_int.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_int.h
+/// \brief Library configuration file
+/// \details <tt>config_int.h</tt> provides defines and typedefs for fixed
+///  size integers. The library's choices for fixed size integers predates other
+///  standard-based integers by about 5 years. After fixed sizes were
+///  made standard, the library continued to use its own definitions for
+///  compatibility with previous versions of the library.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_int.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_INT_H
+#define CRYPTOPP_CONFIG_INT_H
+
+#include "config_ns.h"
+#include "config_ver.h"
+#include "config_misc.h"
+
+// C5264 new for VS2022/v17.4, MSC v17.3.4
+// https://github.com/weidai11/cryptopp/issues/1185
+#if (CRYPTOPP_MSC_VERSION)
+# pragma warning(push)
+# if (CRYPTOPP_MSC_VERSION >= 1933)
+#  pragma warning(disable: 5264)
+# endif
+#endif
+
+/// \brief Library byte guard
+/// \details CRYPTOPP_NO_GLOBAL_BYTE indicates <tt>byte</tt> is in the Crypto++
+///  namespace.
+/// \details The Crypto++ <tt>byte</tt> was originally in global namespace to avoid
+///  ambiguity with other byte typedefs. <tt>byte</tt> was moved to CryptoPP namespace
+///  at Crypto++ 6.0 due to C++17, <tt>std::byte</tt> and potential compile problems.
+/// \sa <A HREF="http://github.com/weidai11/cryptopp/issues/442">Issue 442</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">std::byte</A> on the
+///  Crypto++ wiki
+/// \since Crypto++ 6.0
+#define CRYPTOPP_NO_GLOBAL_BYTE 1
+
+NAMESPACE_BEGIN(CryptoPP)
+
+// Signed words added at Issue 609 for early versions of and Visual Studio and
+// the NaCl gear. Also see https://github.com/weidai11/cryptopp/issues/609.
+
+/// \brief 8-bit unsigned datatype
+/// \details The Crypto++ <tt>byte</tt> was originally in global namespace to avoid
+///  ambiguity with other byte typedefs. <tt>byte</tt> was moved to CryptoPP namespace
+///  at Crypto++ 6.0 due to C++17, <tt>std::byte</tt> and potential compile problems.
+/// \sa CRYPTOPP_NO_GLOBAL_BYTE, <A HREF="http://github.com/weidai11/cryptopp/issues/442">Issue 442</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">std::byte</A> on the
+///  Crypto++ wiki
+/// \since Crypto++ 1.0, CryptoPP namespace since Crypto++ 6.0
+typedef unsigned char byte;
+/// \brief 16-bit unsigned datatype
+/// \since Crypto++ 1.0
+typedef unsigned short word16;
+/// \brief 32-bit unsigned datatype
+/// \since Crypto++ 1.0
+typedef unsigned int word32;
+
+/// \brief 8-bit signed datatype
+/// \details The 8-bit signed datatype was added to support constant time
+///  implementations for curve25519, X25519 key agreement and ed25519
+///  signatures.
+/// \since Crypto++ 8.0
+typedef signed char sbyte;
+/// \brief 16-bit signed datatype
+/// \details The 32-bit signed datatype was added to support constant time
+///  implementations for curve25519, X25519 key agreement and ed25519
+///  signatures.
+/// \since Crypto++ 8.0
+typedef signed short sword16;
+/// \brief 32-bit signed datatype
+/// \details The 32-bit signed datatype was added to support constant time
+///  implementations for curve25519, X25519 key agreement and ed25519
+///  signatures.
+/// \since Crypto++ 8.0
+typedef signed int sword32;
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+
+	/// \brief 64-bit unsigned datatype
+	/// \details The typedef for <tt>word64</tt> varies depending on the platform.
+	///  On Microsoft platforms it is <tt>unsigned __int64</tt>. On Unix &amp; Linux
+	///  with LP64 data model it is <tt>unsigned long</tt>. On Unix &amp; Linux with ILP32
+	///  data model it is <tt>unsigned long long</tt>.
+	/// \since Crypto++ 1.0
+	typedef unsigned long long word64;
+
+	/// \brief 64-bit signed datatype
+	/// \details The typedef for <tt>sword64</tt> varies depending on the platform.
+	///  On Microsoft platforms it is <tt>signed __int64</tt>. On Unix &amp; Linux
+	///  with LP64 data model it is <tt>signed long</tt>. On Unix &amp; Linux with ILP32
+	///  data model it is <tt>signed long long</tt>.
+	/// \since Crypto++ 8.0
+	typedef signed long long sword64;
+
+	/// \brief 128-bit unsigned datatype
+	/// \details The typedef for <tt>word128</tt> varies depending on the platform.
+	///  <tt>word128</tt> is only available on 64-bit machines when
+	///  <tt>CRYPTOPP_WORD128_AVAILABLE</tt> is defined.
+	///  On Unix &amp; Linux with LP64 data model it is <tt>__uint128_t</tt>.
+	///  Microsoft platforms do not provide a 128-bit integer type. 32-bit platforms
+	///  do not provide a 128-bit integer type.
+	/// \since Crypto++ 5.6
+	typedef __uint128_t word128;
+
+	/// \brief Declare an unsigned word64
+	/// \details W64LIT is used to portability declare or assign 64-bit literal values.
+	///  W64LIT will append the proper suffix to ensure the compiler accepts the literal.
+	/// \details Use the macro like shown below.
+	///  <pre>
+	///    word64 x = W64LIT(0xffffffffffffffff);
+	///  </pre>
+	/// \since Crypto++ 1.0
+	#define W64LIT(x) ...
+
+	/// \brief Declare a signed word64
+	/// \details SW64LIT is used to portability declare or assign 64-bit literal values.
+	///  SW64LIT will append the proper suffix to ensure the compiler accepts the literal.
+	/// \details Use the macro like shown below.
+	///  <pre>
+	///    sword64 x = SW64LIT(0xffffffffffffffff);
+	///  </pre>
+	/// \since Crypto++ 8.0
+	#define SW64LIT(x) ...
+
+	/// \brief Declare ops on word64 are slow
+	/// \details CRYPTOPP_BOOL_SLOW_WORD64 is typically defined to 1 on platforms
+	///  that have a machine word smaller than 64-bits. That is, the define
+	///  is present on 32-bit platforms. The define is also present on platforms
+	///  where the cpu is slow even with a 64-bit cpu.
+	#define CRYPTOPP_BOOL_SLOW_WORD64 ...
+
+#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__)
+	typedef signed __int64 sword64;
+	typedef unsigned __int64 word64;
+	#define SW64LIT(x) x##i64
+	#define W64LIT(x) x##ui64
+#elif (_LP64 || __LP64__)
+	typedef signed long sword64;
+	typedef unsigned long word64;
+	#define SW64LIT(x) x##L
+	#define W64LIT(x) x##UL
+#else
+	typedef signed long long sword64;
+	typedef unsigned long long word64;
+	#define SW64LIT(x) x##LL
+	#define W64LIT(x) x##ULL
+#endif
+
+/// \brief Large word type
+/// \details lword is a typedef for large word types. It is used for file
+///  offsets and such.
+typedef word64 lword;
+
+/// \brief Large word type max value
+/// \details LWORD_MAX is the maximum value for large word types.
+///  Since an <tt>lword</tt> is an unsigned type, the value is
+///  <tt>0xffffffffffffffff</tt>. W64LIT will append the proper suffix.
+CRYPTOPP_CONST_OR_CONSTEXPR lword LWORD_MAX = W64LIT(0xffffffffffffffff);
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+	/// \brief Half word used for multiprecision integer arithmetic
+	/// \details hword is used for multiprecision integer arithmetic.
+	///  The typedef for <tt>hword</tt> varies depending on the platform.
+	///  On 32-bit platforms it is usually <tt>word16</tt>. On 64-bit platforms
+	///  it is usually <tt>word32</tt>.
+	/// \details Library users typically use byte, word16, word32 and word64.
+	/// \since Crypto++ 2.0
+	typedef word32 hword;
+	/// \brief Full word used for multiprecision integer arithmetic
+	/// \details word is used for multiprecision integer arithmetic.
+	///  The typedef for <tt>word</tt> varies depending on the platform.
+	///  On 32-bit platforms it is usually <tt>word32</tt>. On 64-bit platforms
+	///  it is usually <tt>word64</tt>.
+	/// \details Library users typically use byte, word16, word32 and word64.
+	/// \since Crypto++ 2.0
+	typedef word64 word;
+	/// \brief Double word used for multiprecision integer arithmetic
+	/// \details dword is used for multiprecision integer arithmetic.
+	///  The typedef for <tt>dword</tt> varies depending on the platform.
+	///  On 32-bit platforms it is usually <tt>word64</tt>. On 64-bit Unix &amp;
+	///  Linux platforms it is usually <tt>word128</tt>. <tt>word128</tt> is
+	///  not available on Microsoft platforms. <tt>word128</tt> is only available
+	///  when <tt>CRYPTOPP_WORD128_AVAILABLE</tt> is defined.
+	/// \details Library users typically use byte, word16, word32 and word64.
+	/// \sa CRYPTOPP_WORD128_AVAILABLE
+	/// \since Crypto++ 2.0
+	typedef word128 dword;
+
+	/// \brief 128-bit word availability
+	/// \details CRYPTOPP_WORD128_AVAILABLE indicates a 128-bit word is
+	///  available from the platform. 128-bit words are usually available on
+	///  64-bit platforms, but not available 32-bit platforms.
+	/// \details If CRYPTOPP_WORD128_AVAILABLE is not defined, then 128-bit
+	///  words are not available.
+	/// \details GCC and compatible compilers signal 128-bit word availability
+	///  with the preporcessor macro <tt>__SIZEOF_INT128__ >= 16</tt>.
+	/// \since Crypto++ 2.0
+	#define CRYPTOPP_WORD128_AVAILABLE ...
+#else
+	// define hword, word, and dword. these are used for multiprecision integer arithmetic
+	// Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx
+	#if (defined(CRYPTOPP_MSC_VERSION) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(__alpha__)) || (defined(__INTEL_COMPILER) && defined(__x86_64__)) || (defined(__SUNPRO_CC) && defined(__x86_64__))
+		typedef word32 hword;
+		typedef word64 word;
+	#else
+		#define CRYPTOPP_NATIVE_DWORD_AVAILABLE 1
+		#if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || defined(__x86_64__) || defined(__mips64) || defined(__sparc64__) || defined(__aarch64__)
+			#if ((CRYPTOPP_GCC_VERSION >= 30400) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) && (__SIZEOF_INT128__ >= 16)
+				// GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3
+				// GCC 4.8.3 and bad uint128_t ops on PPC64/POWER7 (Issue 421)
+				// mode(TI) division broken on amd64 with GCC earlier than GCC 3.4
+				typedef word32 hword;
+				typedef word64 word;
+				typedef __uint128_t dword;
+				typedef __uint128_t word128;
+				#define CRYPTOPP_WORD128_AVAILABLE 1
+			#else
+				// if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results
+				typedef word16 hword;
+				typedef word32 word;
+				typedef word64 dword;
+			#endif
+		#else
+			// being here means the native register size is probably 32 bits or less
+			#define CRYPTOPP_BOOL_SLOW_WORD64 1
+			typedef word16 hword;
+			typedef word32 word;
+			typedef word64 dword;
+		#endif
+	#endif
+#endif
+
+#ifndef CRYPTOPP_BOOL_SLOW_WORD64
+# define CRYPTOPP_BOOL_SLOW_WORD64 0
+#endif
+
+/// \brief Size of a platform word in bytes
+/// \details The size of a platform word, in bytes
+CRYPTOPP_CONST_OR_CONSTEXPR unsigned int WORD_SIZE = sizeof(word);
+
+/// \brief Size of a platform word in bits
+/// \details The size of a platform word, in bits
+/// \sa https://github.com/weidai11/cryptopp/issues/1185
+CRYPTOPP_CONST_OR_CONSTEXPR unsigned int WORD_BITS = WORD_SIZE * 8;
+
+NAMESPACE_END
+
+#if (CRYPTOPP_MSC_VERSION)
+# pragma warning(pop)
+#endif
+
+#endif  // CRYPTOPP_CONFIG_INT_H

+ 199 - 0
cryptopp/config_misc.h

@@ -0,0 +1,199 @@
+// config_misc.h - written and placed in public domain by Jeffrey Walton
+//                 the bits that make up this source file are from the
+//                 library's monolithic config.h.
+
+/// \file config_misc.h
+/// \brief Library configuration file
+/// \details <tt>config_misc.h</tt> provides miscellaneous defines.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_misc.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_MISC_H
+#define CRYPTOPP_CONFIG_MISC_H
+
+#include "config_asm.h"
+#include "config_cxx.h"
+#include "config_os.h"
+#include "config_ver.h"
+
+// Define this if running on a big-endian CPU
+// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0
+#if !defined(CRYPTOPP_LITTLE_ENDIAN) && !defined(CRYPTOPP_BIG_ENDIAN) && (defined(__BIG_ENDIAN__) || (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || (defined(__m68k__) || defined(__MC68K__)) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__MIPSEB__) || defined(__ARMEB__) || (defined(__MWERKS__) && !defined(__INTEL__)))
+#	define CRYPTOPP_BIG_ENDIAN 1
+#endif
+
+// Define this if running on a little-endian CPU
+// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0
+#if !defined(CRYPTOPP_BIG_ENDIAN) && !defined(CRYPTOPP_LITTLE_ENDIAN)
+#	define CRYPTOPP_LITTLE_ENDIAN 1
+#endif
+
+// Define this if you want to set a prefix for TestData/ and TestVectors/
+// Be sure to add the trailing slash since its simple concatenation.
+// After https://github.com/weidai11/cryptopp/issues/760 the library
+// should find the test vectors and data without much effort. It
+// will search in "./" and "$ORIGIN/../share/cryptopp" automatically.
+#ifndef CRYPTOPP_DATA_DIR
+# define CRYPTOPP_DATA_DIR ""
+#endif
+
+// Define this to disable the test suite from searching for test
+// vectors and data in "./" and "$ORIGIN/../share/cryptopp". The
+// library will still search in CRYPTOPP_DATA_DIR, regardless.
+// Some distros may want to disable this feature. Also see
+// https://github.com/weidai11/cryptopp/issues/760
+// #ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH
+// # define CRYPTOPP_DISABLE_DATA_DIR_SEARCH
+// #endif
+
+// Define this if you want or need the library's memcpy_s and memmove_s.
+// See http://github.com/weidai11/cryptopp/issues/28.
+// #if !defined(CRYPTOPP_WANT_SECURE_LIB)
+// # define CRYPTOPP_WANT_SECURE_LIB
+// #endif
+
+// Define this if ARMv8 shifts are slow. ARM Cortex-A53 and Cortex-A57 shift
+// operation perform poorly, so NEON and ASIMD code that relies on shifts
+// or rotates often performs worse than C/C++ code. Also see
+// http://github.com/weidai11/cryptopp/issues/367.
+#define CRYPTOPP_SLOW_ARMV8_SHIFT 1
+
+// CRYPTOPP_DEBUG enables the library's CRYPTOPP_ASSERT. CRYPTOPP_ASSERT
+// raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). CRYPTOPP_ASSERT
+// is only in effect when CRYPTOPP_DEBUG, DEBUG or _DEBUG is defined. Unlike
+// Posix assert, CRYPTOPP_ASSERT is not affected by NDEBUG (or failure to
+// define it). According to the ndk-build docs, Android use NDK_DEBUG=1 to
+// signal a DEBUG build (and NDK_DEBUG=0 to signal non-DEBUG build).
+// Also see http://github.com/weidai11/cryptopp/issues/277, CVE-2016-7420 and
+// https://developer.android.com/ndk/guides/ndk-build
+#if (defined(DEBUG) || defined(_DEBUG)) || (defined(NDK_DEBUG) && (NDK_DEBUG > 0))
+# undef CRYPTOPP_DEBUG
+# define CRYPTOPP_DEBUG 1
+#endif
+
+// File system code to use when creating GZIP archive.
+// http://www.gzip.org/format.txt
+#if !defined(GZIP_OS_CODE)
+# if defined(__macintosh__)
+#  define GZIP_OS_CODE 7
+# elif defined(__unix__) || defined(__linux__)
+#  define GZIP_OS_CODE 3
+# else
+#  define GZIP_OS_CODE 0
+# endif
+#endif
+
+// Try this if your CPU has 256K internal cache or a slow multiply instruction
+// and you want a (possibly) faster IDEA implementation using log tables
+// #define IDEA_LARGECACHE
+
+// Define this if, for the linear congruential RNG, you want to use
+// the original constants as specified in S.K. Park and K.W. Miller's
+// CACM paper.
+// #define LCRNG_ORIGINAL_NUMBERS
+
+// Define this if you want Integer's operator<< to honor std::showbase (and
+// std::noshowbase). If defined, Integer will use a suffix of 'b', 'o', 'h'
+// or '.' (the last for decimal) when std::showbase is in effect. If
+// std::noshowbase is set, then the suffix is not added to the Integer. If
+// not defined, existing behavior is preserved and Integer will use a suffix
+// of 'b', 'o', 'h' or '.' (the last for decimal).
+// #define CRYPTOPP_USE_STD_SHOWBASE
+
+// Define this if you want to decouple AlgorithmParameters and Integer
+// The decoupling should make it easier for the linker to remove Integer
+// related code for those who do not need Integer, and avoid a potential
+// race during AssignIntToInteger pointer initialization. Also
+// see http://github.com/weidai11/cryptopp/issues/389.
+// #define CRYPTOPP_NO_ASSIGN_TO_INTEGER
+
+// Need GCC 4.6/Clang 1.7/Apple Clang 2.0 or above due to "GCC diagnostic {push|pop}"
+#if (CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_LLVM_CLANG_VERSION >= 10700) || \
+    (CRYPTOPP_APPLE_CLANG_VERSION >= 20000)
+	#define CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE 1
+#endif
+
+// Portable way to suppress warnings.
+// Moved from misc.h due to circular depenedencies.
+#ifndef CRYPTOPP_UNUSED
+	#define CRYPTOPP_UNUSED(x) ((void)(x))
+#endif
+
+// how to disable inlining
+#if defined(CRYPTOPP_MSC_VERSION)
+#	define CRYPTOPP_NOINLINE_DOTDOTDOT
+#	define CRYPTOPP_NOINLINE __declspec(noinline)
+#elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__)
+#	define CRYPTOPP_NOINLINE_DOTDOTDOT ...
+#	define CRYPTOPP_NOINLINE __attribute__((noinline))
+#elif defined(__GNUC__)
+#	define CRYPTOPP_NOINLINE_DOTDOTDOT
+#	define CRYPTOPP_NOINLINE __attribute__((noinline))
+#else
+#	define CRYPTOPP_NOINLINE_DOTDOTDOT ...
+#	define CRYPTOPP_NOINLINE
+#endif
+
+// http://stackoverflow.com/a/13867690/608639
+// CRYPTOPP_CONST_OR_CONSTEXPR due to https://github.com/weidai11/cryptopp/issues/1185
+#if defined(CRYPTOPP_CXX11_CONSTEXPR)
+#  define CRYPTOPP_STATIC_CONSTEXPR static constexpr
+#  define CRYPTOPP_STATIC_CONST_OR_CONSTEXPR static constexpr
+#  define CRYPTOPP_CONST_OR_CONSTEXPR constexpr
+#  define CRYPTOPP_CONSTEXPR constexpr
+#else
+#  define CRYPTOPP_STATIC_CONSTEXPR static
+#  define CRYPTOPP_STATIC_CONST_OR_CONSTEXPR static const
+#  define CRYPTOPP_CONST_OR_CONSTEXPR const
+#  define CRYPTOPP_CONSTEXPR
+#endif // CRYPTOPP_CXX11_CONSTEXPR
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+# define CRYPTOPP_CONSTANT(x) static const int x
+#elif defined(CRYPTOPP_CXX11_STRONG_ENUM)
+# define CRYPTOPP_CONSTANT(x) enum : int { x }
+#elif defined(CRYPTOPP_CXX11_CONSTEXPR)
+# define CRYPTOPP_CONSTANT(x) constexpr static int x
+#else
+# define CRYPTOPP_CONSTANT(x) static const int x
+#endif
+
+// Warnings
+#ifdef CRYPTOPP_MSC_VERSION
+	// 4127: conditional expression is constant
+	// 4512: assignment operator not generated
+	// 4661: no suitable definition provided for explicit template instantiation request
+	// 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
+#	pragma warning(disable: 4127 4512 4661 4910)
+	// CRYPTOPP_MSC_VERSION 1920 is VS2019
+#	if CRYPTOPP_MSC_VERSION >= 1920
+		// 5054: operator '|': deprecated between enumerations of different types
+#		pragma warning(disable: 5054)
+#	endif
+	// Security related, possible defects
+	// http://blogs.msdn.com/b/vcblog/archive/2010/12/14/off-by-default-compiler-warnings-in-visual-c.aspx
+#	pragma warning(once: 4191 4242 4263 4264 4266 4302 4826 4905 4906 4928)
+#endif
+
+#ifdef __BORLANDC__
+// 8037: non-const function called for const object. needed to work around BCB2006 bug
+#	pragma warn -8037
+#endif
+
+// [GCC Bug 53431] "C++ preprocessor ignores #pragma GCC diagnostic". Clang honors it.
+#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
+# pragma GCC diagnostic ignored "-Wunknown-pragmas"
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#endif  // CRYPTOPP_CONFIG_MISC_H

+ 76 - 0
cryptopp/config_ns.h

@@ -0,0 +1,76 @@
+// config_ns.h - written and placed in public domain by Jeffrey Walton
+//               the bits that make up this source file are from the
+//               library's monolithic config.h.
+
+/// \file config_ns.h
+/// \brief Library configuration file
+/// \details <tt>config_ns.h</tt> provides defines for C++ and library
+///  namespaces.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_ns.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_NAMESPACE_H
+#define CRYPTOPP_CONFIG_NAMESPACE_H
+
+// namespace support is now required
+#ifdef NO_NAMESPACE
+# error namespace support is now required
+#endif
+
+#ifdef CRYPTOPP_DOXYGEN_PROCESSING
+
+/// \namespace CryptoPP
+/// \brief Crypto++ library namespace
+/// \details Nearly all classes are located in the CryptoPP namespace. Within
+///  the namespace, there are four additional namespaces.
+///   <ul>
+///     <li>Name - namespace for names used with NameValuePairs and documented
+///         in argnames.h
+///     <li>NaCl - namespace for NaCl test functions like crypto_box,
+///         crypto_box_open, crypto_sign, and crypto_sign_open
+///     <li>Donna - namespace for curve25519 library operations. The name was
+///         selected due to use of Langley and Moon's curve25519-donna.
+///     <li>Test - namespace for testing and benchmarks classes
+///     <li>Weak - namespace for weak and wounded algorithms, like ARC4, MD5
+///         and Pananma
+///   </ul>
+/// \since Crypto++ 3.0
+namespace CryptoPP { }
+
+// Bring in the symbols found in the weak namespace; and fold Weak1 into Weak
+#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
+#define Weak1 Weak
+// Avoid putting "CryptoPP::" in front of everything in Doxygen output
+#define CryptoPP
+#define NAMESPACE_BEGIN(x)
+#define NAMESPACE_END
+// Get Doxygen to generate better documentation for these typedefs
+#define DOCUMENTED_TYPEDEF(x, y) class y : public x {}
+// Make "protected" "private" so the functions and members are not documented
+#define protected private
+
+#else
+// Not Doxygen
+#define NAMESPACE_BEGIN(x) namespace x {
+#define NAMESPACE_END }
+#define DOCUMENTED_TYPEDEF(x, y) typedef x y
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+
+#define ANONYMOUS_NAMESPACE_BEGIN namespace {
+#define ANONYMOUS_NAMESPACE_END }
+#define USING_NAMESPACE(x) using namespace x;
+#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x {
+#define DOCUMENTED_NAMESPACE_END }
+
+#endif  // CRYPTOPP_CONFIG_NAMESPACE_H

+ 168 - 0
cryptopp/config_os.h

@@ -0,0 +1,168 @@
+// config_os.h - written and placed in public domain by Jeffrey Walton
+//               the bits that make up this source file are from the
+//               library's monolithic config.h.
+
+/// \file config_os.h
+/// \brief Library configuration file
+/// \details <tt>config_os.h</tt> provides defines for platforms and operating
+///  systems.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_os.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_OS_H
+#define CRYPTOPP_CONFIG_OS_H
+
+#include "config_ver.h"
+
+// It is OK to remove the hard stop below, but you are on your own.
+// After building the library be sure to run self tests described
+// https://www.cryptopp.com/wiki/Release_Process#Self_Tests
+// The problems with Clang pretending to be other compilers is
+// discussed at http://github.com/weidai11/cryptopp/issues/147.
+#if (defined(_MSC_VER) && defined(__clang__))
+# error: "Unsupported configuration"
+#endif
+
+// Windows platform
+#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+#define CRYPTOPP_WIN32_AVAILABLE
+#endif
+
+// Unix and Linux platforms
+#if defined(__unix__) || defined(__MACH__) || defined(__NetBSD__) || defined(__sun)
+#define CRYPTOPP_UNIX_AVAILABLE
+#endif
+
+// BSD platforms
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#define CRYPTOPP_BSD_AVAILABLE
+#endif
+
+// Microsoft compilers
+#if defined(CRYPTOPP_MSC_VERSION) || defined(__fastcall)
+	#define CRYPTOPP_FASTCALL __fastcall
+#else
+	#define CRYPTOPP_FASTCALL
+#endif
+
+// Microsoft compilers
+#if defined(CRYPTOPP_MSC_VERSION)
+	#define CRYPTOPP_NO_VTABLE __declspec(novtable)
+#else
+	#define CRYPTOPP_NO_VTABLE
+#endif
+
+// Define this if you want to disable all OS-dependent features,
+// such as sockets and OS-provided random number generators
+// #define NO_OS_DEPENDENCE
+
+// Define this to use features provided by Microsoft's CryptoAPI.
+// Currently the only feature used is Windows random number generation.
+// This macro will be ignored if NO_OS_DEPENDENCE is defined.
+// #define USE_MS_CRYPTOAPI
+
+// Define this to use features provided by Microsoft's CryptoNG API.
+// CryptoNG API is available in Vista and above and its cross platform,
+// including desktop apps and store apps. Currently the only feature
+// used is Windows random number generation.
+// This macro will be ignored if NO_OS_DEPENDENCE is defined.
+// #define USE_MS_CNGAPI
+
+// If the user did not make a choice, then select CryptoNG if
+// targeting Windows 8 or above.
+#if !defined(USE_MS_CRYPTOAPI) && !defined(USE_MS_CNGAPI)
+# if !defined(_USING_V110_SDK71_) && ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || \
+     (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/))
+#  define USE_MS_CNGAPI
+# else
+#  define USE_MS_CRYPTOAPI
+# endif
+#endif
+
+// Begin OS features, like init priorities and random numbers
+#ifndef NO_OS_DEPENDENCE
+
+// CRYPTOPP_INIT_PRIORITY attempts to manage initialization of C++ static objects.
+// Under GCC, the library uses init_priority attribute in the range
+// [CRYPTOPP_INIT_PRIORITY, CRYPTOPP_INIT_PRIORITY+100]. Under Windows,
+// CRYPTOPP_INIT_PRIORITY enlists "#pragma init_seg(lib)". The platforms
+// with gaps are Apple and Sun because they require linker scripts. Apple and
+// Sun will use the library's Singletons to initialize and acquire resources.
+// Also see http://cryptopp.com/wiki/Static_Initialization_Order_Fiasco
+#ifndef CRYPTOPP_INIT_PRIORITY
+# define CRYPTOPP_INIT_PRIORITY 250
+#endif
+
+// CRYPTOPP_USER_PRIORITY is for other libraries and user code that is using Crypto++
+// and managing C++ static object creation. It is guaranteed not to conflict with
+// values used by (or would be used by) the Crypto++ library.
+#ifndef CRYPTOPP_USER_PRIORITY
+# define CRYPTOPP_USER_PRIORITY (CRYPTOPP_INIT_PRIORITY+101)
+#endif
+
+// Most platforms allow us to specify when to create C++ objects. Apple and Sun do not.
+#if (CRYPTOPP_INIT_PRIORITY > 0) && !(defined(NO_OS_DEPENDENCE) || defined(__APPLE__) || defined(__sun__))
+# if (CRYPTOPP_GCC_VERSION >= 30000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 800)
+#  define HAVE_GCC_INIT_PRIORITY 1
+# elif (CRYPTOPP_MSC_VERSION >= 1310)
+#  define HAVE_MSC_INIT_PRIORITY 1
+# elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__)
+#  define HAVE_XLC_INIT_PRIORITY 1
+# endif
+#endif  // CRYPTOPP_INIT_PRIORITY, NO_OS_DEPENDENCE, Apple, Sun
+
+#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE)
+#	define HIGHRES_TIMER_AVAILABLE
+#endif
+
+#ifdef CRYPTOPP_WIN32_AVAILABLE
+# if !defined(WINAPI_FAMILY)
+#	define THREAD_TIMER_AVAILABLE
+# elif defined(WINAPI_FAMILY)
+#   if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
+#	  define THREAD_TIMER_AVAILABLE
+#  endif
+# endif
+#endif
+
+#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
+#	define NONBLOCKING_RNG_AVAILABLE
+#	define BLOCKING_RNG_AVAILABLE
+#	define OS_RNG_AVAILABLE
+#endif
+
+// Cygwin/Newlib requires _XOPEN_SOURCE=600
+#if defined(CRYPTOPP_UNIX_AVAILABLE)
+# define UNIX_SIGNALS_AVAILABLE 1
+#endif
+
+#ifdef CRYPTOPP_WIN32_AVAILABLE
+# if !defined(WINAPI_FAMILY)
+#	define NONBLOCKING_RNG_AVAILABLE
+#	define OS_RNG_AVAILABLE
+# elif defined(WINAPI_FAMILY)
+#   if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
+#	  define NONBLOCKING_RNG_AVAILABLE
+#	  define OS_RNG_AVAILABLE
+#   elif !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
+#     if ((WINVER >= 0x0A00 /*_WIN32_WINNT_WIN10*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/))
+#	    define NONBLOCKING_RNG_AVAILABLE
+#	    define OS_RNG_AVAILABLE
+#     endif
+#   endif
+# endif
+#endif
+
+#endif	// NO_OS_DEPENDENCE
+
+#endif  // CRYPTOPP_CONFIG_OS_H

+ 98 - 0
cryptopp/config_ver.h

@@ -0,0 +1,98 @@
+// config_ver.h - written and placed in public domain by Jeffrey Walton
+//                the bits that make up this source file are from the
+//                library's monolithic config.h.
+
+/// \file config_ver.h
+/// \brief Library configuration file
+/// \details <tt>config_ver.h</tt> provides defines for library and compiler
+///  versions.
+/// \details <tt>config.h</tt> was split into components in May 2019 to better
+///  integrate with Autoconf and its feature tests. The splitting occurred so
+///  users could continue to include <tt>config.h</tt> while allowing Autoconf
+///  to write new <tt>config_asm.h</tt> and new <tt>config_cxx.h</tt> using
+///  its feature tests.
+/// \note You should include <tt>config.h</tt> rather than <tt>config_ver.h</tt>
+///  directly.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/835">Issue 835,
+///  Make config.h more autoconf friendly</A>,
+///  <A HREF="https://www.cryptopp.com/wiki/Configure.sh">Configure.sh script</A>
+///  on the Crypto++ wiki
+/// \since Crypto++ 8.3
+
+#ifndef CRYPTOPP_CONFIG_VERSION_H
+#define CRYPTOPP_CONFIG_VERSION_H
+
+/// \brief Library major version
+/// \details CRYPTOPP_MAJOR reflects the major version of the library the
+///  headers came from. It is not necessarily the version of the library built
+///  as a shared object if versions are inadvertently mixed and matched.
+/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion()
+/// \since Crypto++ 8.2
+#define CRYPTOPP_MAJOR 8
+/// \brief Library minor version
+/// \details CRYPTOPP_MINOR reflects the minor version of the library the
+///  headers came from. It is not necessarily the version of the library built
+///  as a shared object if versions are inadvertently mixed and matched.
+/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion()
+/// \since Crypto++ 8.2
+#define CRYPTOPP_MINOR 9
+/// \brief Library revision number
+/// \details CRYPTOPP_REVISION reflects the revision number of the library the
+///  headers came from. It is not necessarily the revision of the library built
+///  as a shared object if versions are inadvertently mixed and matched.
+/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion()
+/// \since Crypto++ 8.2
+#define CRYPTOPP_REVISION 0
+
+/// \brief Full library version
+/// \details CRYPTOPP_VERSION reflects the version of the library the headers
+///  came from. It is not necessarily the version of the library built as a
+///  shared object if versions are inadvertently mixed and matched.
+/// \sa CRYPTOPP_MAJOR, CRYPTOPP_MINOR, CRYPTOPP_REVISION, LibraryVersion(), HeaderVersion()
+/// \since Crypto++ 5.6
+#define CRYPTOPP_VERSION 890
+
+// Compiler version macros
+
+// Apple and LLVM Clang versions. Apple Clang version 7.0 roughly equals
+// LLVM Clang version 3.7. Also see https://gist.github.com/yamaya/2924292
+#if defined(__clang__) && defined(__apple_build_version__)
+# define CRYPTOPP_APPLE_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#elif defined(__clang__) && defined(_MSC_VER)
+# define CRYPTOPP_MSVC_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#elif defined(__clang__)
+# define CRYPTOPP_LLVM_CLANG_VERSION  (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#endif
+
+// Clang pretends to be other compilers. The compiler gets into
+// code paths that it cannot compile. Unset Clang to save the grief.
+// Also see http://github.com/weidai11/cryptopp/issues/147.
+
+#if defined(__GNUC__) && !defined(__clang__)
+# undef CRYPTOPP_APPLE_CLANG_VERSION
+# undef CRYPTOPP_LLVM_CLANG_VERSION
+# define CRYPTOPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__xlc__) || defined(__xlC__) && !defined(__clang__)
+# undef CRYPTOPP_LLVM_CLANG_VERSION
+# define CRYPTOPP_XLC_VERSION ((__xlC__ / 256) * 10000 + (__xlC__ % 256) * 100)
+#endif
+
+#if defined(__INTEL_COMPILER) && !defined(__clang__)
+# undef CRYPTOPP_LLVM_CLANG_VERSION
+# define CRYPTOPP_INTEL_VERSION (__INTEL_COMPILER)
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+# undef CRYPTOPP_LLVM_CLANG_VERSION
+# define CRYPTOPP_MSC_VERSION (_MSC_VER)
+#endif
+
+// To control <x86intrin.h> include. May need a guard, like GCC 4.5 and above
+// Also see https://stackoverflow.com/a/42493893 and https://github.com/weidai11/cryptopp/issues/1198
+#if defined(CRYPTOPP_GCC_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_LLVM_CLANG_VERSION)
+# define CRYPTOPP_GCC_COMPATIBLE 1
+#endif
+
+#endif  // CRYPTOPP_CONFIG_VERSION_H

+ 1089 - 0
cryptopp/cpu.h

@@ -0,0 +1,1089 @@
+// cpu.h - originally written and placed in the public domain by Wei Dai
+//         updated for ARM and PowerPC by Jeffrey Walton.
+//         updated to split CPU_Query() and CPU_Probe() by Jeffrey Walton.
+
+/// \file cpu.h
+/// \brief Functions for CPU features and intrinsics
+/// \details The CPU functions are used in IA-32, ARM and PowerPC code paths. The
+///  functions provide cpu specific feature testing on IA-32, ARM and PowerPC machines.
+/// \details Feature detection uses CPUID on IA-32, like Intel and AMD. On other platforms
+///  a two-part strategy is used. First, the library attempts to *Query* the OS for a feature,
+///  like using Linux getauxval() or android_getCpuFeatures(). If that fails, then *Probe*
+///  the cpu executing an instruction and an observe a SIGILL if unsupported. The general
+///  pattern used by the library is:
+/// <pre>
+///    g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();
+///    g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
+///    g_hasAES  = CPU_QueryAES() || CPU_ProbeAES();
+/// </pre>
+/// \details Generally speaking, CPU_Query() is in the source file <tt>cpu.cpp</tt> because it
+///  does not require special architectural flags. CPU_Probe() is in a source file that receives
+///  architectural flags, like <tt>sse_simd.cpp</tt>, <tt>neon_simd.cpp</tt> and
+///  <tt>ppc_simd.cpp</tt>. For example, compiling <tt>neon_simd.cpp</tt> on an ARM64 machine will
+///  have <tt>-march=armv8-a</tt> applied during a compile to make the instruction set architecture
+///  (ISA) available.
+/// \details The cpu probes are expensive when compared to a standard OS feature query. The library
+///  also avoids probes on Apple platforms because Apple's signal handling for SIGILLs appears to
+///  corrupt memory. CPU_Probe() will unconditionally return false for Apple platforms. OpenSSL
+///  experienced the same problem and moved away from SIGILL probes on Apple.
+
+#ifndef CRYPTOPP_CPU_H
+#define CRYPTOPP_CPU_H
+
+#include "config.h"
+
+// Issue 340
+#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
+// Applies to both X86/X32/X64 and ARM32/ARM64
+#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION)
+	#define NEW_LINE "\n"
+	#define INTEL_PREFIX ".intel_syntax;"
+	#define INTEL_NOPREFIX ".intel_syntax;"
+	#define ATT_PREFIX ".att_syntax;"
+	#define ATT_NOPREFIX ".att_syntax;"
+#elif defined(CRYPTOPP_GCC_VERSION)
+	#define NEW_LINE
+	#define INTEL_PREFIX ".intel_syntax prefix;"
+	#define INTEL_NOPREFIX ".intel_syntax noprefix;"
+	#define ATT_PREFIX ".att_syntax prefix;"
+	#define ATT_NOPREFIX ".att_syntax noprefix;"
+#else
+	#define NEW_LINE
+	#define INTEL_PREFIX
+	#define INTEL_NOPREFIX
+	#define ATT_PREFIX
+	#define ATT_NOPREFIX
+#endif
+
+// Thanks to v1ne at https://github.com/weidai11/cryptopp/pull/1133
+#define PERCENT_PASTE(x) "%" #x
+#define PERCENT_REG(x) PERCENT_PASTE(x)
+
+#ifdef CRYPTOPP_GENERATE_X64_MASM
+
+#define CRYPTOPP_X86_ASM_AVAILABLE
+#define CRYPTOPP_BOOL_X64 1
+#define CRYPTOPP_SSE2_ASM_AVAILABLE 1
+#define NAMESPACE_END
+
+#else
+
+NAMESPACE_BEGIN(CryptoPP)
+
+// ***************************** IA-32 ***************************** //
+
+#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_DOXYGEN_PROCESSING
+
+#define CRYPTOPP_CPUID_AVAILABLE 1
+
+// Hide from Doxygen
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+// These should not be used directly
+extern CRYPTOPP_DLL bool g_x86DetectionDone;
+extern CRYPTOPP_DLL bool g_hasSSE2;
+extern CRYPTOPP_DLL bool g_hasSSSE3;
+extern CRYPTOPP_DLL bool g_hasSSE41;
+extern CRYPTOPP_DLL bool g_hasSSE42;
+extern CRYPTOPP_DLL bool g_hasMOVBE;
+extern CRYPTOPP_DLL bool g_hasAESNI;
+extern CRYPTOPP_DLL bool g_hasCLMUL;
+extern CRYPTOPP_DLL bool g_hasAVX;
+extern CRYPTOPP_DLL bool g_hasAVX2;
+extern CRYPTOPP_DLL bool g_hasSHA;
+extern CRYPTOPP_DLL bool g_hasADX;
+extern CRYPTOPP_DLL bool g_isP4;
+extern CRYPTOPP_DLL bool g_hasRDRAND;
+extern CRYPTOPP_DLL bool g_hasRDSEED;
+extern CRYPTOPP_DLL bool g_hasPadlockRNG;
+extern CRYPTOPP_DLL bool g_hasPadlockACE;
+extern CRYPTOPP_DLL bool g_hasPadlockACE2;
+extern CRYPTOPP_DLL bool g_hasPadlockPHE;
+extern CRYPTOPP_DLL bool g_hasPadlockPMM;
+extern CRYPTOPP_DLL word32 g_cacheLineSize;
+
+CRYPTOPP_DLL void CRYPTOPP_API DetectX86Features();
+CRYPTOPP_DLL bool CRYPTOPP_API CpuId(word32 func, word32 subfunc, word32 output[4]);
+#endif // CRYPTOPP_DOXYGEN_PROCESSING
+
+/// \name IA-32 CPU FEATURES
+//@{
+
+/// \brief Determine SSE2 availability
+/// \return true if SSE2 is determined to be available, false otherwise
+/// \details MMX, SSE and SSE2 are core processor features for x86_64, and
+///  the function return value is based on OSXSAVE. On i386 both
+///  SSE2 and OSXSAVE are used for the return value.
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasSSE2()
+{
+#if (CRYPTOPP_SSE2_ASM_AVAILABLE || CRYPTOPP_SSE2_INTRIN_AVAILABLE)
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasSSE2;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine SSSE3 availability
+/// \return true if SSSE3 is determined to be available, false otherwise
+/// \details HasSSSE3() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasSSSE3()
+{
+#if CRYPTOPP_SSSE3_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasSSSE3;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine SSE4.1 availability
+/// \return true if SSE4.1 is determined to be available, false otherwise
+/// \details HasSSE41() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasSSE41()
+{
+#if CRYPTOPP_SSE41_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasSSE41;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine SSE4.2 availability
+/// \return true if SSE4.2 is determined to be available, false otherwise
+/// \details HasSSE42() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasSSE42()
+{
+#if CRYPTOPP_SSE42_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasSSE42;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine MOVBE availability
+/// \return true if MOVBE is determined to be available, false otherwise
+/// \details HasMOVBE() is a runtime check performed using CPUID
+/// \since Crypto++ 8.3
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasMOVBE()
+{
+#if CRYPTOPP_SSE42_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasMOVBE;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine AES-NI availability
+/// \return true if AES-NI is determined to be available, false otherwise
+/// \details HasAESNI() is a runtime check performed using CPUID
+/// \since Crypto++ 5.6.1
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasAESNI()
+{
+#if CRYPTOPP_AESNI_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasAESNI;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Carryless Multiply availability
+/// \return true if pclmulqdq is determined to be available, false otherwise
+/// \details HasCLMUL() is a runtime check performed using CPUID
+/// \since Crypto++ 5.6.1
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasCLMUL()
+{
+#if CRYPTOPP_CLMUL_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasCLMUL;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine SHA availability
+/// \return true if SHA is determined to be available, false otherwise
+/// \details HasSHA() is a runtime check performed using CPUID
+/// \since Crypto++ 6.0
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasSHA()
+{
+#if CRYPTOPP_SHANI_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasSHA;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine ADX availability
+/// \return true if ADX is determined to be available, false otherwise
+/// \details HasADX() is a runtime check performed using CPUID
+/// \since Crypto++ 7.0
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasADX()
+{
+#if CRYPTOPP_ADX_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasADX;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine AVX availability
+/// \return true if AVX is determined to be available, false otherwise
+/// \details HasAVX() is a runtime check performed using CPUID
+/// \since Crypto++ 8.0
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasAVX()
+{
+#if CRYPTOPP_AVX_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasAVX;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine AVX2 availability
+/// \return true if AVX2 is determined to be available, false otherwise
+/// \details HasAVX2() is a runtime check performed using CPUID
+/// \since Crypto++ 8.0
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasAVX2()
+{
+#if CRYPTOPP_AVX2_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasAVX2;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine RDRAND availability
+/// \return true if RDRAND is determined to be available, false otherwise
+/// \details HasRDRAND() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasRDRAND()
+{
+#if CRYPTOPP_RDRAND_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasRDRAND;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine RDSEED availability
+/// \return true if RDSEED is determined to be available, false otherwise
+/// \details HasRDSEED() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasRDSEED()
+{
+#if CRYPTOPP_RDSEED_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasRDSEED;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Padlock RNG availability
+/// \return true if VIA Padlock RNG is determined to be available, false otherwise
+/// \details HasPadlockRNG() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasPadlockRNG()
+{
+#if CRYPTOPP_PADLOCK_RNG_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasPadlockRNG;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Padlock ACE availability
+/// \return true if VIA Padlock ACE is determined to be available, false otherwise
+/// \details HasPadlockACE() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasPadlockACE()
+{
+#if CRYPTOPP_PADLOCK_ACE_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasPadlockACE;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Padlock ACE2 availability
+/// \return true if VIA Padlock ACE2 is determined to be available, false otherwise
+/// \details HasPadlockACE2() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasPadlockACE2()
+{
+#if CRYPTOPP_PADLOCK_ACE2_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasPadlockACE2;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Padlock PHE availability
+/// \return true if VIA Padlock PHE is determined to be available, false otherwise
+/// \details HasPadlockPHE() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasPadlockPHE()
+{
+#if CRYPTOPP_PADLOCK_PHE_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasPadlockPHE;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine Padlock PMM availability
+/// \return true if VIA Padlock PMM is determined to be available, false otherwise
+/// \details HasPadlockPMM() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool HasPadlockPMM()
+{
+#if CRYPTOPP_PADLOCK_PMM_AVAILABLE
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_hasPadlockPMM;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if the CPU is an Intel P4
+/// \return true if the CPU is a P4, false otherwise
+/// \details IsP4() is a runtime check performed using CPUID
+/// \note This function is only available on Intel IA-32 platforms
+inline bool IsP4()
+{
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_isP4;
+}
+
+/// \brief Provides the cache line size
+/// \return lower bound on the size of a cache line in bytes, if available
+/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it
+///  is available. If the value is not available at runtime, then 32 is returned for a 32-bit
+///  processor and 64 is returned for a 64-bit processor.
+/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC
+///  and AIX also makes the value available to user space and it is also usually accurate. The
+///  ARM processor equivalent is a privileged instruction, so a compile time value is returned.
+inline int GetCacheLineSize()
+{
+	if (!g_x86DetectionDone)
+		DetectX86Features();
+	return g_cacheLineSize;
+}
+//@}
+
+#endif  // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
+
+// ***************************** ARM-32, Aarch32 and Aarch64 ***************************** //
+
+#if CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || CRYPTOPP_DOXYGEN_PROCESSING
+
+// Hide from Doxygen
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+extern bool g_ArmDetectionDone;
+extern bool g_hasARMv7;
+extern bool g_hasNEON;
+extern bool g_hasPMULL;
+extern bool g_hasCRC32;
+extern bool g_hasAES;
+extern bool g_hasSHA1;
+extern bool g_hasSHA2;
+extern bool g_hasSHA512;
+extern bool g_hasSHA3;
+extern bool g_hasSM3;
+extern bool g_hasSM4;
+void CRYPTOPP_API DetectArmFeatures();
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+
+/// \name ARM A-32, Aarch32 and AArch64 CPU FEATURES
+//@{
+
+/// \brief Determine if an ARM processor is ARMv7 or above
+/// \return true if the hardware is ARMv7 or above, false otherwise.
+/// \details Some AES code requires ARMv7 or above
+/// \since Crypto++ 8.0
+/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms
+inline bool HasARMv7()
+{
+	// ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64
+#if defined(__aarch32__) || defined(__aarch64__)
+	return true;
+#else
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasARMv7;
+#endif
+}
+
+/// \brief Determine if an ARM processor has Advanced SIMD available
+/// \return true if the hardware is capable of Advanced SIMD at runtime, false otherwise.
+/// \details Advanced SIMD instructions are available under most ARMv7, Aarch32 and Aarch64.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mfpu=neon</tt> (32-bit) or <tt>-march=armv8-a</tt>
+///  (64-bit). Also see ARM's <tt>__ARM_NEON</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms
+inline bool HasNEON()
+{
+	// ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64
+#if defined(CRYPTOPP_ARM_ASIMD_AVAILABLE)
+	return true;
+#elif defined(CRYPTOPP_ARM_NEON_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasNEON;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has CRC32 available
+/// \return true if the hardware is capable of CRC32 at runtime, false otherwise.
+/// \details CRC32 instructions provide access to the processor's CRC-32 and CRC-32C
+///  instructions. They are provided by ARM C Language Extensions 2.0 (ACLE 2.0) and
+///  available under Aarch32 and Aarch64.
+/// \details Runtime support requires compile time support. When compiling with GCC,
+///  you may need to compile with <tt>-march=armv8-a+crc</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRC32</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasCRC32()
+{
+#if defined(CRYPTOPP_ARM_CRC32_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasCRC32;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has AES available
+/// \return true if the hardware is capable of AES at runtime, false otherwise.
+/// \details AES is part of the optional Crypto extensions on Aarch32 and Aarch64. They are
+///  accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-march=armv8-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasAES()
+{
+#if defined(CRYPTOPP_ARM_AES_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasAES;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor provides Polynomial Multiplication
+/// \return true if the hardware is capable of polynomial multiplications at runtime,
+///  false otherwise.
+/// \details The multiplication instructions are available under Aarch32 and Aarch64.
+/// \details Runtime support requires compile time support. When compiling with GCC,
+///  you may need to compile with <tt>-march=armv8-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasPMULL()
+{
+#if defined(CRYPTOPP_ARM_PMULL_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasPMULL;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SHA1 available
+/// \return true if the hardware is capable of SHA1 at runtime, false otherwise.
+/// \details SHA1 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are
+///  accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-march=armv8-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSHA1()
+{
+#if defined(CRYPTOPP_ARM_SHA1_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSHA1;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SHA256 available
+/// \return true if the hardware is capable of SHA256 at runtime, false otherwise.
+/// \details SHA256 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are
+///  accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-march=armv8-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 5.6.4
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSHA2()
+{
+#if defined(CRYPTOPP_ARM_SHA2_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSHA2;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SHA3 available
+/// \return true if the hardware is capable of SHA3 at runtime, false otherwise.
+/// \details SHA3 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They
+///  are accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you
+///  may need to compile with <tt>-march=armv8.2-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 8.0
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSHA3()
+{
+#if defined(CRYPTOPP_ARM_SHA3_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSHA3;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SHA512 available
+/// \return true if the hardware is capable of SHA512 at runtime, false otherwise.
+/// \details SHA512 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They
+///  are accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you
+///  may need to compile with <tt>-march=armv8.2-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 8.0
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSHA512()
+{
+#if defined(CRYPTOPP_ARM_SHA512_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSHA512;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SM3 available
+/// \return true if the hardware is capable of SM3 at runtime, false otherwise.
+/// \details SM3 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They
+///  are accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you
+///  may need to compile with <tt>-march=armv8.2-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 8.0
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSM3()
+{
+#if defined(CRYPTOPP_ARM_SM3_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSM3;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if an ARM processor has SM4 available
+/// \return true if the hardware is capable of SM4 at runtime, false otherwise.
+/// \details SM4 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They
+///  are accessed using ARM C Language Extensions 2.0 (ACLE 2.0).
+/// \details Runtime support requires compile time support. When compiling with GCC, you
+///  may need to compile with <tt>-march=armv8.2-a+crypto</tt>; while Apple requires
+///  <tt>-arch arm64</tt>. Also see ARM's <tt>__ARM_FEATURE_CRYPTO</tt> preprocessor macro.
+/// \since Crypto++ 8.0
+/// \note This function is only available on Aarch32 and Aarch64 platforms
+inline bool HasSM4()
+{
+#if defined(CRYPTOPP_ARM_SM4_AVAILABLE)
+	if (!g_ArmDetectionDone)
+		DetectArmFeatures();
+	return g_hasSM4;
+#else
+	return false;
+#endif
+}
+
+//@}
+
+#endif  // CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8
+
+// ***************************** PowerPC ***************************** //
+
+#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_DOXYGEN_PROCESSING
+
+// Hide from Doxygen
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+extern bool g_PowerPcDetectionDone;
+extern bool g_hasAltivec;
+extern bool g_hasPower7;
+extern bool g_hasPower8;
+extern bool g_hasPower9;
+extern bool g_hasAES;
+extern bool g_hasPMULL;
+extern bool g_hasSHA256;
+extern bool g_hasSHA512;
+extern bool g_hasDARN;
+extern word32 g_cacheLineSize;
+void CRYPTOPP_API DetectPowerPcFeatures();
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+
+/// \name POWERPC CPU FEATURES
+//@{
+
+/// \brief Determine if a PowerPC processor has Altivec available
+/// \return true if the hardware is capable of Altivec at runtime, false otherwise.
+/// \details Altivec instructions are available on modern PowerPCs.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power4</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr6 -qaltivec</tt>. Also see PowerPC's <tt>_ALTIVEC_</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasAltivec()
+{
+#if CRYPTOPP_ALTIVEC_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasAltivec;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has Power7 available
+/// \return true if the hardware is capable of Power7 at runtime, false otherwise.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power7</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr7 -qaltivec</tt>. Also see PowerPC's <tt>_ALTIVEC_</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasPower7()
+{
+#if CRYPTOPP_POWER7_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasPower7;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has Power8 available
+/// \return true if the hardware is capable of Power8 at runtime, false otherwise.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>_ALTIVEC_</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasPower8()
+{
+#if CRYPTOPP_POWER8_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasPower8;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has Power9 available
+/// \return true if the hardware is capable of Power9 at runtime, false otherwise.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power9</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr9 -qaltivec</tt>. Also see PowerPC's <tt>_ALTIVEC_</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasPower9()
+{
+#if CRYPTOPP_POWER9_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasPower9;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has AES available
+/// \return true if the hardware is capable of AES at runtime, false otherwise.
+/// \details AES is part of the in-crypto extensions on Power8 and Power9.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasAES()
+{
+#if CRYPTOPP_POWER8_AES_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasAES;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has Polynomial Multiply available
+/// \return true if the hardware is capable of PMULL at runtime, false otherwise.
+/// \details PMULL is part of the in-crypto extensions on Power8 and Power9.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasPMULL()
+{
+#if CRYPTOPP_POWER8_VMULL_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasPMULL;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has SHA256 available
+/// \return true if the hardware is capable of SHA256 at runtime, false otherwise.
+/// \details SHA is part of the in-crypto extensions on Power8 and Power9.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasSHA256()
+{
+#if CRYPTOPP_POWER8_SHA_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasSHA256;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has SHA512 available
+/// \return true if the hardware is capable of SHA512 at runtime, false otherwise.
+/// \details SHA is part of the in-crypto extensions on Power8 and Power9.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasSHA512()
+{
+#if CRYPTOPP_POWER8_SHA_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_hasSHA512;
+#else
+	return false;
+#endif
+}
+
+/// \brief Determine if a PowerPC processor has DARN available
+/// \return true if the hardware is capable of DARN at runtime, false otherwise.
+/// \details Runtime support requires compile time support. When compiling with GCC, you may
+///  need to compile with <tt>-mcpu=power9</tt>; while IBM XL C/C++ compilers require
+///  <tt>-qarch=pwr9 -qaltivec</tt>. Also see PowerPC's <tt>_ALTIVEC_</tt> preprocessor macro.
+/// \note This function is only available on PowerPC and PowerPC-64 platforms
+inline bool HasDARN()
+{
+#if CRYPTOPP_POWER9_AVAILABLE
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	// see comments in cpu.cpp
+#  if defined(__ibmxl__) && defined(__linux__)
+	return false;
+#  else
+	return g_hasDARN;
+#  endif
+#else
+	return false;
+#endif
+}
+
+/// \brief Provides the cache line size
+/// \return lower bound on the size of a cache line in bytes, if available
+/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it
+///  is available. If the value is not available at runtime, then 32 is returned for a 32-bit
+///  processor and 64 is returned for a 64-bit processor.
+/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC
+///  and AIX also makes the value available to user space and it is also usually accurate. The
+///  ARM processor equivalent is a privileged instruction, so a compile time value is returned.
+inline int GetCacheLineSize()
+{
+	if (!g_PowerPcDetectionDone)
+		DetectPowerPcFeatures();
+	return g_cacheLineSize;
+}
+
+//@}
+
+#endif  // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
+
+// ***************************** L1 cache line ***************************** //
+
+// Non-Intel systems
+#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
+/// \brief Provides the cache line size
+/// \return lower bound on the size of a cache line in bytes, if available
+/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it
+///  is available. If the value is not available at runtime, then 32 is returned for a 32-bit
+///  processor and 64 is returned for a 64-bit processor.
+/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC
+///  and AIX also makes the value available to user space and it is also usually accurate. The
+///  ARM processor equivalent is a privileged instruction, so a compile time value is returned.
+inline int GetCacheLineSize()
+{
+	return CRYPTOPP_L1_CACHE_LINE_SIZE;
+}
+#endif  // Non-Intel systems
+
+#endif  // CRYPTOPP_GENERATE_X64_MASM
+
+// ***************************** Inline ASM Helper ***************************** //
+
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+
+#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
+
+#ifdef CRYPTOPP_GENERATE_X64_MASM
+	#define AS1(x) x*newline*
+	#define AS2(x, y) x, y*newline*
+	#define AS3(x, y, z) x, y, z*newline*
+	#define ASS(x, y, a, b, c, d) x, y, a*64+b*16+c*4+d*newline*
+	#define ASL(x) label##x:*newline*
+	#define ASJ(x, y, z) x label##y*newline*
+	#define ASC(x, y) x label##y*newline*
+	#define AS_HEX(y) 0##y##h
+#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__)
+	#define AS1(x) __asm {x}
+	#define AS2(x, y) __asm {x, y}
+	#define AS3(x, y, z) __asm {x, y, z}
+	#define ASS(x, y, a, b, c, d) __asm {x, y, (a)*64+(b)*16+(c)*4+(d)}
+	#define ASL(x) __asm {label##x:}
+	#define ASJ(x, y, z) __asm {x label##y}
+	#define ASC(x, y) __asm {x label##y}
+	#define CRYPTOPP_NAKED __declspec(naked)
+	#define AS_HEX(y) 0x##y
+#else
+	// define these in two steps to allow arguments to be expanded
+	#define GNU_AS1(x) #x ";" NEW_LINE
+	#define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE
+	#define GNU_AS3(x, y, z) #x ", " #y ", " #z ";" NEW_LINE
+	#define GNU_ASL(x) "\n" #x ":" NEW_LINE
+// clang 5.0.0 and apple clang 9.0.0 don't support numerical backward jumps
+#if (CRYPTOPP_LLVM_CLANG_VERSION >= 50000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 90000)
+	#define GNU_ASJ(x, y, z) ATT_PREFIX ";" NEW_LINE #x " " #y #z ";" NEW_LINE INTEL_PREFIX ";" NEW_LINE
+#else
+	#define GNU_ASJ(x, y, z) #x " " #y #z ";" NEW_LINE
+#endif
+	#define AS1(x) GNU_AS1(x)
+	#define AS2(x, y) GNU_AS2(x, y)
+	#define AS3(x, y, z) GNU_AS3(x, y, z)
+	#define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";"
+	#define ASL(x) GNU_ASL(x)
+	#define ASJ(x, y, z) GNU_ASJ(x, y, z)
+	#define ASC(x, y) #x " " #y ";"
+	#define CRYPTOPP_NAKED
+	#define AS_HEX(y) 0x##y
+#endif
+
+#define IF0(y)
+#define IF1(y) y
+
+#ifdef CRYPTOPP_GENERATE_X64_MASM
+#define ASM_MOD(x, y) ((x) MOD (y))
+#define XMMWORD_PTR XMMWORD PTR
+#else
+// GNU assembler doesn't seem to have mod operator
+#define ASM_MOD(x, y) ((x)-((x)/(y))*(y))
+// GAS 2.15 doesn't support XMMWORD PTR. it seems necessary only for MASM
+#define XMMWORD_PTR
+#endif
+
+#if CRYPTOPP_BOOL_X86
+	#define AS_REG_1 ecx
+	#define AS_REG_2 edx
+	#define AS_REG_3 esi
+	#define AS_REG_4 edi
+	#define AS_REG_5 eax
+	#define AS_REG_6 ebx
+	#define AS_REG_7 ebp
+	#define AS_REG_1d ecx
+	#define AS_REG_2d edx
+	#define AS_REG_3d esi
+	#define AS_REG_4d edi
+	#define AS_REG_5d eax
+	#define AS_REG_6d ebx
+	#define AS_REG_7d ebp
+	#define WORD_SZ 4
+	#define WORD_REG(x)	e##x
+	#define WORD_PTR DWORD PTR
+	#define AS_PUSH_IF86(x) AS1(push e##x)
+	#define AS_POP_IF86(x) AS1(pop e##x)
+	#define AS_JCXZ jecxz
+#elif CRYPTOPP_BOOL_X32
+	#define AS_REG_1 ecx
+	#define AS_REG_2 edx
+	#define AS_REG_3 r8d
+	#define AS_REG_4 r9d
+	#define AS_REG_5 eax
+	#define AS_REG_6 r10d
+	#define AS_REG_7 r11d
+	#define AS_REG_1d ecx
+	#define AS_REG_2d edx
+	#define AS_REG_3d r8d
+	#define AS_REG_4d r9d
+	#define AS_REG_5d eax
+	#define AS_REG_6d r10d
+	#define AS_REG_7d r11d
+	#define WORD_SZ 4
+	#define WORD_REG(x)	e##x
+	#define WORD_PTR DWORD PTR
+	#define AS_PUSH_IF86(x) AS1(push r##x)
+	#define AS_POP_IF86(x) AS1(pop r##x)
+	#define AS_JCXZ jecxz
+#elif CRYPTOPP_BOOL_X64
+	#ifdef CRYPTOPP_GENERATE_X64_MASM
+		#define AS_REG_1 rcx
+		#define AS_REG_2 rdx
+		#define AS_REG_3 r8
+		#define AS_REG_4 r9
+		#define AS_REG_5 rax
+		#define AS_REG_6 r10
+		#define AS_REG_7 r11
+		#define AS_REG_1d ecx
+		#define AS_REG_2d edx
+		#define AS_REG_3d r8d
+		#define AS_REG_4d r9d
+		#define AS_REG_5d eax
+		#define AS_REG_6d r10d
+		#define AS_REG_7d r11d
+	#else
+		#define AS_REG_1 rdi
+		#define AS_REG_2 rsi
+		#define AS_REG_3 rdx
+		#define AS_REG_4 rcx
+		#define AS_REG_5 r8
+		#define AS_REG_6 r9
+		#define AS_REG_7 r10
+		#define AS_REG_1d edi
+		#define AS_REG_2d esi
+		#define AS_REG_3d edx
+		#define AS_REG_4d ecx
+		#define AS_REG_5d r8d
+		#define AS_REG_6d r9d
+		#define AS_REG_7d r10d
+	#endif
+	#define WORD_SZ 8
+	#define WORD_REG(x)	r##x
+	#define WORD_PTR QWORD PTR
+	#define AS_PUSH_IF86(x)
+	#define AS_POP_IF86(x)
+	#define AS_JCXZ jrcxz
+#endif
+
+// helper macro for stream cipher output
+#define AS_XMM_OUTPUT4(labelPrefix, inputPtr, outputPtr, x0, x1, x2, x3, t, p0, p1, p2, p3, increment)\
+	AS2(	test	inputPtr, inputPtr)\
+	ASC(	jz,		labelPrefix##3)\
+	AS2(	test	inputPtr, 15)\
+	ASC(	jnz,	labelPrefix##7)\
+	AS2(	pxor	xmm##x0, [inputPtr+p0*16])\
+	AS2(	pxor	xmm##x1, [inputPtr+p1*16])\
+	AS2(	pxor	xmm##x2, [inputPtr+p2*16])\
+	AS2(	pxor	xmm##x3, [inputPtr+p3*16])\
+	AS2(	add		inputPtr, increment*16)\
+	ASC(	jmp,	labelPrefix##3)\
+	ASL(labelPrefix##7)\
+	AS2(	movdqu	xmm##t, [inputPtr+p0*16])\
+	AS2(	pxor	xmm##x0, xmm##t)\
+	AS2(	movdqu	xmm##t, [inputPtr+p1*16])\
+	AS2(	pxor	xmm##x1, xmm##t)\
+	AS2(	movdqu	xmm##t, [inputPtr+p2*16])\
+	AS2(	pxor	xmm##x2, xmm##t)\
+	AS2(	movdqu	xmm##t, [inputPtr+p3*16])\
+	AS2(	pxor	xmm##x3, xmm##t)\
+	AS2(	add		inputPtr, increment*16)\
+	ASL(labelPrefix##3)\
+	AS2(	test	outputPtr, 15)\
+	ASC(	jnz,	labelPrefix##8)\
+	AS2(	movdqa	[outputPtr+p0*16], xmm##x0)\
+	AS2(	movdqa	[outputPtr+p1*16], xmm##x1)\
+	AS2(	movdqa	[outputPtr+p2*16], xmm##x2)\
+	AS2(	movdqa	[outputPtr+p3*16], xmm##x3)\
+	ASC(	jmp,	labelPrefix##9)\
+	ASL(labelPrefix##8)\
+	AS2(	movdqu	[outputPtr+p0*16], xmm##x0)\
+	AS2(	movdqu	[outputPtr+p1*16], xmm##x1)\
+	AS2(	movdqu	[outputPtr+p2*16], xmm##x2)\
+	AS2(	movdqu	[outputPtr+p3*16], xmm##x3)\
+	ASL(labelPrefix##9)\
+	AS2(	add		outputPtr, increment*16)
+
+#endif  // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
+
+#endif  // Not CRYPTOPP_DOXYGEN_PROCESSING
+
+NAMESPACE_END
+
+// Issue 340
+#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
+# pragma GCC diagnostic pop
+#endif
+
+#endif  // CRYPTOPP_CPU_H

+ 90 - 0
cryptopp/crc.h

@@ -0,0 +1,90 @@
+// crc.h - originally written and placed in the public domain by Wei Dai
+
+/// \file crc.h
+/// \brief Classes for CRC-32 and CRC-32C checksum algorithm
+
+#ifndef CRYPTOPP_CRC32_H
+#define CRYPTOPP_CRC32_H
+
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+const word32 CRC32_NEGL = 0xffffffffL;
+
+#if (CRYPTOPP_LITTLE_ENDIAN)
+#define CRC32_INDEX(c) (c & 0xff)
+#define CRC32_SHIFTED(c) (c >> 8)
+#else
+#define CRC32_INDEX(c) (c >> 24)
+#define CRC32_SHIFTED(c) (c << 8)
+#endif
+
+/// \brief CRC-32 Checksum Calculation
+/// \details Uses CRC polynomial 0xEDB88320
+class CRC32 : public HashTransformation
+{
+public:
+	CRYPTOPP_CONSTANT(DIGESTSIZE = 4);
+	CRC32();
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *hash, size_t size);
+	unsigned int DigestSize() const {return DIGESTSIZE;}
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32";}
+	std::string AlgorithmName() const {return StaticAlgorithmName();}
+
+	/// \brief Updates a CRC with additional input
+	/// \param b the additional input as a byte
+	void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);}
+
+	/// \brief Retrieves the i-th byte of the CRC
+	/// \param i the additional input as a byte
+	/// \return the byte at the i-th position
+	byte GetCrcByte(size_t i) const {return reinterpret_cast<const byte *>(&m_crc)[i];}
+
+	std::string AlgorithmProvider() const;
+
+protected:
+	void Reset() {m_crc = CRC32_NEGL;}
+
+private:
+	static const word32 m_tab[256];
+	word32 m_crc;
+};
+
+/// \brief CRC-32C Checksum Calculation
+/// \details Uses CRC polynomial 0x82F63B78
+/// \since Crypto++ 5.6.4
+class CRC32C : public HashTransformation
+{
+public:
+	CRYPTOPP_CONSTANT(DIGESTSIZE = 4);
+	CRC32C();
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *hash, size_t size);
+	unsigned int DigestSize() const {return DIGESTSIZE;}
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32C";}
+	std::string AlgorithmName() const {return StaticAlgorithmName();}
+
+	/// \brief Updates a CRC with additional input
+	/// \param b the additional input as a byte
+	void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);}
+
+	/// \brief Retrieves the i-th byte of the CRC
+	/// \param i the additional input as a byte
+	/// \return the byte at the i-th position
+	byte GetCrcByte(size_t i) const {return reinterpret_cast<const byte *>(&m_crc)[i];}
+
+	std::string AlgorithmProvider() const;
+
+protected:
+	void Reset() {m_crc = CRC32_NEGL;}
+
+private:
+	static const word32 m_tab[256];
+	word32 m_crc;
+};
+
+NAMESPACE_END
+
+#endif

+ 3384 - 0
cryptopp/cryptlib.h

@@ -0,0 +1,3384 @@
+// cryptlib.h - originally written and placed in the public domain by Wei Dai
+
+/// \file cryptlib.h
+/// \brief Abstract base classes that provide a uniform interface to this library.
+
+/*!	\mainpage Crypto++ Library 8.9 API Reference
+<dl>
+<dt>Abstract Base Classes<dd>
+	cryptlib.h
+<dt>Authenticated Encryption Modes<dd>
+	CCM, EAX, \ref GCM "GCM (2K tables)", \ref GCM "GCM (64K tables)"
+<dt>Block Ciphers<dd>
+	\ref Rijndael "AES", ARIA, Weak::ARC4, Blowfish, BTEA, \ref CHAM128 "CHAM (64/128)", Camellia,
+	\ref CAST128 "CAST (128/256)", DES, \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES",
+	\ref DES_XEX3 "DESX", GOST, HIGHT, IDEA, LEA, \ref LR "Luby-Rackoff", \ref Kalyna128 "Kalyna (128/256/512)",
+	MARS, RC2, RC5, RC6, \ref SAFER_K "SAFER-K", \ref SAFER_SK "SAFER-SK", SEED, Serpent,
+	\ref SHACAL2 "SHACAL-2", SHARK, \ref SIMECK64 "SIMECK (32/64)" SKIPJACK, SM4, Square, TEA,
+	\ref ThreeWay "3-Way", \ref Threefish256 "Threefish (256/512/1024)", Twofish, XTEA
+<dt>Stream Ciphers<dd>
+	\ref ChaCha "ChaCha (8/12/20)", \ref HC128 "HC-128/256", \ref Panama "Panama-LE", \ref Panama "Panama-BE",
+	Rabbit, Salsa20, \ref SEAL "SEAL-LE", \ref SEAL "SEAL-BE", WAKE, XSalsa20
+<dt>Hash Functions<dd>
+	BLAKE2s, BLAKE2b, \ref Keccak "Keccak (F1600)", SHA1, SHA224, SHA256, SHA384, SHA512,
+	\ref SHA3 "SHA-3", SM3, LSH (256/512), Tiger, RIPEMD160, RIPEMD256, SipHash, Whirlpool,
+	Weak::MD2, Weak::MD4, Weak::MD5
+<dt>Non-Cryptographic Checksums<dd>
+	CRC32, CRC32C, Adler32
+<dt>Message Authentication Codes<dd>
+	BLAKE2b, BLAKE2s, CBC_MAC, CMAC, DMAC, \ref GCM "GCM (GMAC)", HMAC, Poly1305, TTMAC, VMAC
+<dt>Random Number Generators<dd>
+	NullRNG, LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG,
+	NIST Hash_DRBG and HMAC_DRBG, \ref MersenneTwister "MersenneTwister (MT19937 and MT19937-AR)",
+	DARN, RDRAND, RDSEED
+<dt>Key Derivation and Password-based Cryptography<dd>
+	HKDF, \ref PKCS12_PBKDF "PBKDF (PKCS #12)", \ref PKCS5_PBKDF1 "PBKDF-1 (PKCS #5)",
+	\ref PKCS5_PBKDF2_HMAC "PBKDF-2/HMAC (PKCS #5)"
+<dt>Public Key Cryptosystems<dd>
+	DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES
+<dt>Public Key Signature Schemes<dd>
+	DSA, DSA2, \ref ed25519 "Ed25519", GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO,
+	RabinSS, RWSS, ESIGN
+<dt>Key Agreement<dd>
+	DH, DH2, \ref x25519 "X25519", \ref MQV_Domain "MQV", \ref HMQV_Domain "HMQV",
+    \ref FHMQV_Domain "FHMQV", ECDH, x25519, ECMQV, ECHMQV, ECFHMQV, XTR_DH
+<dt>Algebraic Structures<dd>
+	Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver,
+	ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, GF2NP, GF256, GF2_32, EC2N, ECP
+<dt>Secret Sharing and Information Dispersal<dd>
+	SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery
+<dt>Compression<dd>
+	Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor
+<dt>Input Source Classes<dd>
+	StringSource, ArraySource, VectorSource, FileSource, RandomNumberSource
+<dt>Output Sink Classes<dd>
+	StringSinkTemplate, StringSink, VectorSink, ArraySink, FileSink, RandomNumberSink
+<dt>Filter Wrappers<dd>
+	StreamTransformationFilter, AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashFilter,
+	HashVerificationFilter, SignerFilter, SignatureVerificationFilter
+<dt>Binary to Text Encoders and Decoders<dd>
+	HexEncoder, HexDecoder, Base64Encoder, Base64Decoder, Base64URLEncoder, Base64URLDecoder, Base32Encoder,
+	Base32Decoder
+<dt>Wrappers for OS features<dd>
+	Timer, ThreadUserTimer
+
+</dl>
+
+<!--
+
+<dt>FIPS 140 validated cryptography<dd>
+	fips140.h
+
+In the DLL version of Crypto++, only the following implementation class are available.
+<dl>
+<dt>Block Ciphers<dd>
+	AES, \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES", SKIPJACK
+<dt>Cipher Modes (replace template parameter BC with one of the block ciphers above)<dd>
+	\ref ECB_Mode "ECB_Mode<BC>", \ref CTR_Mode "CTR_Mode<BC>", \ref CBC_Mode "CBC_Mode<BC>",
+	\ref CFB_FIPS_Mode "CFB_FIPS_Mode<BC>", \ref OFB_Mode "OFB_Mode<BC>", \ref GCM "GCM<AES>"
+<dt>Hash Functions<dd>
+	SHA1, SHA224, SHA256, SHA384, SHA512
+<dt>Public Key Signature Schemes (replace template parameter H with one of the hash functions above)<dd>
+	RSASS\<PKCS1v15, H\>, RSASS\<PSS, H\>, RSASS_ISO\<H\>, RWSS\<P1363_EMSA2, H\>, DSA, ECDSA\<ECP, H\>,
+	ECDSA\<EC2N, H\>
+<dt>Message Authentication Codes (replace template parameter H with one of the hash functions above)<dd>
+	HMAC\<H\>, CBC_MAC\<DES_EDE2\>, CBC_MAC\<DES_EDE3\>, GCM\<AES\>
+<dt>Random Number Generators<dd>
+	DefaultAutoSeededRNG (AutoSeededX917RNG\<AES\>)
+<dt>Key Agreement<dd>
+	DH, DH2
+<dt>Public Key Cryptosystems<dd>
+	RSAES\<OAEP\<SHA1\> \>
+</dl>
+
+-->
+
+<p>This reference manual is a work in progress. Some classes lack detailed descriptions.
+<p>Click <a href="CryptoPPRef.zip">here</a> to download a zip archive containing this manual.
+<p>Thanks to Ryan Phillips for providing the Doxygen configuration file
+and getting us started on the manual.
+*/
+
+#ifndef CRYPTOPP_CRYPTLIB_H
+#define CRYPTOPP_CRYPTLIB_H
+
+#include "config.h"
+#include "stdcpp.h"
+#include "trap.h"
+
+// C5264 new for VS2022/v17.4, MSC v17.3.4
+// https://github.com/weidai11/cryptopp/issues/1185
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4127 4189 4505 4702)
+# if (CRYPTOPP_MSC_VERSION >= 1933)
+#  pragma warning(disable: 5264)
+# endif
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+// forward declarations
+class Integer;
+class RandomNumberGenerator;
+class BufferedTransformation;
+
+/// \brief Specifies a direction for a cipher to operate
+/// \sa BlockTransformation::IsForwardTransformation(), BlockTransformation::IsPermutation(), BlockTransformation::GetCipherDirection()
+enum CipherDir {
+	/// \brief the cipher is performing encryption
+	ENCRYPTION,
+	/// \brief the cipher is performing decryption
+	DECRYPTION};
+
+/// \brief Represents infinite time
+CRYPTOPP_CONST_OR_CONSTEXPR unsigned long INFINITE_TIME = ULONG_MAX;
+
+// VC60 workaround: using enums as template parameters causes problems
+/// \brief Converts an enumeration to a type suitable for use as a template parameter
+template <typename ENUM_TYPE, int VALUE>
+struct EnumToType
+{
+	static ENUM_TYPE ToEnum() {return static_cast<ENUM_TYPE>(VALUE);}
+};
+
+/// \brief Provides the byte ordering
+/// \details Big-endian and little-endian modes are supported. Bi-endian and PDP-endian modes
+///  are not supported.
+enum ByteOrder {
+	/// \brief byte order is little-endian
+	LITTLE_ENDIAN_ORDER = 0,
+	/// \brief byte order is big-endian
+	BIG_ENDIAN_ORDER = 1};
+
+/// \brief Provides a constant for LittleEndian
+typedef EnumToType<ByteOrder, LITTLE_ENDIAN_ORDER> LittleEndian;
+/// \brief Provides a constant for BigEndian
+typedef EnumToType<ByteOrder, BIG_ENDIAN_ORDER> BigEndian;
+
+/// \brief Base class for all exceptions thrown by the library
+/// \details All library exceptions directly or indirectly inherit from the Exception class.
+///  The Exception class itself inherits from std::exception. The library does not use
+///  std::runtime_error derived classes.
+class CRYPTOPP_DLL Exception : public std::exception
+{
+public:
+	/// \enum ErrorType
+	/// \brief Error types or categories
+	enum ErrorType {
+		/// \brief A method was called which was not implemented
+		NOT_IMPLEMENTED,
+		/// \brief An invalid argument was detected
+		INVALID_ARGUMENT,
+		/// \brief BufferedTransformation received a Flush(true) signal but can't flush buffers
+		CANNOT_FLUSH,
+		/// \brief Data integerity check, such as CRC or MAC, failed
+		DATA_INTEGRITY_CHECK_FAILED,
+		/// \brief Input data was received that did not conform to expected format
+		INVALID_DATA_FORMAT,
+		/// \brief Error reading from input device or writing to output device
+		IO_ERROR,
+		/// \brief Some other error occurred not belonging to other categories
+		OTHER_ERROR
+	};
+
+	virtual ~Exception() throw() {}
+
+	/// \brief Construct a new Exception
+	explicit Exception(ErrorType errorType, const std::string &s) : m_errorType(errorType), m_what(s) {}
+
+	/// \brief Retrieves a C-string describing the exception
+	const char *what() const throw() {return (m_what.c_str());}
+	/// \brief Retrieves a string describing the exception
+	const std::string &GetWhat() const {return m_what;}
+	/// \brief Sets the error string for the exception
+	void SetWhat(const std::string &s) {m_what = s;}
+	/// \brief Retrieves the error type for the exception
+	ErrorType GetErrorType() const {return m_errorType;}
+	/// \brief Sets the error type for the exceptions
+	void SetErrorType(ErrorType errorType) {m_errorType = errorType;}
+
+private:
+	ErrorType m_errorType;
+	std::string m_what;
+};
+
+/// \brief An invalid argument was detected
+class CRYPTOPP_DLL InvalidArgument : public Exception
+{
+public:
+	/// \brief Construct an InvalidArgument
+	/// \param s the message for the exception
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {}
+};
+
+/// \brief Input data was received that did not conform to expected format
+class CRYPTOPP_DLL InvalidDataFormat : public Exception
+{
+public:
+	/// \brief Construct an InvalidDataFormat
+	/// \param s the message for the exception
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {}
+};
+
+/// \brief A decryption filter encountered invalid ciphertext
+class CRYPTOPP_DLL InvalidCiphertext : public InvalidDataFormat
+{
+public:
+	/// \brief Construct an InvalidCiphertext
+	/// \param s the message for the exception
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {}
+};
+
+/// \brief A method was called which was not implemented
+class CRYPTOPP_DLL NotImplemented : public Exception
+{
+public:
+	/// \brief Construct an NotImplemented
+	/// \param s the message for the exception
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {}
+};
+
+/// \brief Flush(true) was called but it can't completely flush its buffers
+class CRYPTOPP_DLL CannotFlush : public Exception
+{
+public:
+	/// \brief Construct an CannotFlush
+	/// \param s the message for the exception
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {}
+};
+
+/// \brief The operating system reported an error
+class CRYPTOPP_DLL OS_Error : public Exception
+{
+public:
+	virtual ~OS_Error() throw() {}
+
+	/// \brief Construct an OS_Error
+	/// \param errorType the error type
+	/// \param s the message for the exception
+	/// \param operation the operation for the exception
+	/// \param errorCode the error code
+	/// \details The member function <tt>what()</tt> returns <tt>s</tt>.
+	OS_Error(ErrorType errorType, const std::string &s, const std::string& operation, int errorCode)
+		: Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {}
+
+	/// \brief Retrieve the operating system API that reported the error
+	const std::string & GetOperation() const {return m_operation;}
+	/// \brief Retrieve the error code returned by the operating system
+	int GetErrorCode() const {return m_errorCode;}
+
+protected:
+	std::string m_operation;
+	int m_errorCode;
+};
+
+/// \brief Returns a decoding results
+struct CRYPTOPP_DLL DecodingResult
+{
+	/// \brief Constructs a DecodingResult
+	/// \details isValidCoding is initialized to false and messageLength is
+	///  initialized to 0.
+	explicit DecodingResult() : isValidCoding(false), messageLength(0) {}
+	/// \brief Constructs a DecodingResult
+	/// \param len the message length
+	/// \details isValidCoding is initialized to true.
+	explicit DecodingResult(size_t len) : isValidCoding(true), messageLength(len) {}
+
+	/// \brief Compare two DecodingResult
+	/// \param rhs the other DecodingResult
+	/// \return true if either isValidCoding or messageLength is \a not equal,
+	///  false otherwise
+	bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;}
+	/// \brief Compare two DecodingResult
+	/// \param rhs the other DecodingResult
+	/// \return true if either isValidCoding or messageLength is \a not equal,
+	///  false otherwise
+	/// \details Returns <tt>!operator==(rhs)</tt>.
+	bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);}
+
+	/// \brief Flag to indicate the decoding is valid
+	bool isValidCoding;
+	/// \brief Recovered message length if isValidCoding is true, undefined otherwise
+	size_t messageLength;
+};
+
+/// \brief Interface for retrieving values given their names
+/// \details This class is used to safely pass a variable number of arbitrarily
+///  typed arguments to functions and to read values from keys and crypto parameters.
+/// \details To obtain an object that implements NameValuePairs for the purpose of
+///  parameter passing, use the MakeParameters() function.
+/// \details To get a value from NameValuePairs, you need to know the name and the
+///  type of the value. Call GetValueNames() on a NameValuePairs object to obtain a
+///  list of value names that it supports. then look at the Name namespace
+///  documentation to see what the type of each value is, or alternatively, call
+///  GetIntValue() with the value name, and if the type is not int, a
+///  ValueTypeMismatch exception will be thrown and you can get the actual type from
+///  the exception object.
+/// \sa NullNameValuePairs, g_nullNameValuePairs,
+///  <A HREF="http://www.cryptopp.com/wiki/NameValuePairs">NameValuePairs</A> on the
+///  Crypto++ wiki
+class NameValuePairs
+{
+public:
+	virtual ~NameValuePairs() {}
+
+	/// \brief Thrown when an unexpected type is encountered
+	/// \details Exception thrown when trying to retrieve a value using a different
+	///  type than expected
+	class CRYPTOPP_DLL ValueTypeMismatch : public InvalidArgument
+	{
+	public:
+		/// \brief Construct a ValueTypeMismatch
+		/// \param name the name of the value
+		/// \param stored the \a actual type of the value stored
+		/// \param retrieving the \a presumed type of the value retrieved
+		ValueTypeMismatch(const std::string &name, const std::type_info &stored, const std::type_info &retrieving)
+			: InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'")
+			, m_stored(stored), m_retrieving(retrieving) {}
+
+		/// \brief Provides the stored type
+		/// \return the C++ mangled name of the type
+		const std::type_info & GetStoredTypeInfo() const {return m_stored;}
+
+		/// \brief Provides the retrieveing type
+		/// \return the C++ mangled name of the type
+		const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;}
+
+	private:
+		const std::type_info &m_stored;
+		const std::type_info &m_retrieving;
+	};
+
+	/// \brief Get a copy of this object or subobject
+	/// \tparam T class or type
+	/// \param object reference to a variable that receives the value
+	template <class T>
+	bool GetThisObject(T &object) const
+	{
+		return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object);
+	}
+
+	/// \brief Get a pointer to this object
+	/// \tparam T class or type
+	/// \param ptr reference to a pointer to a variable that receives the value
+	template <class T>
+	bool GetThisPointer(T *&ptr) const
+	{
+		return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), ptr);
+	}
+
+	/// \brief Get a named value
+	/// \tparam T class or type
+	/// \param name the name of the object or value to retrieve
+	/// \param value reference to a variable that receives the value
+	/// \return true if the value was retrieved, false otherwise
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	template <class T>
+	bool GetValue(const char *name, T &value) const
+	{
+		return GetVoidValue(name, typeid(T), &value);
+	}
+
+	/// \brief Get a named value
+	/// \tparam T class or type
+	/// \param name the name of the object or value to retrieve
+	/// \param defaultValue the default value of the class or type if it does not exist
+	/// \return the object or value
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	template <class T>
+	T GetValueWithDefault(const char *name, T defaultValue) const
+	{
+		T value;
+		bool result = GetValue(name, value);
+		// No assert... this recovers from failure
+		if (result) {return value;}
+		return defaultValue;
+	}
+
+	/// \brief Get a list of value names that can be retrieved
+	/// \return a list of names available to retrieve
+	/// \details the items in the list are delimited with a colon.
+	CRYPTOPP_DLL std::string GetValueNames() const
+		{std::string result; GetValue("ValueNames", result); return result;}
+
+	/// \brief Get a named value with type int
+	/// \param name the name of the value to retrieve
+	/// \param value the value retrieved upon success
+	/// \return true if an int value was retrieved, false otherwise
+	/// \details GetIntValue() is used to ensure we don't accidentally try to get an
+	///  unsigned int or some other type when we mean int (which is the most common case)
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL bool GetIntValue(const char *name, int &value) const
+		{return GetValue(name, value);}
+
+	/// \brief Get a named value with type int, with default
+	/// \param name the name of the value to retrieve
+	/// \param defaultValue the default value if the name does not exist
+	/// \return the value retrieved on success or the default value
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const
+		{return GetValueWithDefault(name, defaultValue);}
+
+	/// \brief Get a named value with type word64
+	/// \param name the name of the value to retrieve
+	/// \param value the value retrieved upon success
+	/// \return true if an word64 value was retrieved, false otherwise
+	/// \sa GetValue(), GetValueWithDefault(), GetWord64ValueWithDefault(), GetIntValue(),
+	///  GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL bool GetWord64Value(const char *name, word64 &value) const
+		{return GetValue(name, value);}
+
+	/// \brief Get a named value with type word64, with default
+	/// \param name the name of the value to retrieve
+	/// \param defaultValue the default value if the name does not exist
+	/// \return the value retrieved on success or the default value
+	/// \sa GetValue(), GetValueWithDefault(), GetWord64Value(), GetIntValue(),
+	///  GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredWord64Parameter()
+	CRYPTOPP_DLL word64 GetWord64ValueWithDefault(const char *name, word64 defaultValue) const
+		{return GetValueWithDefault(name, defaultValue);}
+
+	/// \brief Ensures an expected name and type is present
+	/// \param name the name of the value
+	/// \param stored the type that was stored for the name
+	/// \param retrieving the type that is being retrieved for the name
+	/// \throw ValueTypeMismatch
+	/// \details ThrowIfTypeMismatch() effectively performs a type safety check.
+	///  stored and retrieving are C++ mangled names for the type.
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL static void CRYPTOPP_API ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving)
+		{if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);}
+
+	/// \brief Retrieves a required name/value pair
+	/// \tparam T class or type
+	/// \param className the name of the class
+	/// \param name the name of the value
+	/// \param value reference to a variable to receive the value
+	/// \throw InvalidArgument
+	/// \details GetRequiredParameter() throws InvalidArgument if the name
+	///  is not present or not of the expected type T.
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	template <class T>
+	void GetRequiredParameter(const char *className, const char *name, T &value) const
+	{
+		if (!GetValue(name, value))
+			throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'");
+	}
+
+	/// \brief Retrieves a required name/value pair
+	/// \param className the name of the class
+	/// \param name the name of the value
+	/// \param value reference to a variable to receive the value
+	/// \throw InvalidArgument
+	/// \details GetRequiredParameter() throws InvalidArgument if the name
+	///  is not present or not of the expected type T.
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL void GetRequiredIntParameter(const char *className, const char *name, int &value) const
+	{
+		if (!GetIntValue(name, value))
+			throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'");
+	}
+
+	/// \brief Get a named value
+	/// \param name the name of the object or value to retrieve
+	/// \param valueType reference to a variable that receives the value
+	/// \param pValue void pointer to a variable that receives the value
+	/// \return true if the value was retrieved, false otherwise
+	/// \details GetVoidValue() retrieves the value of name if it exists.
+	/// \note GetVoidValue() is an internal function and should be implemented
+	///  by derived classes. Users should use one of the other functions instead.
+	/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+	///  GetRequiredParameter() and GetRequiredIntParameter()
+	CRYPTOPP_DLL virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
+};
+
+// Doxygen cannot handle initialization
+#if CRYPTOPP_DOXYGEN_PROCESSING
+/// \brief Default channel for BufferedTransformation
+/// \details DEFAULT_CHANNEL is equal to an empty string
+/// \details The definition for DEFAULT_CHANNEL is in <tt>cryptlib.cpp</tt>.
+///  It can be subject to <A HREF="https://isocpp.org/wiki/faq/ctors">Static
+///  Initialization Order Fiasco</A>. If you experience a crash in
+///  DEFAULT_CHANNEL where the string object is NULL, then you probably have
+///  a global object using DEFAULT_CHANNEL before it has been constructed.
+const std::string DEFAULT_CHANNEL;
+
+/// \brief Channel for additional authenticated data
+/// \details AAD_CHANNEL is equal to "AAD"
+/// \details The definition for AAD_CHANNEL is in <tt>cryptlib.cpp</tt>.
+///  It can be subject to <A HREF="https://isocpp.org/wiki/faq/ctors">Static
+///  Initialization Order Fiasco</A>. If you experience a crash in
+///  AAD_CHANNEL where the string object is NULL, then you probably have a
+///  global object using AAD_CHANNEL before it has been constructed.
+const std::string AAD_CHANNEL;
+
+/// \brief An empty set of name-value pairs
+/// \details The definition for g_nullNameValuePairs is in <tt>cryptlib.cpp</tt>.
+///  It can be subject to <A HREF="https://isocpp.org/wiki/faq/ctors">Static
+///  Initialization Order Fiasco</A>. If you experience a crash in
+///  g_nullNameValuePairs where the string object is NULL, then you probably
+///  have a global object using g_nullNameValuePairs before it has been
+///  constructed.
+const NameValuePairs& g_nullNameValuePairs;
+
+#else
+extern CRYPTOPP_DLL const std::string DEFAULT_CHANNEL;
+extern CRYPTOPP_DLL const std::string AAD_CHANNEL;
+extern CRYPTOPP_DLL const NameValuePairs& g_nullNameValuePairs;
+#endif
+
+// Document additional name spaces which show up elsewhere in the sources.
+#if CRYPTOPP_DOXYGEN_PROCESSING
+/// \brief Namespace containing value name definitions.
+/// \details Name is part of the CryptoPP namespace.
+/// \details The semantics of value names, types are:
+/// <pre>
+///     ThisObject:ClassName (ClassName, copy of this object or a subobject)
+///     ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject)
+/// </pre>
+DOCUMENTED_NAMESPACE_BEGIN(Name)
+// more names defined in argnames.h
+DOCUMENTED_NAMESPACE_END
+
+/// \brief Namespace containing weak and wounded algorithms.
+/// \details Weak is part of the CryptoPP namespace. Schemes and algorithms are moved into Weak
+///  when their security level is reduced to an unacceptable level by contemporary standards.
+/// \details To use an algorithm in the Weak namespace, you must <tt>\c \#define
+///  CRYPTOPP_ENABLE_NAMESPACE_WEAK 1</tt> before including a header for a weak or wounded
+///  algorithm. For example:
+///  <pre>  \c \#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
+///   \c \#include <md5.h>
+///   ...
+///   CryptoPP::Weak::MD5 md5;
+///   </pre>
+DOCUMENTED_NAMESPACE_BEGIN(Weak)
+// weak and wounded algorithms
+DOCUMENTED_NAMESPACE_END
+#endif
+
+/// \brief Namespace containing NaCl library functions
+/// \details TweetNaCl is a compact and portable reimplementation of the NaCl library.
+DOCUMENTED_NAMESPACE_BEGIN(NaCl)
+// crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open (and friends)
+DOCUMENTED_NAMESPACE_END
+
+/// \brief Namespace containing testing and benchmark classes.
+/// \details Source files for classes in the Test namespaces include
+///  <tt>test.cpp</tt>, <tt>validat#.cpp</tt> and <tt>bench#.cpp</tt>.
+DOCUMENTED_NAMESPACE_BEGIN(Test)
+// testing and benchmark classes
+DOCUMENTED_NAMESPACE_END
+
+// ********************************************************
+
+/// \brief Interface for cloning objects
+/// \note this is \a not implemented by most classes
+/// \sa ClonableImpl, NotCopyable
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Clonable
+{
+public:
+	virtual ~Clonable() {}
+
+	/// \brief Copies  this object
+	/// \return a copy of this object
+	/// \throw NotImplemented
+	/// \note this is \a not implemented by most classes
+	/// \sa NotCopyable
+	virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");}	// TODO: make this =0
+};
+
+/// \brief Interface for all crypto algorithms
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Algorithm : public Clonable
+{
+public:
+	virtual ~Algorithm() {}
+
+	/// \brief Interface for all crypto algorithms
+	/// \param checkSelfTestStatus determines whether the object can proceed if the self
+	///  tests have not been run or failed.
+	/// \details When FIPS 140-2 compliance is enabled and checkSelfTestStatus == true,
+	///  this constructor throws SelfTestFailure if the self test hasn't been run or fails.
+	/// \details FIPS 140-2 compliance is disabled by default. It is only used by certain
+	///  versions of the library when the library is built as a DLL on Windows. Also see
+	///  CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 in config.h.
+	Algorithm(bool checkSelfTestStatus = true);
+
+	/// \brief Provides the name of this algorithm
+	/// \return the standard algorithm name
+	/// \details The standard algorithm name can be a name like <tt>AES</tt> or <tt>AES/GCM</tt>.
+	///  Some algorithms do not have standard names yet. For example, there is no standard
+	///  algorithm name for Shoup's ECIES.
+	/// \note AlgorithmName is not universally implemented yet.
+	virtual std::string AlgorithmName() const {return "unknown";}
+
+	/// \brief Retrieve the provider of this algorithm
+	/// \return the algorithm provider
+	/// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI",
+	///  "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE,
+	///  usually indicate a specialized implementation using instructions from a higher
+	///  instruction set architecture (ISA). Future labels may include external hardware
+	///  like a hardware security module (HSM).
+	/// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2".
+	///  Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics
+	///  instead of ASM.
+	/// \details Algorithms which combine different instructions or ISAs provide the
+	///  dominant one. For example on x86 <tt>AES/GCM</tt> returns "AESNI" rather than
+	///  "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL".
+	/// \note Provider is not universally implemented yet.
+	/// \since Crypto++ 8.0
+	virtual std::string AlgorithmProvider() const {return "C++";}
+};
+
+/// \brief Interface for algorithms that take byte strings as keys
+/// \sa FixedKeyLength(), VariableKeyLength(), SameKeyLengthAs(), SimpleKeyingInterfaceImpl()
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyingInterface
+{
+public:
+	virtual ~SimpleKeyingInterface() {}
+
+	/// \brief Returns smallest valid key length
+	/// \return the minimum key length, in bytes
+	virtual size_t MinKeyLength() const =0;
+
+	/// \brief Returns largest valid key length
+	/// \return the maximum key length, in bytes
+	virtual size_t MaxKeyLength() const =0;
+
+	/// \brief Returns default key length
+	/// \return the default key length, in bytes
+	virtual size_t DefaultKeyLength() const =0;
+
+	/// \brief Returns a valid key length for the algorithm
+	/// \param keylength the size of the key, in bytes
+	/// \return the valid key length, in bytes
+	/// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH,
+	///  then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH,
+	///  then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE,
+	///  then keylength is returned. Otherwise, the function returns a \a lower multiple of
+	///  KEYLENGTH_MULTIPLE.
+	virtual size_t GetValidKeyLength(size_t keylength) const =0;
+
+	/// \brief Returns whether keylength is a valid key length
+	/// \param keylength the requested keylength
+	/// \return true if keylength is valid, false otherwise
+	/// \details Internally the function calls GetValidKeyLength()
+	virtual bool IsValidKeyLength(size_t keylength) const
+		{return keylength == GetValidKeyLength(keylength);}
+
+	/// \brief Sets or reset the key of this object
+	/// \param key the key to use when keying the object
+	/// \param length the size of the key, in bytes
+	/// \param params additional initialization parameters to configure this object
+	virtual void SetKey(const byte *key, size_t length, const NameValuePairs &params = g_nullNameValuePairs);
+
+	/// \brief Sets or reset the key of this object
+	/// \param key the key to use when keying the object
+	/// \param length the size of the key, in bytes
+	/// \param rounds the number of rounds to apply the transformation function,
+	///  if applicable
+	/// \details SetKeyWithRounds() calls SetKey() with a NameValuePairs
+	///  object that only specifies rounds. rounds is an integer parameter,
+	///  and <tt>-1</tt> means use the default number of rounds.
+	void SetKeyWithRounds(const byte *key, size_t length, int rounds);
+
+	/// \brief Sets or reset the key of this object
+	/// \param key the key to use when keying the object
+	/// \param length the size of the key, in bytes
+	/// \param iv the initialization vector to use when keying the object
+	/// \param ivLength the size of the iv, in bytes
+	/// \details SetKeyWithIV() calls SetKey() with a NameValuePairs
+	///  that only specifies IV. The IV is a byte buffer with size ivLength.
+	///  ivLength is an integer parameter, and <tt>-1</tt> means use IVSize().
+	void SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength);
+
+	/// \brief Sets or reset the key of this object
+	/// \param key the key to use when keying the object
+	/// \param length the size of the key, in bytes
+	/// \param iv the initialization vector to use when keying the object
+	/// \details SetKeyWithIV() calls SetKey() with a NameValuePairs() object
+	///  that only specifies iv. iv is a byte buffer, and it must have
+	///  a size IVSize().
+	void SetKeyWithIV(const byte *key, size_t length, const byte *iv)
+		{SetKeyWithIV(key, length, iv, IVSize());}
+
+	/// \brief Secure IVs requirements as enumerated values.
+	/// \details Provides secure IV requirements as a monotonically increasing enumerated values.
+	///  Requirements can be compared using less than (&lt;) and greater than (&gt;). For example,
+	///  <tt>UNIQUE_IV &lt; RANDOM_IV</tt> and <tt>UNPREDICTABLE_RANDOM_IV &gt; RANDOM_IV</tt>.
+	/// \details Objects that use SimpleKeyingInterface do not support an optional IV. That is,
+	///	 an IV must be present or it must be absent. If you wish to support an optional IV then
+	///  provide two classes - one with an IV and one without an IV.
+	/// \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs()
+	enum IV_Requirement {
+		/// \brief The IV must be unique
+		UNIQUE_IV = 0,
+		/// \brief The IV must be random and possibly predictable
+		RANDOM_IV,
+		/// \brief The IV must be random and unpredictable
+		UNPREDICTABLE_RANDOM_IV,
+		/// \brief The IV is set by the object
+		INTERNALLY_GENERATED_IV,
+		/// \brief The object does not use an IV
+		NOT_RESYNCHRONIZABLE
+	};
+
+	/// \brief Minimal requirement for secure IVs
+	/// \return the secure IV requirement of the algorithm
+	virtual IV_Requirement IVRequirement() const =0;
+
+	/// \brief Determines if the object can be resynchronized
+	/// \return true if the object can be resynchronized (i.e. supports initialization vectors), false otherwise
+	/// \note If this function returns true, and no IV is passed to SetKey() and <tt>CanUseStructuredIVs()==true</tt>,
+	///  an IV of all 0's will be assumed.
+	bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;}
+
+	/// \brief Determines if the object can use random IVs
+	/// \return true if the object can use random IVs (in addition to ones returned by GetNextIV), false otherwise
+	bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;}
+
+	/// \brief Determines if the object can use random but possibly predictable IVs
+	/// \return true if the object can use random but possibly predictable IVs (in addition to ones returned by
+	///  GetNextIV), false otherwise
+	bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;}
+
+	/// \brief Determines if the object can use structured IVs
+	/// \return true if the object can use structured IVs, false otherwise
+	/// \details CanUseStructuredIVs() indicates whether the object can use structured IVs; for example a counter
+	///  (in addition to ones returned by GetNextIV).
+	bool CanUseStructuredIVs() const {return IVRequirement() <= UNIQUE_IV;}
+
+	/// \brief Returns length of the IV accepted by this object
+	/// \return the size of an IV, in bytes
+	/// \throw NotImplemented() if the object does not support resynchronization
+	/// \details The default implementation throws NotImplemented
+	virtual unsigned int IVSize() const
+		{throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");}
+
+	/// \brief Provides the default size of an IV
+	/// \return default length of IVs accepted by this object, in bytes
+	unsigned int DefaultIVLength() const {return IVSize();}
+
+	/// \brief Provides the minimum size of an IV
+	/// \return minimal length of IVs accepted by this object, in bytes
+	/// \throw NotImplemented() if the object does not support resynchronization
+	virtual unsigned int MinIVLength() const {return IVSize();}
+
+	/// \brief Provides the maximum size of an IV
+	/// \return maximal length of IVs accepted by this object, in bytes
+	/// \throw NotImplemented() if the object does not support resynchronization
+	virtual unsigned int MaxIVLength() const {return IVSize();}
+
+	/// \brief Resynchronize with an IV
+	/// \param iv the initialization vector
+	/// \param ivLength the size of the initialization vector, in bytes
+	/// \details Resynchronize() resynchronizes with an IV provided by the caller. <tt>ivLength=-1</tt> means use IVSize().
+	/// \throw NotImplemented() if the object does not support resynchronization
+	virtual void Resynchronize(const byte *iv, int ivLength=-1) {
+		CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(ivLength);
+		throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");
+	}
+
+	/// \brief Retrieves a secure IV for the next message
+	/// \param rng a RandomNumberGenerator to produce keying material
+	/// \param iv a block of bytes to receive the IV
+	/// \details The IV must be at least IVSize() in length.
+	/// \details This method should be called after you finish encrypting one message and are ready
+	///  to start the next one. After calling it, you must call SetKey() or Resynchronize().
+	///  before using this object again.
+	/// \details Internally, the base class implementation calls RandomNumberGenerator's GenerateBlock()
+	/// \note This method is not implemented on decryption objects.
+	virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv);
+
+protected:
+	/// \brief Returns the base class Algorithm
+	/// \return the base class Algorithm
+	virtual const Algorithm & GetAlgorithm() const =0;
+
+	/// \brief Sets the key for this object without performing parameter validation
+	/// \param key a byte buffer used to key the cipher
+	/// \param length the length of the byte buffer
+	/// \param params additional parameters passed as NameValuePairs
+	/// \details key must be at least DEFAULT_KEYLENGTH in length.
+	virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params) =0;
+
+	/// \brief Validates the key length
+	/// \param length the size of the keying material, in bytes
+	/// \throw InvalidKeyLength if the key length is invalid
+	void ThrowIfInvalidKeyLength(size_t length);
+
+	/// \brief Validates the object
+	/// \throw InvalidArgument if the IV is present
+	/// \details Internally, the default implementation calls IsResynchronizable() and throws
+	///  InvalidArgument if the function returns  true.
+	/// \note called when no IV is passed
+	void ThrowIfResynchronizable();
+
+	/// \brief Validates the IV
+	/// \param iv the IV with a length of IVSize, in bytes
+	/// \throw InvalidArgument on failure
+	/// \details Internally, the default implementation checks the iv. If iv is not NULL or nullptr,
+	///  then the function succeeds. If iv is NULL, then IVRequirement is checked against
+	///  UNPREDICTABLE_RANDOM_IV. If IVRequirement is UNPREDICTABLE_RANDOM_IV, then
+	///  then the function succeeds. Otherwise, an exception is thrown.
+	void ThrowIfInvalidIV(const byte *iv);
+
+	/// \brief Validates the IV length
+	/// \param length the size of an IV, in bytes
+	/// \throw InvalidArgument if the IV length is invalid
+	size_t ThrowIfInvalidIVLength(int length);
+
+	/// \brief Retrieves and validates the IV
+	/// \param params NameValuePairs with the IV supplied as a ConstByteArrayParameter
+	/// \param size the length of the IV, in bytes
+	/// \return a pointer to the first byte of the IV
+	/// \throw InvalidArgument if the number of rounds are invalid
+	const byte * GetIVAndThrowIfInvalid(const NameValuePairs &params, size_t &size);
+
+	/// \brief Validates the key length
+	/// \param length the size of the keying material, in bytes
+	inline void AssertValidKeyLength(size_t length) const
+		{CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(IsValidKeyLength(length));}
+};
+
+/// \brief Interface for the data processing part of block ciphers
+/// \details Classes derived from BlockTransformation are block ciphers
+///  in ECB mode (for example the DES::Encryption class), which are stateless.
+///  These classes should not be used directly, but only in combination with
+///  a mode class (see CipherModeDocumentation in modes.h).
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockTransformation : public Algorithm
+{
+public:
+	virtual ~BlockTransformation() {}
+
+	/// \brief Encrypt or decrypt a block
+	/// \param inBlock the input message before processing
+	/// \param outBlock the output message after processing
+	/// \param xorBlock an optional XOR mask
+	/// \details ProcessAndXorBlock encrypts or decrypts inBlock, xor with xorBlock, and write to outBlock.
+	/// \details The size of the block is determined by the block cipher and its documentation. Use
+	///  BLOCKSIZE at compile time, or BlockSize() at runtime.
+	/// \note The message can be transformed in-place, or the buffers must \a not overlap
+	/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
+	virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0;
+
+	/// \brief Encrypt or decrypt a block
+	/// \param inBlock the input message before processing
+	/// \param outBlock the output message after processing
+	/// \details ProcessBlock encrypts or decrypts inBlock and write to outBlock.
+	/// \details The size of the block is determined by the block cipher and its documentation.
+	///  Use BLOCKSIZE at compile time, or BlockSize() at runtime.
+	/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
+	/// \note The message can be transformed in-place, or the buffers must \a not overlap
+	void ProcessBlock(const byte *inBlock, byte *outBlock) const
+		{ProcessAndXorBlock(inBlock, NULLPTR, outBlock);}
+
+	/// \brief Encrypt or decrypt a block in place
+	/// \param inoutBlock the input message before processing
+	/// \details ProcessBlock encrypts or decrypts inoutBlock in-place.
+	/// \details The size of the block is determined by the block cipher and its documentation.
+	///  Use BLOCKSIZE at compile time, or BlockSize() at runtime.
+	/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
+	void ProcessBlock(byte *inoutBlock) const
+		{ProcessAndXorBlock(inoutBlock, NULLPTR, inoutBlock);}
+
+	/// Provides the block size of the cipher
+	/// \return the block size of the cipher, in bytes
+	virtual unsigned int BlockSize() const =0;
+
+	/// \brief Provides input and output data alignment for optimal performance.
+	/// \return the input data alignment that provides optimal performance
+	/// \sa GetAlignment() and OptimalBlockSize()
+	virtual unsigned int OptimalDataAlignment() const;
+
+	/// \brief Determines if the transformation is a permutation
+	/// \return true if this is a permutation (i.e. there is an inverse transformation)
+	virtual bool IsPermutation() const {return true;}
+
+	/// \brief Determines if the cipher is being operated in its forward direction
+	/// \return true if DIR is ENCRYPTION, false otherwise
+	/// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection()
+	virtual bool IsForwardTransformation() const =0;
+
+	/// \brief Determines the number of blocks that can be processed in parallel
+	/// \return the number of blocks that can be processed in parallel, for bit-slicing implementations
+	/// \details Bit-slicing is often used to improve throughput and minimize timing attacks.
+	virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;}
+
+	/// \brief Bit flags that control AdvancedProcessBlocks() behavior
+	enum FlagsForAdvancedProcessBlocks {
+		/// \brief inBlock is a counter
+		BT_InBlockIsCounter=1,
+		/// \brief should not modify block pointers
+		BT_DontIncrementInOutPointers=2,
+		/// \brief Xor inputs before transformation
+		BT_XorInput=4,
+		/// \brief perform the transformation in reverse
+		BT_ReverseDirection=8,
+		/// \brief Allow parallel transformations
+		BT_AllowParallel=16};
+
+	/// \brief Encrypt and xor multiple blocks using additional flags
+	/// \param inBlocks the input message before processing
+	/// \param xorBlocks an optional XOR mask
+	/// \param outBlocks the output message after processing
+	/// \param length the size of the blocks, in bytes
+	/// \param flags additional flags to control processing
+	/// \details Encrypt and xor multiple blocks according to FlagsForAdvancedProcessBlocks flags.
+	/// \note If BT_InBlockIsCounter is set, then the last byte of inBlocks may be modified.
+	virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const;
+
+	/// \brief Provides the direction of the cipher
+	/// \return ENCRYPTION if IsForwardTransformation() is true, DECRYPTION otherwise
+	/// \sa IsForwardTransformation(), IsPermutation()
+	inline CipherDir GetCipherDirection() const {return IsForwardTransformation() ? ENCRYPTION : DECRYPTION;}
+};
+
+/// \brief Interface for the data processing portion of stream ciphers
+/// \sa StreamTransformationFilter()
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm
+{
+public:
+	virtual ~StreamTransformation() {}
+
+	/// \brief Provides a reference to this object
+	/// \return A reference to this object
+	/// \details Useful for passing a temporary object to a function that takes a non-const reference
+	StreamTransformation& Ref() {return *this;}
+
+	/// \brief Provides the mandatory block size of the cipher
+	/// \return The block size of the cipher if input must be processed in blocks, 1 otherwise
+	/// \details Stream ciphers and some block ciphers modes of operation return 1. Modes that
+	///  return 1 must be able to process a single byte at a time, like counter mode. If a
+	///  mode of operation or block cipher cannot stream then it must not return 1.
+	/// \details When filters operate the mode or cipher, ProcessData will be called with a
+	///  string of bytes that is determined by MandatoryBlockSize and OptimalBlockSize. When a
+	///  policy is set, like 16-byte strings for a 16-byte block cipher, the filter will buffer
+	///  bytes until the specified number of bytes is available to the object.
+	/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
+	virtual unsigned int MandatoryBlockSize() const {return 1;}
+
+	/// \brief Provides the input block size most efficient for this cipher
+	/// \return The input block size that is most efficient for the cipher
+	/// \details The base class implementation returns MandatoryBlockSize().
+	/// \note Optimal input length is
+	///  <tt>n * OptimalBlockSize() - GetOptimalBlockSizeUsed()</tt> for any <tt>n \> 0</tt>.
+	virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();}
+
+	/// \brief Provides the number of bytes used in the current block when processing at optimal block size.
+	/// \return the number of bytes used in the current block when processing at the optimal block size
+	virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;}
+
+	/// \brief Provides input and output data alignment for optimal performance
+	/// \return the input data alignment that provides optimal performance
+	/// \sa GetAlignment() and OptimalBlockSize()
+	virtual unsigned int OptimalDataAlignment() const;
+
+	/// \brief Encrypt or decrypt an array of bytes
+	/// \param outString the output byte buffer
+	/// \param inString the input byte buffer
+	/// \param length the size of the input and output byte buffers, in bytes
+	/// \details ProcessData is called with a string of bytes whose size depends on MandatoryBlockSize.
+	///  Either <tt>inString == outString</tt>, or they must not overlap.
+	/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
+	virtual void ProcessData(byte *outString, const byte *inString, size_t length) =0;
+
+	/// \brief Encrypt or decrypt the last block of data
+	/// \param outString the output byte buffer
+	/// \param outLength the size of the output byte buffer, in bytes
+	/// \param inString the input byte buffer
+	/// \param inLength the size of the input byte buffer, in bytes
+	/// \return the number of bytes used in outString
+	/// \details ProcessLastBlock is used when the last block of data is special and requires handling
+	///  by the cipher. The current implementation provides an output buffer with a size
+	///  <tt>inLength+2*MandatoryBlockSize()</tt>. The return value allows the cipher to expand cipher
+	///  text during encryption or shrink plain text during decryption.
+	/// \details This member function is used by CBC-CTS and OCB modes.
+	/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
+	virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength);
+
+	/// \brief Provides the size of the last block
+	/// \return the minimum size of the last block
+	/// \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last
+	///  block is not special.
+	/// \details MandatoryBlockSize() enlists one of two behaviors. First, if MandatoryBlockSize()
+	///  returns 1, then the cipher can be streamed and ProcessData() is called with the tail bytes.
+	///  Second, if MandatoryBlockSize() returns non-0, then the string of bytes is padded to
+	///  MandatoryBlockSize() according to the padding mode. Then, ProcessData() is called with the
+	///  padded string of bytes.
+	/// \details Some authenticated encryption modes are not expressed well with MandatoryBlockSize()
+	///  and MinLastBlockSize(). For example, AES/OCB uses 16-byte blocks (MandatoryBlockSize = 16)
+	///  and the last block requires special processing (MinLastBlockSize = 0). However, 0 is a valid
+	///  last block size for OCB and the special processing is custom padding, and not standard PKCS
+	///  padding. In response an unambiguous IsLastBlockSpecial() was added.
+	/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
+	virtual unsigned int MinLastBlockSize() const {return 0;}
+
+	/// \brief Determines if the last block receives special processing
+	/// \return true if the last block receives special processing, false otherwise.
+	/// \details Some authenticated encryption modes are not expressed well with
+	///  MandatoryBlockSize() and MinLastBlockSize(). For example, AES/OCB uses
+	///  16-byte blocks (MandatoryBlockSize = 16) and the last block requires special processing
+	///  (MinLastBlockSize = 0). However, 0 is a valid last block size for OCB and the special
+	///  processing is custom padding, and not standard PKCS padding. In response an
+	///  unambiguous IsLastBlockSpecial() was added.
+	/// \details When IsLastBlockSpecial() returns false nothing special happens. All the former
+	///  rules and behaviors apply. This is the default behavior of IsLastBlockSpecial().
+	/// \details When IsLastBlockSpecial() returns true four things happen. First, MinLastBlockSize = 0
+	///  means 0 is a valid block size that should be processed. Second, standard block cipher padding is
+	///  \a not \a applied. Third, the caller supplies an outString is larger than inString by
+	///  <tt>2*MandatoryBlockSize()</tt>. That is, there's a reserve available when processing the last block.
+	///  Fourth, the cipher is responsible for finalization like custom padding. The cipher will tell
+	///  the library how many bytes were processed or used by returning the appropriate value from
+	///  ProcessLastBlock().
+	/// \details The return value of ProcessLastBlock() indicates how many bytes were written to
+	///  <tt>outString</tt>. A filter pipelining data will send <tt>outString</tt> and up to <tt>outLength</tt>
+	///  to an <tt>AttachedTransformation()</tt> for additional processing. Below is an example of the code
+	///  used in <tt>StreamTransformationFilter::LastPut</tt>.
+	/// <pre>  if (m_cipher.IsLastBlockSpecial())
+	///   {
+	///     size_t reserve = 2*m_cipher.MandatoryBlockSize();
+	///     space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length+reserve);
+	///     length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
+	///     AttachedTransformation()->Put(space, length);
+	///     return;
+	///   }</pre>
+	/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
+	/// \since Crypto++ 6.0
+	virtual bool IsLastBlockSpecial() const {return false;}
+
+	/// \brief Encrypt or decrypt a string of bytes
+	/// \param inoutString the string to process
+	/// \param length the size of the inoutString, in bytes
+	/// \details Internally, the base class implementation calls ProcessData().
+	inline void ProcessString(byte *inoutString, size_t length)
+		{ProcessData(inoutString, inoutString, length);}
+
+	/// \brief Encrypt or decrypt a string of bytes
+	/// \param outString the output string to process
+	/// \param inString the input string to process
+	/// \param length the size of the input and output strings, in bytes
+	/// \details Internally, the base class implementation calls ProcessData().
+	inline void ProcessString(byte *outString, const byte *inString, size_t length)
+		{ProcessData(outString, inString, length);}
+
+	/// \brief Encrypt or decrypt a byte
+	/// \param input the input byte to process
+	/// \details Internally, the base class implementation calls ProcessData() with a size of 1.
+	inline byte ProcessByte(byte input)
+		{ProcessData(&input, &input, 1); return input;}
+
+	/// \brief Determines whether the cipher supports random access
+	/// \return true if the cipher supports random access, false otherwise
+	virtual bool IsRandomAccess() const =0;
+
+	/// \brief Seek to an absolute position
+	/// \param pos position to seek
+	/// \throw NotImplemented
+	/// \details The base class implementation throws NotImplemented. The function
+	///  \ref CRYPTOPP_ASSERT "asserts" IsRandomAccess() in debug builds.
+	virtual void Seek(lword pos)
+	{
+		CRYPTOPP_UNUSED(pos);
+		CRYPTOPP_ASSERT(!IsRandomAccess());
+		throw NotImplemented("StreamTransformation: this object doesn't support random access");
+	}
+
+	/// \brief Determines whether the cipher is self-inverting
+	/// \return true if the cipher is self-inverting, false otherwise
+	/// \details IsSelfInverting determines whether this transformation is
+	///  self-inverting (e.g. xor with a keystream).
+	virtual bool IsSelfInverting() const =0;
+
+	/// \brief Determines if the cipher is being operated in its forward direction
+	/// \return true if DIR is ENCRYPTION, false otherwise
+	/// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection()
+	virtual bool IsForwardTransformation() const =0;
+};
+
+/// \brief Interface for hash functions and data processing part of MACs
+/// \details HashTransformation objects are stateful. They are created in an initial state,
+///  change state as Update() is called, and return to the initial
+///  state when Final() is called. This interface allows a large message to
+///  be hashed in pieces by calling Update() on each piece followed by
+///  calling Final().
+/// \sa HashFilter(), HashVerificationFilter()
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HashTransformation : public Algorithm
+{
+public:
+	virtual ~HashTransformation() {}
+
+	/// \brief Provides a reference to this object
+	/// \return A reference to this object
+	/// \details Useful for passing a temporary object to a function that takes a non-const reference
+	HashTransformation& Ref() {return *this;}
+
+	/// \brief Updates a hash with additional input
+	/// \param input the additional input as a buffer
+	/// \param length the size of the buffer, in bytes
+	virtual void Update(const byte *input, size_t length) =0;
+
+	/// \brief Request space which can be written into by the caller
+	/// \param size the requested size of the buffer
+	/// \details The purpose of this method is to help avoid extra memory allocations.
+	/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
+	///  size is the requested size of the buffer. When the call returns, size is the size of
+	///  the array returned to the caller.
+	/// \details The base class implementation sets size to 0 and returns NULL or nullptr.
+	/// \note Some objects, like ArraySink, cannot create a space because its fixed.
+	virtual byte * CreateUpdateSpace(size_t &size) {size=0; return NULLPTR;}
+
+	/// \brief Computes the hash of the current message
+	/// \param digest a pointer to the buffer to receive the hash
+	/// \details Final() restarts the hash for a new message.
+	/// \pre <tt>COUNTOF(digest) <= DigestSize()</tt> or <tt>COUNTOF(digest) <= HASH::DIGESTSIZE</tt> ensures
+	///  the output byte buffer is large enough for the digest.
+	virtual void Final(byte *digest)
+		{TruncatedFinal(digest, DigestSize());}
+
+	/// \brief Restart the hash
+	/// \details Discards the current state, and restart for a new message
+	virtual void Restart()
+		{TruncatedFinal(NULLPTR, 0);}
+
+	/// Provides the digest size of the hash
+	/// \return the digest size of the hash.
+	virtual unsigned int DigestSize() const =0;
+
+	/// Provides the tag size of the hash
+	/// \return the tag size of the hash.
+	/// \details Same as DigestSize().
+	unsigned int TagSize() const {return DigestSize();}
+
+	/// \brief Provides the block size of the compression function
+	/// \return block size of the compression function, in bytes
+	/// \details BlockSize() will return 0 if the hash is not block based
+	///  or does not have an equivalent block size. For example, Keccak
+	///  and SHA-3 do not have a block size, but they do have an equivalent
+	///  block size called rate expressed as <tt>r</tt>.
+	virtual unsigned int BlockSize() const {return 0;}
+
+	/// \brief Provides the input block size most efficient for this hash.
+	/// \return The input block size that is most efficient for the cipher
+	/// \details The base class implementation returns MandatoryBlockSize().
+	/// \details Optimal input length is
+	///  <tt>n * OptimalBlockSize() - GetOptimalBlockSizeUsed()</tt> for any <tt>n \> 0</tt>.
+	virtual unsigned int OptimalBlockSize() const {return 1;}
+
+	/// \brief Provides input and output data alignment for optimal performance
+	/// \return the input data alignment that provides optimal performance
+	/// \sa GetAlignment() and OptimalBlockSize()
+	virtual unsigned int OptimalDataAlignment() const;
+
+	/// \brief Updates the hash with additional input and computes the hash of the current message
+	/// \param digest a pointer to the buffer to receive the hash
+	/// \param input the additional input as a buffer
+	/// \param length the size of the buffer, in bytes
+	/// \details Use this if your input is in one piece and you don't want to call Update()
+	///  and Final() separately
+	/// \details CalculateDigest() restarts the hash for the next message.
+	/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
+	///  the output byte buffer is a valid size.
+	virtual void CalculateDigest(byte *digest, const byte *input, size_t length)
+		{Update(input, length); Final(digest);}
+
+	/// \brief Verifies the hash of the current message
+	/// \param digest a pointer to the buffer of an \a existing hash
+	/// \return \p true if the existing hash matches the computed hash, \p false otherwise
+	/// \throw InvalidArgument() if the existing hash's size exceeds DigestSize()
+	/// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is
+	///  a constant time comparison function. digestLength cannot exceed DigestSize().
+	/// \details Verify() restarts the hash for the next message.
+	/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
+	///  the input byte buffer is a valid size.
+	virtual bool Verify(const byte *digest)
+		{return TruncatedVerify(digest, DigestSize());}
+
+	/// \brief Updates the hash with additional input and verifies the hash of the current message
+	/// \param digest a pointer to the buffer of an \a existing hash
+	/// \param input the additional input as a buffer
+	/// \param length the size of the buffer, in bytes
+	/// \return \p true if the existing hash matches the computed hash, \p false otherwise
+	/// \throw InvalidArgument() if the existing hash's size exceeds DigestSize()
+	/// \details Use this if your input is in one piece and you don't want to call Update()
+	///  and Verify() separately
+	/// \details VerifyDigest() performs a bitwise compare on the buffers using VerifyBufsEqual(),
+	///  which is a constant time comparison function.
+	/// \details VerifyDigest() restarts the hash for the next message.
+	/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
+	///  the output byte buffer is a valid size.
+	virtual bool VerifyDigest(const byte *digest, const byte *input, size_t length)
+		{Update(input, length); return Verify(digest);}
+
+	/// \brief Computes the hash of the current message
+	/// \param digest a pointer to the buffer to receive the hash
+	/// \param digestSize the size of the truncated digest, in bytes
+	/// \details TruncatedFinal() calls Final() and then copies digestSize bytes to digest.
+	///  The hash is restarted the hash for the next message.
+	/// \pre <tt>COUNTOF(digest) <= DigestSize()</tt> or <tt>COUNTOF(digest) <= HASH::DIGESTSIZE</tt> ensures
+	///  the output byte buffer is a valid size.
+	virtual void TruncatedFinal(byte *digest, size_t digestSize) =0;
+
+	/// \brief Updates the hash with additional input and computes the hash of the current message
+	/// \param digest a pointer to the buffer to receive the hash
+	/// \param digestSize the length of the truncated hash, in bytes
+	/// \param input the additional input as a buffer
+	/// \param length the size of the buffer, in bytes
+	/// \details Use this if your input is in one piece and you don't want to call Update()
+	///  and CalculateDigest() separately.
+	/// \details CalculateTruncatedDigest() restarts the hash for the next message.
+	/// \pre <tt>digestSize <= DigestSize()</tt> or <tt>digestSize <= HASH::DIGESTSIZE</tt> ensures
+	///  the output byte buffer is a valid size.
+	virtual void CalculateTruncatedDigest(byte *digest, size_t digestSize, const byte *input, size_t length)
+		{Update(input, length); TruncatedFinal(digest, digestSize);}
+
+	/// \brief Verifies the hash of the current message
+	/// \param digest a pointer to the buffer of an \a existing hash
+	/// \param digestLength the size of the truncated hash, in bytes
+	/// \return \p true if the existing hash matches the computed hash, \p false otherwise
+	/// \throw InvalidArgument() if digestLength exceeds DigestSize()
+	/// \details TruncatedVerify() is a truncated version of Verify(). It can operate on a
+	///  buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize().
+	/// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is
+	///  a constant time comparison function. digestLength cannot exceed DigestSize().
+	/// \details TruncatedVerify() restarts the hash for the next message.
+	/// \pre <tt>digestLength <= DigestSize()</tt> or <tt>digestLength <= HASH::DIGESTSIZE</tt> ensures
+	///  the input byte buffer is a valid size.
+	virtual bool TruncatedVerify(const byte *digest, size_t digestLength);
+
+	/// \brief Updates the hash with additional input and verifies the hash of the current message
+	/// \param digest a pointer to the buffer of an \a existing hash
+	/// \param digestLength the size of the truncated hash, in bytes
+	/// \param input the additional input as a buffer
+	/// \param length the size of the buffer, in bytes
+	/// \return \p true if the existing hash matches the computed hash, \p false otherwise
+	/// \throw InvalidArgument() if digestLength exceeds DigestSize()
+	/// \details Use this if your input is in one piece and you don't want to call Update()
+	///  and TruncatedVerify() separately.
+	/// \details VerifyTruncatedDigest() is a truncated version of VerifyDigest(). It can operate
+	///  on a buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize().
+	/// \details VerifyTruncatedDigest() restarts the hash for the next message.
+	/// \pre <tt>digestLength <= DigestSize()</tt> or <tt>digestLength <= HASH::DIGESTSIZE</tt> ensures
+	///  the input byte buffer is a valid size.
+	virtual bool VerifyTruncatedDigest(const byte *digest, size_t digestLength, const byte *input, size_t length)
+		{Update(input, length); return TruncatedVerify(digest, digestLength);}
+
+protected:
+	/// \brief Validates a truncated digest size
+	/// \param size the requested digest size
+	/// \throw InvalidArgument if the algorithm's digest size cannot be truncated to the requested size
+	/// \details Throws an exception when the truncated digest size is greater than DigestSize()
+	void ThrowIfInvalidTruncatedSize(size_t size) const;
+};
+
+/// \brief Interface for one direction (encryption or decryption) of a block cipher
+/// \details These objects usually should not be used directly. See BlockTransformation for more details.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockCipher : public SimpleKeyingInterface, public BlockTransformation
+{
+protected:
+	const Algorithm & GetAlgorithm() const {return *this;}
+};
+
+/// \brief Interface for one direction (encryption or decryption) of a stream cipher or cipher mode
+/// \details These objects usually should not be used directly. See StreamTransformation for more details.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SymmetricCipher : public SimpleKeyingInterface, public StreamTransformation
+{
+protected:
+	const Algorithm & GetAlgorithm() const {return *this;}
+};
+
+/// \brief Interface for message authentication codes
+/// \details These objects usually should not be used directly. See HashTransformation for more details.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE MessageAuthenticationCode : public SimpleKeyingInterface, public HashTransformation
+{
+protected:
+	const Algorithm & GetAlgorithm() const {return *this;}
+};
+
+/// \brief Interface for authenticated encryption modes of operation
+/// \details AuthenticatedSymmetricCipher() provides the interface for one direction
+///  (encryption or decryption) of a stream cipher or block cipher mode with authentication. The
+///  StreamTransformation() part of this interface is used to encrypt or decrypt the data. The
+///  MessageAuthenticationCode() part of the interface is used to input additional authenticated
+///  data (AAD), which is MAC'ed but not encrypted. The MessageAuthenticationCode() part is also
+///  used to generate and verify the MAC.
+/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM
+///  and OCB mode. All modes implement AuthenticatedSymmetricCipher() and the motivation for
+///  the API, like calling AAD a &quot;header&quot;, can be found in Bellare, Rogaway and
+///  Wagner's <A HREF="http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf">The EAX Mode of
+///  Operation</A>. The EAX paper suggested a basic API to help standardize AEAD schemes in
+///  software and promote adoption of the modes.
+/// \sa <A HREF="http://www.cryptopp.com/wiki/Authenticated_Encryption">Authenticated
+///  Encryption</A> on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipher : public MessageAuthenticationCode, public StreamTransformation
+{
+public:
+	virtual ~AuthenticatedSymmetricCipher() {}
+
+	/// \brief Exception thrown when the object is in the wrong state for the operation
+	/// \details this indicates that a member function was called in the wrong state, for example trying to encrypt
+	///  a message before having set the key or IV
+	class BadState : public Exception
+	{
+	public:
+		explicit BadState(const std::string &name, const char *message) : Exception(OTHER_ERROR, name + ": " + message) {}
+		explicit BadState(const std::string &name, const char *function, const char *state) : Exception(OTHER_ERROR, name + ": " + function + " was called before " + state) {}
+	};
+
+	/// \brief Provides the maximum length of AAD that can be input
+	/// \return the maximum length of AAD that can be input before the encrypted data
+	virtual lword MaxHeaderLength() const =0;
+
+	/// \brief Provides the maximum length of encrypted data
+	/// \return the maximum length of encrypted data
+	virtual lword MaxMessageLength() const =0;
+
+	/// \brief Provides the maximum length of AAD
+	/// \return the maximum length of AAD that can be input after the encrypted data
+	virtual lword MaxFooterLength() const {return 0;}
+
+	/// \brief Determines if data lengths must be specified prior to inputting data
+	/// \return true if the data lengths are required before inputting data, false otherwise
+	/// \details if this function returns true, SpecifyDataLengths() must be called before attempting to input data.
+	///  This is the case for some schemes, such as CCM.
+	/// \sa SpecifyDataLengths()
+	virtual bool NeedsPrespecifiedDataLengths() const {return false;}
+
+	/// \brief Prescribes the data lengths
+	/// \param headerLength size of data before message is input, in bytes
+	/// \param messageLength size of the message, in bytes
+	/// \param footerLength size of data after message is input, in bytes
+	/// \details SpecifyDataLengths() only needs to be called if NeedsPrespecifiedDataLengths() returns <tt>true</tt>.
+	///  If <tt>true</tt>, then <tt>headerLength</tt> will be validated against <tt>MaxHeaderLength()</tt>,
+	///  <tt>messageLength</tt> will be validated against <tt>MaxMessageLength()</tt>, and
+	///  <tt>footerLength</tt> will be validated against <tt>MaxFooterLength()</tt>.
+	/// \sa NeedsPrespecifiedDataLengths()
+	void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0);
+
+	/// \brief Encrypts and calculates a MAC in one call
+	/// \param ciphertext the encryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param header the AAD buffer
+	/// \param headerLength the size of the AAD buffer, in bytes
+	/// \param message the message buffer
+	/// \param messageLength the size of the messagetext buffer, in bytes
+	/// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function
+	///  truncates the MAC if <tt>macSize < TagSize()</tt>.
+	virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength);
+
+	/// \brief Decrypts and verifies a MAC in one call
+	/// \param message the decryption buffer
+	/// \param mac the mac buffer
+	/// \param macSize the size of the MAC buffer, in bytes
+	/// \param iv the iv buffer
+	/// \param ivLength the size of the IV buffer, in bytes
+	/// \param header the AAD buffer
+	/// \param headerLength the size of the AAD buffer, in bytes
+	/// \param ciphertext the ciphertext buffer
+	/// \param ciphertextLength the size of the ciphertext buffer, in bytes
+	/// \return true if the MAC is valid and the decoding succeeded, false otherwise
+	/// \details DecryptAndVerify() decrypts and verifies the MAC in one call.
+	/// <tt>message</tt> is a decryption buffer and should be at least as large as the ciphertext buffer.
+	/// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC
+	///  is truncated if <tt>macLength < TagSize()</tt>.
+	virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength);
+
+	/// \brief Provides the name of this algorithm
+	/// \return the standard algorithm name
+	/// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms
+	///  do not have standard names yet. For example, there is no standard algorithm name for
+	///  Shoup's ECIES.
+	virtual std::string AlgorithmName() const;
+
+	/// \brief Retrieve the provider of this algorithm
+	/// \return the algorithm provider
+	/// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI",
+	///  "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE,
+	///  usually indicate a specialized implementation using instructions from a higher
+	///  instruction set architecture (ISA). Future labels may include external hardware
+	///  like a hardware security module (HSM).
+	/// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2".
+	///  Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics
+	///  instead of ASM.
+	/// \details Algorithms which combine different instructions or ISAs provide the
+	///  dominant one. For example on x86 <tt>AES/GCM</tt> returns "AESNI" rather than
+	///  "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL".
+	/// \note Provider is not universally implemented yet.
+	/// \since Crypto++ 8.0
+	virtual std::string AlgorithmProvider() const {return "C++";}
+
+protected:
+	const Algorithm & GetAlgorithm() const
+		{return *static_cast<const MessageAuthenticationCode *>(this);}
+	virtual void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength)
+		{CRYPTOPP_UNUSED(headerLength); CRYPTOPP_UNUSED(messageLength); CRYPTOPP_UNUSED(footerLength);}
+};
+
+/// \brief Interface for random number generators
+/// \details The library provides a number of random number generators, from software based
+///  to hardware based generators.
+/// \details All generated values are uniformly distributed over the range specified.
+/// \since Crypto++ 3.1
+/// \sa <A HREF="https://www.cryptopp.com/wiki/RandomNumberGenerator">RandomNumberGenerator</A>
+///  on the Crypto++ wiki
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomNumberGenerator : public Algorithm
+{
+public:
+	virtual ~RandomNumberGenerator() {}
+
+	/// \brief Update RNG state with additional unpredictable values
+	/// \param input the entropy to add to the generator
+	/// \param length the size of the input buffer
+	/// \throw NotImplemented
+	/// \details A generator may or may not accept additional entropy. Call CanIncorporateEntropy()
+	///  to test for the ability to use additional entropy.
+	/// \details If a derived class does not override IncorporateEntropy(), then the base class
+	///  throws NotImplemented.
+	virtual void IncorporateEntropy(const byte *input, size_t length)
+	{
+		CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
+		throw NotImplemented("RandomNumberGenerator: IncorporateEntropy not implemented");
+	}
+
+	/// \brief Determines if a generator can accept additional entropy
+	/// \return true if IncorporateEntropy() is implemented
+	virtual bool CanIncorporateEntropy() const {return false;}
+
+	/// \brief Generate new random byte and return it
+	/// \return a random 8-bit byte
+	/// \details Default implementation calls GenerateBlock() with one byte.
+	/// \details All generated values are uniformly distributed over the range specified within the
+	///  the constraints of a particular generator.
+	virtual byte GenerateByte();
+
+	/// \brief Generate new random bit and return it
+	/// \return a random bit
+	/// \details The default implementation calls GenerateByte() and return its lowest bit.
+	/// \details All generated values are uniformly distributed over the range specified within the
+	///  the constraints of a particular generator.
+	virtual unsigned int GenerateBit();
+
+	/// \brief Generate a random 32 bit word in the range min to max, inclusive
+	/// \param min the lower bound of the range
+	/// \param max the upper bound of the range
+	/// \return a random 32-bit word
+	/// \details The default implementation calls Crop() on the difference between max and
+	///  min, and then returns the result added to min.
+	/// \details All generated values are uniformly distributed over the range specified within the
+	///  the constraints of a particular generator.
+	virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL);
+
+	/// \brief Generate random array of bytes
+	/// \param output the byte buffer
+	/// \param size the length of the buffer, in bytes
+	/// \details All generated values are uniformly distributed over the range specified within the
+	///  the constraints of a particular generator.
+	/// \note A derived generator \a must override either GenerateBlock() or
+	///  GenerateIntoBufferedTransformation(). They can override both, or have one call the other.
+	virtual void GenerateBlock(byte *output, size_t size);
+
+	/// \brief Generate random bytes into a BufferedTransformation
+	/// \param target the BufferedTransformation object which receives the bytes
+	/// \param channel the channel on which the bytes should be pumped
+	/// \param length the number of bytes to generate
+	/// \details The default implementation calls GenerateBlock() and pumps the result into
+	///  the DEFAULT_CHANNEL of the target.
+	/// \details All generated values are uniformly distributed over the range specified within the
+	///  the constraints of a particular generator.
+	/// \note A derived generator \a must override either GenerateBlock() or
+	///  GenerateIntoBufferedTransformation(). They can override both, or have one call the other.
+	virtual void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length);
+
+	/// \brief Generate and discard n bytes
+	/// \param n the number of bytes to generate and discard
+	virtual void DiscardBytes(size_t n);
+
+	/// \brief Randomly shuffle the specified array
+	/// \param begin an iterator to the first element in the array
+	/// \param end an iterator beyond the last element in the array
+	/// \details The resulting permutation is uniformly distributed.
+	template <class IT> void Shuffle(IT begin, IT end)
+	{
+		// TODO: What happens if there are more than 2^32 elements?
+		for (; begin != end; ++begin)
+			std::iter_swap(begin, begin + GenerateWord32(0, static_cast<word32>(end-begin-1)));
+	}
+};
+
+/// \brief Interface for key derivation functions
+/// \since Crypto++ 7.0
+/// \sa <A HREF="https://www.cryptopp.com/wiki/KeyDerivationFunction">KeyDerivationFunction</A>
+///  on the Crypto++ wiki
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyDerivationFunction : public Algorithm
+{
+public:
+	virtual ~KeyDerivationFunction() {}
+
+	/// \brief Provides the name of this algorithm
+	/// \return the standard algorithm name
+	virtual std::string AlgorithmName() const =0;
+
+	/// \brief Determine minimum number of bytes
+	/// \return Minimum number of bytes which can be derived
+	virtual size_t MinDerivedKeyLength() const;
+
+	/// \brief Determine maximum number of bytes
+	/// \return Maximum number of bytes which can be derived
+	virtual size_t MaxDerivedKeyLength() const;
+
+	/// \brief Returns a valid key length for the derivation function
+	/// \param keylength the size of the derived key, in bytes
+	/// \return the valid key length, in bytes
+	virtual size_t GetValidDerivedLength(size_t keylength) const =0;
+
+	/// \brief Returns whether keylength is a valid key length
+	/// \param keylength the requested keylength
+	/// \return true if the derived keylength is valid, false otherwise
+	/// \details Internally the function calls GetValidKeyLength()
+	virtual bool IsValidDerivedLength(size_t keylength) const {
+		return keylength == GetValidDerivedLength(keylength);
+	}
+
+	/// \brief Derive a key from a seed
+	/// \param derived the derived output buffer
+	/// \param derivedLen the size of the derived buffer, in bytes
+	/// \param secret the seed input buffer
+	/// \param secretLen the size of the secret buffer, in bytes
+	/// \param params additional initialization parameters to configure this object
+	/// \return the number of iterations performed
+	/// \throw InvalidDerivedKeyLength if <tt>derivedLen</tt> is invalid for the scheme
+	/// \details DeriveKey() provides a standard interface to derive a key from
+	///  a secret seed and other parameters. Each class that derives from KeyDerivationFunction
+	///  provides an overload that accepts most parameters used by the derivation function.
+	/// \details the number of iterations performed by DeriveKey() may be 1. For example, a
+	///  scheme like HKDF does not use the iteration count so it returns 1.
+	virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params = g_nullNameValuePairs) const =0;
+
+	/// \brief Set or change parameters
+	/// \param params additional initialization parameters to configure this object
+	/// \details SetParameters() is useful for setting common parameters when an object is
+	///  reused. Some derivation function classes may choose to implement it.
+	virtual void SetParameters(const NameValuePairs& params);
+
+protected:
+	/// \brief Returns the base class Algorithm
+	/// \return the base class Algorithm
+	virtual const Algorithm & GetAlgorithm() const =0;
+
+	/// \brief Validates the derived key length
+	/// \param length the size of the derived key material, in bytes
+	/// \throw InvalidKeyLength if the key length is invalid
+	void ThrowIfInvalidDerivedKeyLength(size_t length) const;
+};
+
+/// \brief Interface for password based key derivation functions
+/// \since Crypto++ 7.0
+struct PasswordBasedKeyDerivationFunction : public KeyDerivationFunction
+{
+};
+
+/// \brief Random Number Generator that does not produce random numbers
+/// \return reference that can be passed to functions that require a RandomNumberGenerator
+/// \details NullRNG() returns a reference that can be passed to functions that require a
+///  RandomNumberGenerator but don't actually use it. The NullRNG() throws NotImplemented
+///  when a generation function is called.
+/// \sa ClassNullRNG, PK_SignatureScheme::IsProbabilistic()
+CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG();
+
+class WaitObjectContainer;
+class CallStack;
+
+/// \brief Interface for objects that can be waited on.
+class CRYPTOPP_NO_VTABLE Waitable
+{
+public:
+	virtual ~Waitable() {}
+
+	/// \brief Maximum number of wait objects that this object can return
+	/// \return the maximum number of wait objects
+	virtual unsigned int GetMaxWaitObjectCount() const =0;
+
+	/// \brief Retrieves waitable objects
+	/// \param container the wait container to receive the references to the objects.
+	/// \param callStack CallStack() object used to select waitable objects
+	/// \details GetWaitObjects() is usually called in one of two ways. First, it can
+	///  be called like <tt>something.GetWaitObjects(c, CallStack("my func after X", 0));</tt>.
+	///  Second, if in an outer GetWaitObjects() method that itself takes a callStack
+	///  parameter, it can be called like
+	///  <tt>innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));</tt>.
+	virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0;
+
+	/// \brief Wait on this object
+	/// \return true if the wait succeeded, false otherwise
+	/// \details Wait() is the same as creating an empty container, calling GetWaitObjects(), and then calling
+	///  Wait() on the container.
+	bool Wait(unsigned long milliseconds, CallStack const& callStack);
+};
+
+/// \brief Interface for buffered transformations
+/// \details BufferedTransformation is a generalization of BlockTransformation,
+///  StreamTransformation and HashTransformation.
+/// \details A buffered transformation is an object that takes a stream of bytes as input (this may
+///  be done in stages), does some computation on them, and then places the result into an internal
+///  buffer for later retrieval. Any partial result already in the output buffer is not modified
+///  by further input.
+/// \details If a method takes a "blocking" parameter, and you pass false for it, then the method
+///  will return before all input has been processed if the input cannot be processed without waiting
+///  (for network buffers to become available, for example). In this case the method will return true
+///  or a non-zero integer value. When this happens you must continue to call the method with the same
+///  parameters until it returns false or zero, before calling any other method on it or attached
+///  BufferedTransformation. The integer return value in this case is approximately
+///  the number of bytes left to be processed, and can be used to implement a progress bar.
+/// \details For functions that take a "propagation" parameter, <tt>propagation != 0</tt> means pass on
+///  the signal to attached BufferedTransformation objects, with propagation decremented at each
+///  step until it reaches <tt>0</tt>. <tt>-1</tt> means unlimited propagation.
+/// \details \a All of the retrieval functions, like Get() and GetWord32(), return the actual
+///  number of bytes retrieved, which is the lesser of the request number and MaxRetrievable().
+/// \details \a Most of the input functions, like Put() and PutWord32(), return the number of
+///  bytes remaining to be processed. A 0 value means all bytes were processed, and a non-0 value
+///  means bytes remain to be processed.
+/// \nosubgrouping
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BufferedTransformation : public Algorithm, public Waitable
+{
+public:
+	virtual ~BufferedTransformation() {}
+
+	/// \brief Construct a BufferedTransformation
+	BufferedTransformation() : Algorithm(false) {}
+
+	/// \brief Provides a reference to this object
+	/// \return A reference to this object
+	/// \details Useful for passing a temporary object to a function that takes a non-const reference
+	BufferedTransformation& Ref() {return *this;}
+
+	///	\name INPUT
+	//@{
+
+		/// \brief Input a byte for processing
+		/// \param inByte the 8-bit byte (octet) to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+		///  0 indicates all bytes were processed.
+		/// \details <tt>Put(byte)</tt> calls <tt>Put(byte*, size_t)</tt>.
+		size_t Put(byte inByte, bool blocking=true)
+			{return Put(&inByte, 1, blocking);}
+
+		/// \brief Input a byte buffer for processing
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+		///  0 indicates all bytes were processed.
+		/// \details Internally, Put() calls Put2().
+		size_t Put(const byte *inString, size_t length, bool blocking=true)
+			{return Put2(inString, length, 0, blocking);}
+
+		/// Input a 16-bit word for processing.
+		/// \param value the 16-bit value to be processed
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+		///  0 indicates all bytes were processed.
+		size_t PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// Input a 32-bit word for processing.
+		/// \param value the 32-bit value to be processed.
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+		///  0 indicates all bytes were processed.
+		size_t PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// Input a 64-bit word for processing.
+		/// \param value the 64-bit value to be processed.
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+		///  0 indicates all bytes were processed.
+		size_t PutWord64(word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// \brief Request space which can be written into by the caller
+		/// \param size the requested size of the buffer
+		/// \return byte pointer to the space to input data
+		/// \details The purpose of this method is to help avoid extra memory allocations.
+		/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
+		///  size is the requested size of the buffer. When the call returns, size is the size of
+		///  the array returned to the caller.
+		/// \details The base class implementation sets size to 0 and returns NULL.
+		/// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of
+		/// an ArraySink, the pointer to the array is returned and the size is remaining size.
+		virtual byte * CreatePutSpace(size_t &size)
+			{size=0; return NULLPTR;}
+
+		/// \brief Determines whether input can be modified by the callee
+		/// \return true if input can be modified, false otherwise
+		/// \details The base class implementation returns false.
+		virtual bool CanModifyInput() const
+			{return false;}
+
+		/// \brief Input multiple bytes that may be modified by callee.
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all
+		///  bytes were processed.
+		size_t PutModifiable(byte *inString, size_t length, bool blocking=true)
+			{return PutModifiable2(inString, length, 0, blocking);}
+
+		/// \brief Signals the end of messages to the object
+		/// \param propagation the number of attached transformations the MessageEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		bool MessageEnd(int propagation=-1, bool blocking=true)
+			{return !!Put2(NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);}
+
+		/// \brief Input multiple bytes for processing and signal the end of a message
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param propagation the number of attached transformations the MessageEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all
+		///  bytes were processed.
+		/// \details Internally, PutMessageEnd() calls Put2() with a modified propagation to
+		///  ensure all attached transformations finish processing the message.
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		size_t PutMessageEnd(const byte *inString, size_t length, int propagation=-1, bool blocking=true)
+			{return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);}
+
+		/// \brief Input multiple bytes for processing
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all
+		///  bytes were processed.
+		/// \details Derived classes must implement Put2().
+		virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) =0;
+
+		/// \brief Input multiple bytes that may be modified by callee.
+		/// \param inString the byte buffer to process.
+		/// \param length the size of the string, in bytes.
+		/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all
+		///  bytes were processed.
+		/// \details Internally, PutModifiable2() calls Put2().
+		virtual size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
+			{return Put2(inString, length, messageEnd, blocking);}
+
+		/// \brief Exception thrown by objects that have \a not implemented nonblocking input processing
+		/// \details BlockingInputOnly inherits from NotImplemented
+		struct BlockingInputOnly : public NotImplemented
+			{BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}};
+	//@}
+
+	///	\name WAITING
+	//@{
+		/// \brief Retrieves the maximum number of waitable objects
+		unsigned int GetMaxWaitObjectCount() const;
+
+		/// \brief Retrieves waitable objects
+		/// \param container the wait container to receive the references to the objects
+		/// \param callStack CallStack() object used to select waitable objects
+		/// \details GetWaitObjects is usually called in one of two ways. First, it can
+		///  be called like <tt>something.GetWaitObjects(c, CallStack("my func after X", 0));</tt>.
+		///  Second, if in an outer GetWaitObjects() method that itself takes a callStack
+		///  parameter, it can be called like
+		///  <tt>innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));</tt>.
+		void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
+	//@} // WAITING
+
+	///	\name SIGNALS
+	//@{
+
+		/// \brief Initialize or reinitialize this object, without signal propagation
+		/// \param parameters a set of NameValuePairs to initialize this object
+		/// \throw NotImplemented
+		/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
+		///  number of arbitrarily typed arguments. The function avoids the need for multiple constructors providing
+		///  all possible combintations of configurable parameters.
+		/// \details IsolatedInitialize() does not call Initialize() on attached transformations. If initialization
+		///  should be propagated, then use the Initialize() function.
+		/// \details If a derived class does not override IsolatedInitialize(), then the base class throws
+		///  NotImplemented.
+		virtual void IsolatedInitialize(const NameValuePairs &parameters) {
+			CRYPTOPP_UNUSED(parameters);
+			throw NotImplemented("BufferedTransformation: this object can't be reinitialized");
+		}
+
+		/// \brief Flushes data buffered by this object, without signal propagation
+		/// \param hardFlush indicates whether all data should be flushed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return true if the flush was successful, false otherwise
+		/// \note hardFlush must be used with care
+		virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0;
+
+		/// \brief Marks the end of a series of messages, without signal propagation
+		/// \param blocking specifies whether the object should block when completing the processing on
+		///  the current series of messages
+		/// \return true if the message was successful, false otherwise
+		virtual bool IsolatedMessageSeriesEnd(bool blocking)
+			{CRYPTOPP_UNUSED(blocking); return false;}
+
+		/// \brief Initialize or reinitialize this object, with signal propagation
+		/// \param parameters a set of NameValuePairs to initialize or reinitialize this object
+		/// \param propagation the number of attached transformations the Initialize() signal should be passed
+		/// \details Initialize() is used to initialize or reinitialize an object using a variable number of
+		///  arbitrarily typed arguments. The function avoids the need for multiple constructors providing
+		///  all possible combintations of configurable parameters.
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		virtual void Initialize(const NameValuePairs &parameters=g_nullNameValuePairs, int propagation=-1);
+
+		/// \brief Flush buffered input and/or output, with signal propagation
+		/// \param hardFlush is used to indicate whether all data should be flushed
+		/// \param propagation the number of attached transformations the Flush()
+		///  signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return true if the flush was successful, false otherwise
+		/// \details propagation count includes this object. Setting propagation to
+		///  <tt>1</tt> means this object only. Setting propagation to <tt>-1</tt>
+		///  means unlimited propagation.
+		/// \note Hard flushes must be used with care. It means try to process and
+		///  output everything, even if there may not be enough data to complete the
+		///  action. For example, hard flushing a HexDecoder would cause an error if
+		///  you do it after inputing an odd number of hex encoded characters.
+		/// \note For some types of filters, like  ZlibDecompressor, hard flushes can
+		///  only be done at "synchronization points". These synchronization points
+		///  are positions in the data stream that are created by hard flushes on the
+		///  corresponding reverse filters, in this example ZlibCompressor. This is
+		///  useful when zlib compressed data is moved across a network in packets
+		///  and compression state is preserved across packets, as in the SSH2 protocol.
+		virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true);
+
+		/// \brief Marks the end of a series of messages, with signal propagation
+		/// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return true if the message was successful, false otherwise
+		/// \details Each object that receives the signal will perform its processing, decrement
+		///  propagation, and then pass the signal on to attached transformations if the value is not 0.
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
+		virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true);
+
+		/// \brief Set propagation of automatically generated and transferred signals
+		/// \param propagation then new value
+		/// \details Setting propagation to <tt>0</tt> means do not automatically generate signals. Setting
+		///  propagation to <tt>-1</tt> means unlimited propagation.
+		virtual void SetAutoSignalPropagation(int propagation)
+			{CRYPTOPP_UNUSED(propagation);}
+
+		/// \brief Retrieve automatic signal propagation value
+		/// \return the number of attached transformations the signal is propagated to. 0 indicates
+		///  the signal is only witnessed by this object
+		virtual int GetAutoSignalPropagation() const {return 0;}
+public:
+
+	///	\name RETRIEVAL OF ONE MESSAGE
+	//@{
+
+		/// \brief Provides the number of bytes ready for retrieval
+		/// \return the number of bytes ready for retrieval
+		/// \details The number of bytes available are dependent on the source. If an exact value is
+		///  available, then the exact value is returned. The exact value can include 0 if the source
+		///  is exhausted.
+		/// \details Some stream-based sources do not allow seeking() on the underlying stream, such
+		///  as some FileSource(). If the stream does not allow seeking() then MaxRetrievable()
+		///  returns LWORD_MAX to indicate there are still bytes to be retrieved.
+		virtual lword MaxRetrievable() const;
+
+		/// \brief Determines whether bytes are ready for retrieval
+		/// \return true if bytes are available for retrieval, false otherwise
+		virtual bool AnyRetrievable() const;
+
+		/// \brief Retrieve a 8-bit byte
+		/// \param outByte the 8-bit value to be retrieved
+		/// \return the number of bytes consumed during the call.
+		/// \details Use the return value of Get to detect short reads.
+		virtual size_t Get(byte &outByte);
+
+		/// \brief Retrieve a block of bytes
+		/// \param outString a block of bytes
+		/// \param getMax the number of bytes to Get
+		/// \return the number of bytes consumed during the call.
+		/// \details Use the return value of Get to detect short reads.
+		virtual size_t Get(byte *outString, size_t getMax);
+
+		/// \brief Peek a 8-bit byte
+		/// \param outByte the 8-bit value to be retrieved
+		/// \return the number of bytes read during the call.
+		/// \details Peek does not remove bytes from the object. Use the return value of
+		///  Get() to detect short reads.
+		virtual size_t Peek(byte &outByte) const;
+
+		/// \brief Peek a block of bytes
+		/// \param outString a block of bytes
+		/// \param peekMax the number of bytes to Peek
+		/// \return the number of bytes read during the call.
+		/// \details Peek does not remove bytes from the object. Use the return value of
+		///  Peek() to detect short reads.
+		virtual size_t Peek(byte *outString, size_t peekMax) const;
+
+		/// \brief Retrieve a 16-bit word
+		/// \param value the 16-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Use the return value of GetWord16() to detect short reads.
+		size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER);
+
+		/// \brief Retrieve a 32-bit word
+		/// \param value the 32-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Use the return value of GetWord32() to detect short reads.
+		size_t GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER);
+
+		/// \brief Retrieve a 64-bit word
+		/// \param value the 64-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Use the return value of GetWord64() to detect short reads.
+		/// \since Crypto++ 8.3
+		size_t GetWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER);
+
+		/// \brief Peek a 16-bit word
+		/// \param value the 16-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Peek does not consume bytes in the stream. Use the return value
+		///  of PeekWord16() to detect short reads.
+		size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const;
+
+		/// \brief Peek a 32-bit word
+		/// \param value the 32-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Peek does not consume bytes in the stream. Use the return value
+		///  of PeekWord32() to detect short reads.
+		size_t PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER) const;
+
+		/// \brief Peek a 64-bit word
+		/// \param value the 64-bit value to be retrieved
+		/// \param order the ByteOrder of the value to be processed.
+		/// \return the number of bytes consumed during the call.
+		/// \details Peek does not consume bytes in the stream. Use the return value
+		///  of PeekWord64() to detect short reads.
+		/// \since Crypto++ 8.3
+		size_t PeekWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER) const;
+
+		/// move transferMax bytes of the buffered output to target as input
+
+		/// \brief Transfer bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param transferMax the number of bytes to transfer
+		/// \param channel the channel on which the transfer should occur
+		/// \return the number of bytes transferred during the call.
+		/// \details TransferTo removes bytes from this object and moves them to the destination.
+		/// \details The function always returns transferMax. If an accurate count is needed, then use TransferTo2().
+		lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL)
+			{TransferTo2(target, transferMax, channel); return transferMax;}
+
+		/// \brief Discard skipMax bytes from the output buffer
+		/// \param skipMax the number of bytes to discard
+		/// \details Skip() discards bytes from the output buffer, which is the AttachedTransformation(), if present.
+		///  The function always returns the parameter <tt>skipMax</tt>.
+		/// \details If you want to skip bytes from a Source, then perform the following.
+		/// <pre>  StringSource ss(str, false, new Redirector(TheBitBucket()));
+		///   ss.Pump(10);    // Skip 10 bytes from Source
+		///   ss.Detach(new FilterChain(...));
+		///   ss.PumpAll();
+		/// </pre>
+		virtual lword Skip(lword skipMax=LWORD_MAX);
+
+		/// \brief Copy bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param copyMax the number of bytes to copy
+		/// \param channel the channel on which the transfer should occur
+		/// \return the number of bytes copied during the call.
+		/// \details CopyTo copies bytes from this object to the destination. The bytes are not removed from this object.
+		/// \details The function always returns copyMax. If an accurate count is needed, then use CopyRangeTo2().
+		lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const
+			{return CopyRangeTo(target, 0, copyMax, channel);}
+
+		/// \brief Copy bytes from this object using an index to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param position the 0-based index of the byte stream to begin the copying
+		/// \param copyMax the number of bytes to copy
+		/// \param channel the channel on which the transfer should occur
+		/// \return the number of bytes copied during the call.
+		/// \details CopyTo copies bytes from this object to the destination. The bytes remain in this
+		///  object. Copying begins at the index position in the current stream, and not from an absolute
+		///  position in the stream.
+		/// \details The function returns the new position in the stream after transferring the bytes starting at the index.
+		lword CopyRangeTo(BufferedTransformation &target, lword position, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const
+			{lword i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;}
+	//@}
+
+	///	\name RETRIEVAL OF MULTIPLE MESSAGES
+	//@{
+
+		/// \brief Provides the number of bytes ready for retrieval
+		/// \return the number of bytes ready for retrieval
+		virtual lword TotalBytesRetrievable() const;
+
+		/// \brief Provides the number of meesages processed by this object
+		/// \return the number of meesages processed by this object
+		/// \details NumberOfMessages returns number of times MessageEnd() has been
+		///  received minus messages retrieved or skipped
+		virtual unsigned int NumberOfMessages() const;
+
+		/// \brief Determines if any messages are available for retrieval
+		/// \return true if <tt>NumberOfMessages() &gt; 0</tt>, false otherwise
+		/// \details AnyMessages returns true if <tt>NumberOfMessages() &gt; 0</tt>
+		virtual bool AnyMessages() const;
+
+		/// \brief Start retrieving the next message
+		/// \return true if a message is ready for retrieval
+		/// \details GetNextMessage() returns true if a message is ready for retrieval; false
+		///  if no more messages exist or this message is not completely retrieved.
+		virtual bool GetNextMessage();
+
+		/// \brief Skip a number of meessages
+		/// \param count number of messages to skip
+		/// \return 0 if the requested number of messages was skipped, non-0 otherwise
+		/// \details SkipMessages() skips count number of messages. If there is an AttachedTransformation()
+		///  then SkipMessages() is called on the attached transformation. If there is no attached
+		///  transformation, then count number of messages are sent to TheBitBucket() using TransferMessagesTo().
+		virtual unsigned int SkipMessages(unsigned int count=UINT_MAX);
+
+		/// \brief Transfer messages from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param count the number of messages to transfer
+		/// \param channel the channel on which the transfer should occur
+		/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
+		/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
+		///  If all bytes are not transferred for a message, then processing stops and the number of remaining
+		///  bytes is returned. TransferMessagesTo() does not proceed to the next message.
+		/// \details A return value of 0 indicates all messages were successfully transferred.
+		unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL)
+			{TransferMessagesTo2(target, count, channel); return count;}
+
+		/// \brief Copy messages from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param count the number of messages to copy
+		/// \param channel the channel on which the copy should occur
+		/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
+		/// \details CopyMessagesTo copies messages from this object to the destination.
+		///  If all bytes are not transferred for a message, then processing stops and the number of remaining
+		///  bytes is returned. CopyMessagesTo() does not proceed to the next message.
+		/// \details A return value of 0 indicates all messages were successfully copied.
+		unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const;
+
+		/// \brief Skip all messages in the series
+		virtual void SkipAll();
+
+		/// \brief Transfer all bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param channel the channel on which the transfer should occur
+		/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
+		///  Internally TransferAllTo() calls TransferAllTo2().
+		void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL)
+			{TransferAllTo2(target, channel);}
+
+		/// \brief Copy messages from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param channel the channel on which the transfer should occur
+		/// \details CopyAllTo copies messages from this object and copies them to the destination.
+		void CopyAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const;
+
+		/// \brief Retrieve the next message in a series
+		/// \return true if a message was retrieved, false otherwise
+		/// \details Internally, the base class implementation returns false.
+		virtual bool GetNextMessageSeries() {return false;}
+		/// \brief Provides the number of messages in a series
+		/// \return the number of messages in this series
+		virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();}
+		/// \brief Provides the number of messages in a series
+		/// \return the number of messages in this series
+		virtual unsigned int NumberOfMessageSeries() const {return 0;}
+	//@}
+
+	///	\name NON-BLOCKING TRANSFER OF OUTPUT
+	//@{
+
+		// upon return, byteCount contains number of bytes that have finished being transferred,
+		// and returns the number of bytes left in the current transfer block
+
+		/// \brief Transfer bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param byteCount the number of bytes to transfer
+		/// \param channel the channel on which the transfer should occur
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain in the transfer block (i.e., bytes not transferred)
+		/// \details TransferTo2() removes bytes from this object and moves them to the destination.
+		///  Transfer begins at the index position in the current stream, and not from an absolute
+		///  position in the stream.
+		/// \details byteCount is an \a IN and \a OUT parameter. When the call is made,
+		///  byteCount is the requested size of the transfer. When the call returns, byteCount is
+		///  the number of bytes that were transferred.
+		virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) =0;
+
+		// upon return, begin contains the start position of data yet to be finished copying,
+		// and returns the number of bytes left in the current transfer block
+
+		/// \brief Copy bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param begin the 0-based index of the first byte to copy in the stream
+		/// \param end the 0-based index of the last byte to copy in the stream
+		/// \param channel the channel on which the transfer should occur
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain in the copy block (i.e., bytes not copied)
+		/// \details CopyRangeTo2 copies bytes from this object to the destination. The bytes are not
+		///  removed from this object. Copying begins at the index position in the current stream, and
+		///  not from an absolute position in the stream.
+		/// \details begin is an \a IN and \a OUT parameter. When the call is made, begin is the
+		///  starting position of the copy. When the call returns, begin is the position of the first
+		///  byte that was \a not copied (which may be different than end). begin can be used for
+		///  subsequent calls to CopyRangeTo2().
+		virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0;
+
+		// upon return, messageCount contains number of messages that have finished being transferred,
+		// and returns the number of bytes left in the current transfer block
+
+		/// \brief Transfer messages from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param messageCount the number of messages to transfer
+		/// \param channel the channel on which the transfer should occur
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
+		/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
+		/// \details messageCount is an \a IN and \a OUT parameter. When the call is made, messageCount is the
+		///  the number of messages requested to be transferred. When the call returns, messageCount is the
+		///  number of messages actually transferred.
+		size_t TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+
+		// returns the number of bytes left in the current transfer block
+
+		/// \brief Transfer all bytes from this object to another BufferedTransformation
+		/// \param target the destination BufferedTransformation
+		/// \param channel the channel on which the transfer should occur
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
+		/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
+		size_t TransferAllTo2(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	//@}
+
+	///	\name CHANNELS
+	//@{
+		/// \brief Exception thrown when a filter does not support named channels
+		struct NoChannelSupport : public NotImplemented
+			{NoChannelSupport(const std::string &name) : NotImplemented(name + ": this object doesn't support multiple channels") {}};
+		/// \brief Exception thrown when a filter does not recognize a named channel
+		struct InvalidChannelName : public InvalidArgument
+			{InvalidChannelName(const std::string &name, const std::string &channel) : InvalidArgument(name + ": unexpected channel name \"" + channel + "\"") {}};
+
+		/// \brief Input a byte for processing on a channel
+		/// \param channel the channel to process the data.
+		/// \param inByte the 8-bit byte (octet) to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true)
+			{return ChannelPut(channel, &inByte, 1, blocking);}
+
+		/// \brief Input a byte buffer for processing on a channel
+		/// \param channel the channel to process the data
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPut(const std::string &channel, const byte *inString, size_t length, bool blocking=true)
+			{return ChannelPut2(channel, inString, length, 0, blocking);}
+
+		/// \brief Input multiple bytes that may be modified by callee on a channel
+		/// \param channel the channel to process the data.
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPutModifiable(const std::string &channel, byte *inString, size_t length, bool blocking=true)
+			{return ChannelPutModifiable2(channel, inString, length, 0, blocking);}
+
+		/// \brief Input a 16-bit word for processing on a channel.
+		/// \param channel the channel to process the data.
+		/// \param value the 16-bit value to be processed.
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// \brief Input a 32-bit word for processing on a channel.
+		/// \param channel the channel to process the data.
+		/// \param value the 32-bit value to be processed.
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// \brief Input a 64-bit word for processing on a channel.
+		/// \param channel the channel to process the data.
+		/// \param value the 64-bit value to be processed.
+		/// \param order the ByteOrder of the value to be processed.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		size_t ChannelPutWord64(const std::string &channel, word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
+
+		/// \brief Signal the end of a message
+		/// \param channel the channel to process the data.
+		/// \param propagation the number of attached transformations the ChannelMessageEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
+		///  number of bytes that were not processed.
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true)
+			{return !!ChannelPut2(channel, NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);}
+
+		/// \brief Input multiple bytes for processing and signal the end of a message
+		/// \param channel the channel to process the data.
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param propagation the number of attached transformations the ChannelPutMessageEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		size_t ChannelPutMessageEnd(const std::string &channel, const byte *inString, size_t length, int propagation=-1, bool blocking=true)
+			{return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);}
+
+		/// \brief Request space which can be written into by the caller
+		/// \param channel the channel to process the data
+		/// \param size the requested size of the buffer
+		/// \return a pointer to a memory block with length size
+		/// \details The purpose of this method is to help avoid extra memory allocations.
+		/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
+		///  size is the requested size of the buffer. When the call returns, size is the size of
+		///  the array returned to the caller.
+		/// \details The base class implementation sets size to 0 and returns NULL.
+		/// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of
+		///  an ArraySink(), the pointer to the array is returned and the size is remaining size.
+		virtual byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
+
+		/// \brief Input multiple bytes for processing on a channel.
+		/// \param channel the channel to process the data.
+		/// \param inString the byte buffer to process.
+		/// \param length the size of the string, in bytes.
+		/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
+		/// \param blocking specifies whether the object should block when processing input.
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
+		virtual size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking);
+
+		/// \brief Input multiple bytes that may be modified by callee on a channel
+		/// \param channel the channel to process the data
+		/// \param inString the byte buffer to process
+		/// \param length the size of the string, in bytes
+		/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
+		virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking);
+
+		/// \brief Flush buffered input and/or output on a channel
+		/// \param channel the channel to flush the data
+		/// \param hardFlush is used to indicate whether all data should be flushed
+		/// \param propagation the number of attached transformations the ChannelFlush() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return true of the Flush was successful
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true);
+
+		/// \brief Marks the end of a series of messages on a channel
+		/// \param channel the channel to signal the end of a series of messages
+		/// \param propagation the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed
+		/// \param blocking specifies whether the object should block when processing input
+		/// \return true if the message was successful, false otherwise
+		/// \details Each object that receives the signal will perform its processing, decrement
+		///  propagation, and then pass the signal on to attached transformations if the value is not 0.
+		/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
+		///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+		/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
+		virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true);
+
+		/// \brief Sets the default retrieval channel
+		/// \param channel the channel to signal the end of a series of messages
+		/// \note this function may not be implemented in all objects that should support it.
+		virtual void SetRetrievalChannel(const std::string &channel);
+	//@}
+
+	///	\name ATTACHMENT
+	/// \details Some BufferedTransformation objects (e.g. Filter objects) allow other BufferedTransformation objects to be
+	///  attached. When this is done, the first object instead of buffering its output, sends that output to the attached
+	///  object as input. The entire attachment chain is deleted when the anchor object is destructed.
+
+	//@{
+		/// \brief Determines whether the object allows attachment
+		/// \return true if the object allows an attachment, false otherwise
+		/// \details Sources and Filters will returns true, while Sinks and other objects will return false.
+		virtual bool Attachable() {return false;}
+
+		/// \brief Returns the object immediately attached to this object
+		/// \return the attached transformation
+		/// \details AttachedTransformation() returns NULL if there is no attachment. The non-const
+		///  version of AttachedTransformation() always returns NULL.
+		virtual BufferedTransformation *AttachedTransformation() {CRYPTOPP_ASSERT(!Attachable()); return NULLPTR;}
+
+		/// \brief Returns the object immediately attached to this object
+		/// \return the attached transformation
+		/// \details AttachedTransformation() returns NULL if there is no attachment. The non-const
+		///  version of AttachedTransformation() always returns NULL.
+		virtual const BufferedTransformation *AttachedTransformation() const
+			{return const_cast<BufferedTransformation *>(this)->AttachedTransformation();}
+
+		/// \brief Delete the current attachment chain and attach a new one
+		/// \param newAttachment the new BufferedTransformation to attach
+		/// \throw NotImplemented
+		/// \details Detach() deletes the current attachment chain and replace it with an optional newAttachment
+		/// \details If a derived class does not override Detach(), then the base class throws
+		///  NotImplemented.
+		virtual void Detach(BufferedTransformation *newAttachment = NULLPTR) {
+			CRYPTOPP_UNUSED(newAttachment); CRYPTOPP_ASSERT(!Attachable());
+			throw NotImplemented("BufferedTransformation: this object is not attachable");
+		}
+
+		/// \brief Add newAttachment to the end of attachment chain
+		/// \param newAttachment the attachment to add to the end of the chain
+		virtual void Attach(BufferedTransformation *newAttachment);
+	//@}
+
+protected:
+	/// \brief Decrements the propagation count while clamping at 0
+	/// \return the decremented propagation or 0
+	static int DecrementPropagation(int propagation)
+		{return propagation != 0 ? propagation - 1 : 0;}
+
+private:
+	// for ChannelPutWord16, ChannelPutWord32 and ChannelPutWord64,
+	// to ensure the buffer isn't deallocated before non-blocking
+	// operation completes
+	byte m_buf[8];
+};
+
+/// \brief An input discarding BufferedTransformation
+/// \return a reference to a BufferedTransformation object that discards all input
+CRYPTOPP_DLL BufferedTransformation & TheBitBucket();
+
+/// \brief Interface for crypto material
+/// \details CryptoMaterial() is an interface for crypto material, such as
+///  public keys, private keys and crypto parameters. Derived classes generally
+///  do not offer public methods such as GenerateRandom() and
+///  GenerateRandomWithKeySize().
+/// \sa GeneratableCryptoMaterial()
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoMaterial : public NameValuePairs
+{
+public:
+	/// Exception thrown when invalid crypto material is detected
+	class CRYPTOPP_DLL InvalidMaterial : public InvalidDataFormat
+	{
+	public:
+		explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {}
+	};
+
+	virtual ~CryptoMaterial() {}
+
+	/// \brief Assign values to this object
+	/// \details This function can be used to create a public key from a private key.
+	virtual void AssignFrom(const NameValuePairs &source) =0;
+
+	/// \brief Check this object for errors
+	/// \param rng a RandomNumberGenerator for objects which use randomized testing
+	/// \param level the level of thoroughness
+	/// \return true if the tests succeed, false otherwise
+	/// \details There are four levels of thoroughness:
+	///   <ul>
+	///   <li>0 - using this object won't cause a crash or exception
+	///   <li>1 - this object will probably function, and encrypt, sign, other operations correctly
+	///   <li>2 - ensure this object will function correctly, and perform reasonable security checks
+	///   <li>3 - perform reasonable security checks, and do checks that may take a long time
+	///   </ul>
+	/// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0.
+	///  Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended.
+	/// \sa ThrowIfInvalid()
+	virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0;
+
+	/// \brief Check this object for errors
+	/// \param rng a RandomNumberGenerator for objects which use randomized testing
+	/// \param level the level of thoroughness
+	/// \throw InvalidMaterial
+	/// \details Internally, ThrowIfInvalid() calls Validate() and throws InvalidMaterial() if validation fails.
+	/// \sa Validate()
+	virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const
+		{if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");}
+
+	/// \brief Saves a key to a BufferedTransformation
+	/// \param bt the destination BufferedTransformation
+	/// \throw NotImplemented
+	/// \details Save() writes the material to a BufferedTransformation.
+	/// \details If the material is a key, then the key is written with ASN.1 DER encoding. The key
+	///  includes an object identifier with an algorithm id, like a subjectPublicKeyInfo.
+	/// \details A "raw" key without the "key info" can be saved using a key's DEREncode() method.
+	/// \details If a derived class does not override Save(), then the base class throws
+	///  NotImplemented().
+	virtual void Save(BufferedTransformation &bt) const
+		{CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support saving");}
+
+	/// \brief Loads a key from a BufferedTransformation
+	/// \param bt the source BufferedTransformation
+	/// \throw KeyingErr
+	/// \details Load() attempts to read material from a BufferedTransformation. If the
+	///  material is a key that was generated outside the library, then the following
+	///  usually applies:
+	///   <ul>
+	///   <li>the key should be ASN.1 BER encoded
+	///   <li>the key should be a "key info"
+	///   </ul>
+	/// \details "key info" means the key should have an object identifier with an algorithm id,
+	///  like a subjectPublicKeyInfo.
+	/// \details To read a "raw" key without the "key info", then call the key's BERDecode() method.
+	/// \note Load() generally does not check that the key is valid. Call Validate(), if needed.
+	virtual void Load(BufferedTransformation &bt)
+		{CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support loading");}
+
+	/// \brief Determines whether the object supports precomputation
+	/// \return true if the object supports precomputation, false otherwise
+	/// \sa Precompute()
+	virtual bool SupportsPrecomputation() const {return false;}
+
+	/// \brief Perform precomputation
+	/// \param precomputationStorage the suggested number of objects for the precompute table
+	/// \throw NotImplemented
+	/// \details The exact semantics of Precompute() varies, but it typically means calculate
+	///  a table of n objects that can be used later to speed up computation.
+	/// \details If a derived class does not override Precompute(), then the base class throws
+	///  NotImplemented.
+	/// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation()
+	virtual void Precompute(unsigned int precomputationStorage) {
+		CRYPTOPP_UNUSED(precomputationStorage); CRYPTOPP_ASSERT(!SupportsPrecomputation());
+		throw NotImplemented("CryptoMaterial: this object does not support precomputation");
+	}
+
+	/// \brief Retrieve previously saved precomputation
+	/// \param storedPrecomputation BufferedTransformation with the saved precomputation
+	/// \throw NotImplemented
+	/// \sa SupportsPrecomputation(), Precompute()
+	virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation)
+		{CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");}
+
+	/// \brief Save precomputation for later use
+	/// \param storedPrecomputation BufferedTransformation to write the precomputation
+	/// \throw NotImplemented
+	/// \sa SupportsPrecomputation(), Precompute()
+	virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const
+		{CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");}
+
+	/// \brief Perform a quick sanity check
+	/// \details DoQuickSanityCheck() is for internal library use, and it should not be called by library users.
+	void DoQuickSanityCheck() const	{ThrowIfInvalid(NullRNG(), 0);}
+
+#if defined(__SUNPRO_CC)
+	// Sun Studio 11/CC 5.8 workaround: it generates incorrect code
+	// when casting to an empty virtual base class. JW, 2018: It is
+	// still a problem in Sun Studio 12.6/CC 5.15 on i386. Just enable
+	// it everywhere in case it affects SPARC (which we don't test).
+	char m_sunCCworkaround;
+#endif
+};
+
+/// \brief Interface for crypto material
+/// \details GeneratableCryptoMaterial() is an interface for crypto material,
+///  such as private keys and crypto parameters. Derived classes offer public
+///  methods such as GenerateRandom() and GenerateRandomWithKeySize().
+/// \sa CryptoMaterial()
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GeneratableCryptoMaterial : virtual public CryptoMaterial
+{
+public:
+	virtual ~GeneratableCryptoMaterial() {}
+
+	/// \brief Generate a random key or crypto parameters
+	/// \param rng a RandomNumberGenerator to produce keying material
+	/// \param params additional initialization parameters
+	/// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid
+	/// \details If a derived class does not override GenerateRandom(), then the base class throws
+	///  NotImplemented.
+	virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &params = g_nullNameValuePairs) {
+		CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(params);
+		throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation");
+	}
+
+	/// \brief Generate a random key or crypto parameters
+	/// \param rng a RandomNumberGenerator to produce keying material
+	/// \param keySize the size of the key, in bits
+	/// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid
+	/// \details GenerateRandomWithKeySize calls GenerateRandom() with a NameValuePairs
+	///  object with only "KeySize"
+	void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize);
+};
+
+/// \brief Interface for public keys
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKey : virtual public CryptoMaterial
+{
+};
+
+/// \brief Interface for private keys
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKey : public GeneratableCryptoMaterial
+{
+};
+
+/// \brief Interface for crypto parameters
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoParameters : public GeneratableCryptoMaterial
+{
+};
+
+/// \brief Interface for certificates
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Certificate : virtual public CryptoMaterial
+{
+};
+
+/// \brief Interface for asymmetric algorithms
+/// \details BERDecode() and DEREncode() were removed under Issue 569
+///  and Commit 9b174e84de7a. Programs should use <tt>AccessMaterial().Load(bt)</tt>
+///  or <tt>GetMaterial().Save(bt)</tt> instead.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/569">Issue 569</A>
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AsymmetricAlgorithm : public Algorithm
+{
+public:
+	virtual ~AsymmetricAlgorithm() {}
+
+	/// \brief Retrieves a reference to CryptoMaterial
+	/// \return a reference to the crypto material
+	virtual CryptoMaterial & AccessMaterial() =0;
+
+	/// \brief Retrieves a reference to CryptoMaterial
+	/// \return a const reference to the crypto material
+	virtual const CryptoMaterial & GetMaterial() const =0;
+
+#if 0
+	/// \brief Loads this object from a BufferedTransformation
+	/// \param bt a BufferedTransformation object
+	/// \details Use of BERDecode() changed to Load() at Issue 569.
+	/// \deprecated for backwards compatibility, calls <tt>AccessMaterial().Load(bt)</tt>
+	void BERDecode(BufferedTransformation &bt)
+		{AccessMaterial().Load(bt);}
+
+	/// \brief Saves this object to a BufferedTransformation
+	/// \param bt a BufferedTransformation object
+	/// \details Use of DEREncode() changed to Save() at Issue 569.
+	/// \deprecated for backwards compatibility, calls GetMaterial().Save(bt)
+	void DEREncode(BufferedTransformation &bt) const
+		{GetMaterial().Save(bt);}
+#endif
+};
+
+/// \brief Interface for asymmetric algorithms using public keys
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKeyAlgorithm : public AsymmetricAlgorithm
+{
+public:
+	virtual ~PublicKeyAlgorithm() {}
+
+	// VC60 workaround: no co-variant return type
+
+	/// \brief Retrieves a reference to a Public Key
+	/// \return a reference to the public key
+	CryptoMaterial & AccessMaterial()
+		{return AccessPublicKey();}
+	/// \brief Retrieves a reference to a Public Key
+	/// \return a const reference the public key
+	const CryptoMaterial & GetMaterial() const
+		{return GetPublicKey();}
+
+	/// \brief Retrieves a reference to a Public Key
+	/// \return a reference to the public key
+	virtual PublicKey & AccessPublicKey() =0;
+	/// \brief Retrieves a reference to a Public Key
+	/// \return a const reference the public key
+	virtual const PublicKey & GetPublicKey() const
+		{return const_cast<PublicKeyAlgorithm *>(this)->AccessPublicKey();}
+};
+
+/// \brief Interface for asymmetric algorithms using private keys
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKeyAlgorithm : public AsymmetricAlgorithm
+{
+public:
+	virtual ~PrivateKeyAlgorithm() {}
+
+	/// \brief Retrieves a reference to a Private Key
+	/// \return a reference the private key
+	CryptoMaterial & AccessMaterial() {return AccessPrivateKey();}
+	/// \brief Retrieves a reference to a Private Key
+	/// \return a const reference the private key
+	const CryptoMaterial & GetMaterial() const {return GetPrivateKey();}
+
+	/// \brief Retrieves a reference to a Private Key
+	/// \return a reference the private key
+	virtual PrivateKey & AccessPrivateKey() =0;
+	/// \brief Retrieves a reference to a Private Key
+	/// \return a const reference the private key
+	virtual const PrivateKey & GetPrivateKey() const {return const_cast<PrivateKeyAlgorithm *>(this)->AccessPrivateKey();}
+};
+
+/// \brief Interface for key agreement algorithms
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyAgreementAlgorithm : public AsymmetricAlgorithm
+{
+public:
+	virtual ~KeyAgreementAlgorithm() {}
+
+	/// \brief Retrieves a reference to Crypto Parameters
+	/// \return a reference the crypto parameters
+	CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();}
+	/// \brief Retrieves a reference to Crypto Parameters
+	/// \return a const reference the crypto parameters
+	const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();}
+
+	/// \brief Retrieves a reference to Crypto Parameters
+	/// \return a reference the crypto parameters
+	virtual CryptoParameters & AccessCryptoParameters() =0;
+	/// \brief Retrieves a reference to Crypto Parameters
+	/// \return a const reference the crypto parameters
+	virtual const CryptoParameters & GetCryptoParameters() const {return const_cast<KeyAgreementAlgorithm *>(this)->AccessCryptoParameters();}
+};
+
+/// \brief Interface for public-key encryptors and decryptors
+/// \details This class provides an interface common to encryptors and decryptors
+///  for querying their plaintext and ciphertext lengths.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_CryptoSystem
+{
+public:
+	virtual ~PK_CryptoSystem() {}
+
+	/// \brief Provides the maximum length of plaintext for a given ciphertext length
+	/// \return the maximum size of the plaintext, in bytes
+	/// \details This function returns 0 if ciphertextLength is not valid (too long or too short).
+	virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0;
+
+	/// \brief Calculate the length of ciphertext given length of plaintext
+	/// \return the maximum size of the ciphertext, in bytes
+	/// \details This function returns 0 if plaintextLength is not valid (too long).
+	virtual size_t CiphertextLength(size_t plaintextLength) const =0;
+
+	/// \brief Determines whether this object supports the use of a named parameter
+	/// \param name the name of the parameter
+	/// \return true if the parameter name is supported, false otherwise
+	/// \details Some possible parameter names: EncodingParameters(), KeyDerivationParameters()
+	///  and others Parameters listed in argnames.h
+	virtual bool ParameterSupported(const char *name) const =0;
+
+	/// \brief Provides the fixed ciphertext length, if one exists
+	/// \return the fixed ciphertext length if one exists, otherwise 0
+	/// \details "Fixed" here means length of ciphertext does not depend on length of plaintext.
+	///  In this case, it usually does depend on the key length.
+	virtual size_t FixedCiphertextLength() const {return 0;}
+
+	/// \brief Provides the maximum plaintext length given a fixed ciphertext length
+	/// \return maximum plaintext length given the fixed ciphertext length, if one exists,
+	///  otherwise return 0.
+	/// \details FixedMaxPlaintextLength(0 returns the maximum plaintext length given the fixed ciphertext
+	///  length, if one exists, otherwise return 0.
+	virtual size_t FixedMaxPlaintextLength() const {return 0;}
+};
+
+/// \brief Interface for public-key encryptors
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Encryptor : public PK_CryptoSystem, public PublicKeyAlgorithm
+{
+public:
+	/// \brief Exception thrown when trying to encrypt plaintext of invalid length
+	class CRYPTOPP_DLL InvalidPlaintextLength : public Exception
+	{
+	public:
+		InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {}
+	};
+
+	/// \brief Encrypt a byte string
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param plaintext the plaintext byte buffer
+	/// \param plaintextLength the size of the plaintext byte buffer
+	/// \param ciphertext a byte buffer to hold the encrypted string
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \pre <tt>CiphertextLength(plaintextLength) != 0</tt> ensures the plaintext isn't too large
+	/// \pre <tt>COUNTOF(ciphertext) == CiphertextLength(plaintextLength)</tt> ensures the output
+	///  byte buffer is large enough.
+	/// \sa PK_Decryptor
+	virtual void Encrypt(RandomNumberGenerator &rng,
+		const byte *plaintext, size_t plaintextLength,
+		byte *ciphertext, const NameValuePairs &parameters = g_nullNameValuePairs) const =0;
+
+	/// \brief Create a new encryption filter
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param attachment an attached transformation
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \details \p attachment can be \p NULL. The caller is responsible for deleting the returned pointer.
+	///  Encoding parameters should be passed in the "EP" channel.
+	virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng,
+		BufferedTransformation *attachment=NULLPTR, const NameValuePairs &parameters = g_nullNameValuePairs) const;
+};
+
+/// \brief Interface for public-key decryptors
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Decryptor : public PK_CryptoSystem, public PrivateKeyAlgorithm
+{
+public:
+	virtual ~PK_Decryptor() {}
+
+	/// \brief Decrypt a byte string
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param ciphertext the encrypted byte buffer
+	/// \param ciphertextLength the size of the encrypted byte buffer
+	/// \param plaintext a byte buffer to hold the decrypted string
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \return the result of the decryption operation
+	/// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength
+	///  is valid and holds the actual length of the plaintext recovered. The result is undefined
+	///  if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength
+	///  is undefined.
+	/// \pre <tt>COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength)</tt> ensures the output
+	///  byte buffer is large enough
+	/// \sa PK_Encryptor
+	virtual DecodingResult Decrypt(RandomNumberGenerator &rng,
+		const byte *ciphertext, size_t ciphertextLength,
+		byte *plaintext, const NameValuePairs &parameters = g_nullNameValuePairs) const =0;
+
+	/// \brief Create a new decryption filter
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param attachment an attached transformation
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \return the newly created decryption filter
+	/// \note the caller is responsible for deleting the returned pointer
+	virtual BufferedTransformation * CreateDecryptionFilter(RandomNumberGenerator &rng,
+		BufferedTransformation *attachment=NULLPTR, const NameValuePairs &parameters = g_nullNameValuePairs) const;
+
+	/// \brief Decrypt a fixed size ciphertext
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param ciphertext the encrypted byte buffer
+	/// \param plaintext a byte buffer to hold the decrypted string
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \return the result of the decryption operation
+	/// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength
+	///  is valid and holds the actual length of the plaintext recovered. The result is undefined
+	///  if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength
+	///  is undefined.
+	/// \pre <tt>COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength)</tt> ensures the output
+	///  byte buffer is large enough
+	/// \sa PK_Encryptor
+	DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *ciphertext, byte *plaintext, const NameValuePairs &parameters = g_nullNameValuePairs) const
+		{return Decrypt(rng, ciphertext, FixedCiphertextLength(), plaintext, parameters);}
+};
+
+/// \brief Interface for public-key signers and verifiers
+/// \details This class provides an interface common to signers and verifiers for querying scheme properties
+/// \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme
+{
+public:
+	/// \brief Exception throw when the private or public key has a length that can't be used
+	/// \details InvalidKeyLength() may be thrown by any function in this class if the private
+	///  or public key has a length that can't be used
+	class CRYPTOPP_DLL InvalidKeyLength : public Exception
+	{
+	public:
+		InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {}
+	};
+
+	/// \brief Exception throw when the private or public key is too short to sign or verify
+	/// \details KeyTooShort() may be thrown by any function in this class if the private or public
+	///  key is too short to sign or verify anything
+	class CRYPTOPP_DLL KeyTooShort : public InvalidKeyLength
+	{
+	public:
+		KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {}
+	};
+
+	virtual ~PK_SignatureScheme() {}
+
+	/// \brief Provides the signature length if it only depends on the key
+	/// \return the signature length if it only depends on the key, in bytes
+	/// \details SignatureLength() returns the signature length if it only depends on the key, otherwise 0.
+	virtual size_t SignatureLength() const =0;
+
+	/// \brief Provides the maximum signature length produced given the length of the recoverable message part
+	/// \param recoverablePartLength the length of the recoverable message part, in bytes
+	/// \return the maximum signature length produced for a given length of recoverable message part, in bytes
+	/// \details MaxSignatureLength() returns the maximum signature length produced given the length of the
+	///  recoverable message part.
+	virtual size_t MaxSignatureLength(size_t recoverablePartLength = 0) const
+		{CRYPTOPP_UNUSED(recoverablePartLength); return SignatureLength();}
+
+	/// \brief Provides the length of longest message that can be recovered
+	/// \return the length of longest message that can be recovered, in bytes
+	/// \details MaxRecoverableLength() returns the length of longest message that can be recovered, or 0 if
+	///  this signature scheme does not support message recovery.
+	virtual size_t MaxRecoverableLength() const =0;
+
+	/// \brief Provides the length of longest message that can be recovered from a signature of given length
+	/// \param signatureLength the length of the signature, in bytes
+	/// \return the length of longest message that can be recovered from a signature of given length, in bytes
+	/// \details MaxRecoverableLengthFromSignatureLength() returns the length of longest message that can be
+	///  recovered from a signature of given length, or 0 if this signature scheme does not support message
+	///  recovery.
+	virtual size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const =0;
+
+	/// \brief Determines whether a signature scheme requires a random number generator
+	/// \return true if the signature scheme requires a RandomNumberGenerator() to sign
+	/// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take
+	///  RandomNumberGenerator().
+	virtual bool IsProbabilistic() const =0;
+
+	/// \brief Determines whether the non-recoverable message part can be signed
+	/// \return true if the non-recoverable message part can be signed
+	virtual bool AllowNonrecoverablePart() const =0;
+
+	/// \brief Determines whether the signature must be input before the message
+	/// \return true if the signature must be input before the message during verifcation
+	/// \details if SignatureUpfront() returns true, then you must input the signature before the message
+	///  during verification. Otherwise you can input the signature at anytime.
+	virtual bool SignatureUpfront() const {return false;}
+
+	/// \brief Determines whether the recoverable part must be input before the non-recoverable part
+	/// \return true if the recoverable part must be input before the non-recoverable part during signing
+	/// \details RecoverablePartFirst() determines whether you must input the recoverable part before the
+	///  non-recoverable part during signing
+	virtual bool RecoverablePartFirst() const =0;
+};
+
+/// \brief Interface for accumulating messages to be signed or verified
+/// \details Only Update() should be called from the PK_MessageAccumulator() class. No other functions
+///  inherited from HashTransformation, like DigestSize() and TruncatedFinal(), should be called.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulator : public HashTransformation
+{
+public:
+	/// \warning DigestSize() should not be called on PK_MessageAccumulator
+	unsigned int DigestSize() const
+		{throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");}
+
+	/// \warning TruncatedFinal() should not be called on PK_MessageAccumulator
+	void TruncatedFinal(byte *digest, size_t digestSize)
+	{
+		CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(digestSize);
+		throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called");
+	}
+};
+
+/// \brief Interface for public-key signers
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Signer : public PK_SignatureScheme, public PrivateKeyAlgorithm
+{
+public:
+	virtual ~PK_Signer() {}
+
+	/// \brief Create a new HashTransformation to accumulate the message to be signed
+	/// \param rng a RandomNumberGenerator derived class
+	/// \return a pointer to a PK_MessageAccumulator
+	/// \details NewSignatureAccumulator() can be used with all signing methods. Sign() will automatically delete the
+	///  accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference.
+	virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const =0;
+
+	/// \brief Input a recoverable message to an accumulator
+	/// \param messageAccumulator a reference to a PK_MessageAccumulator
+	/// \param recoverableMessage a pointer to the recoverable message part to be signed
+	/// \param recoverableMessageLength the size of the recoverable message part
+	virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const =0;
+
+	/// \brief Sign and delete the messageAccumulator
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \param signature a block of bytes for the signature
+	/// \return actual signature length
+	/// \details Sign() deletes the messageAccumulator, even if an exception is thrown.
+	/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
+	virtual size_t Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const;
+
+	/// \brief Sign and restart messageAccumulator
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \param signature a block of bytes for the signature
+	/// \param restart flag indicating whether the messageAccumulator should be restarted
+	/// \return actual signature length
+	/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
+	virtual size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0;
+
+	/// \brief Sign a message
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param message a pointer to the message
+	/// \param messageLen the size of the message to be signed
+	/// \param signature a block of bytes for the signature
+	/// \return actual signature length
+	/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
+	virtual size_t SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const;
+
+	/// \brief Sign a recoverable message
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param recoverableMessage a pointer to the recoverable message part to be signed
+	/// \param recoverableMessageLength the size of the recoverable message part
+	/// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed
+	/// \param nonrecoverableMessageLength the size of the non-recoverable message part
+	/// \param signature a block of bytes for the signature
+	/// \return actual signature length
+	/// \pre <tt>COUNTOF(signature) == MaxSignatureLength(recoverableMessageLength)</tt>
+	virtual size_t SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength,
+		const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const;
+};
+
+/// \brief Interface for public-key signature verifiers
+/// \details The Recover* functions throw NotImplemented if the signature scheme does not support
+///  message recovery.
+/// \details The Verify* functions throw InvalidDataFormat if the scheme does support message
+///  recovery and the signature contains a non-empty recoverable message part. The
+///  Recover* functions should be used in that case.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Verifier : public PK_SignatureScheme, public PublicKeyAlgorithm
+{
+public:
+	virtual ~PK_Verifier() {}
+
+	/// \brief Create a new HashTransformation to accumulate the message to be verified
+	/// \return a pointer to a PK_MessageAccumulator
+	/// \details NewVerificationAccumulator() can be used with all verification methods. Verify() will automatically delete
+	///  the accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference.
+	virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0;
+
+	/// \brief Input signature into a message accumulator
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \param signature the signature on the message
+	/// \param signatureLength the size of the signature
+	virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const =0;
+
+	/// \brief Check whether messageAccumulator contains a valid signature and message
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \return true if the signature is valid, false otherwise
+	/// \details Verify() deletes the messageAccumulator, even if an exception is thrown.
+	virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const;
+
+	/// \brief Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator
+	/// \param messageAccumulator a reference to a PK_MessageAccumulator derived class
+	/// \return true if the signature is valid, false otherwise
+	/// \details VerifyAndRestart() restarts the messageAccumulator
+	virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0;
+
+	/// \brief Check whether input signature is a valid signature for input message
+	/// \param message a pointer to the message to be verified
+	/// \param messageLen the size of the message
+	/// \param signature a pointer to the signature over the message
+	/// \param signatureLen the size of the signature
+	/// \return true if the signature is valid, false otherwise
+	virtual bool VerifyMessage(const byte *message, size_t messageLen,
+		const byte *signature, size_t signatureLen) const;
+
+	/// \brief Recover a message from its signature
+	/// \param recoveredMessage a pointer to the recoverable message part to be verified
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \return the result of the verification operation
+	/// \details Recover() deletes the messageAccumulator, even if an exception is thrown.
+	/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
+	virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const;
+
+	/// \brief Recover a message from its signature
+	/// \param recoveredMessage a pointer to the recoverable message part to be verified
+	/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
+	/// \return the result of the verification operation
+	/// \details RecoverAndRestart() restarts the messageAccumulator
+	/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
+	virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0;
+
+	/// \brief Recover a message from its signature
+	/// \param recoveredMessage a pointer for the recovered message
+	/// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed
+	/// \param nonrecoverableMessageLength the size of the non-recoverable message part
+	/// \param signature the signature on the message
+	/// \param signatureLength the size of the signature
+	/// \return the result of the verification operation
+	/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
+	virtual DecodingResult RecoverMessage(byte *recoveredMessage,
+		const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength,
+		const byte *signature, size_t signatureLength) const;
+};
+
+/// \brief Interface for domains of simple key agreement protocols
+/// \details A key agreement domain is a set of parameters that must be shared
+///  by two parties in a key agreement protocol, along with the algorithms
+///  for generating key pairs and deriving agreed values.
+/// \since Crypto++ 3.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyAgreementDomain : public KeyAgreementAlgorithm
+{
+public:
+	virtual ~SimpleKeyAgreementDomain() {}
+
+	/// \brief Provides the size of the agreed value
+	/// \return size of agreed value produced in this domain
+	virtual unsigned int AgreedValueLength() const =0;
+
+	/// \brief Provides the size of the private key
+	/// \return size of private keys in this domain
+	virtual unsigned int PrivateKeyLength() const =0;
+
+	/// \brief Provides the size of the public key
+	/// \return size of public keys in this domain
+	virtual unsigned int PublicKeyLength() const =0;
+
+	/// \brief Generate private key in this domain
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
+	virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
+
+	/// \brief Generate a public key from a private key in this domain
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer with the previously generated private key
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
+	virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
+
+	/// \brief Generate a private/public key pair
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \details GenerateKeyPair() is equivalent to calling GeneratePrivateKey() and then GeneratePublicKey().
+	/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
+	/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
+	virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
+
+	/// \brief Derive agreed value
+	/// \param agreedValue a byte buffer for the shared secret
+	/// \param privateKey a byte buffer with your private key in this domain
+	/// \param otherPublicKey a byte buffer with the other party's public key in this domain
+	/// \param validateOtherPublicKey a flag indicating if the other party's public key should be validated
+	/// \return true upon success, false in case of failure
+	/// \details Agree() derives an agreed value from your private keys and couterparty's public keys.
+	/// \details The other party's public key is validated by default. If you have previously validated the
+	///  static public key, use <tt>validateStaticOtherPublicKey=false</tt> to save time.
+	/// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
+	/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
+	/// \pre <tt>COUNTOF(otherPublicKey) == PublicKeyLength()</tt>
+	virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0;
+};
+
+/// \brief Interface for domains of authenticated key agreement protocols
+/// \details In an authenticated key agreement protocol, each party has two
+///  key pairs. The long-lived key pair is called the static key pair,
+///  and the short-lived key pair is called the ephemeral key pair.
+/// \since Crypto++ 3.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm
+{
+public:
+	virtual ~AuthenticatedKeyAgreementDomain() {}
+
+	/// \brief Provides the size of the agreed value
+	/// \return size of agreed value produced in this domain
+	virtual unsigned int AgreedValueLength() const =0;
+
+	/// \brief Provides the size of the static private key
+	/// \return size of static private keys in this domain
+	virtual unsigned int StaticPrivateKeyLength() const =0;
+
+	/// \brief Provides the size of the static public key
+	/// \return size of static public keys in this domain
+	virtual unsigned int StaticPublicKeyLength() const =0;
+
+	/// \brief Generate static private key in this domain
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
+	virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
+
+	/// \brief Generate a static public key from a private key in this domain
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer with the previously generated private key
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
+	virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
+
+	/// \brief Generate a static private/public key pair
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \details GenerateStaticKeyPair() is equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey().
+	/// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
+	/// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
+	virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
+
+	/// \brief Provides the size of ephemeral private key
+	/// \return the size of ephemeral private key in this domain
+	virtual unsigned int EphemeralPrivateKeyLength() const =0;
+
+	/// \brief Provides the size of ephemeral public key
+	/// \return the size of ephemeral public key in this domain
+	virtual unsigned int EphemeralPublicKeyLength() const =0;
+
+	/// \brief Generate ephemeral private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \pre <tt>COUNTOF(privateKey) == PrivateEphemeralKeyLength()</tt>
+	virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
+
+	/// \brief Generate ephemeral public key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \pre <tt>COUNTOF(publicKey) == PublicEphemeralKeyLength()</tt>
+	virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
+
+	/// \brief Generate private/public key pair
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param privateKey a byte buffer for the generated private key in this domain
+	/// \param publicKey a byte buffer for the generated public key in this domain
+	/// \details GenerateEphemeralKeyPair() is equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey()
+	virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
+
+	/// \brief Derive agreed value
+	/// \param agreedValue a byte buffer for the shared secret
+	/// \param staticPrivateKey a byte buffer with your static private key in this domain
+	/// \param ephemeralPrivateKey a byte buffer with your ephemeral private key in this domain
+	/// \param staticOtherPublicKey a byte buffer with the other party's static public key in this domain
+	/// \param ephemeralOtherPublicKey a byte buffer with the other party's ephemeral public key in this domain
+	/// \param validateStaticOtherPublicKey a flag indicating if the other party's public key should be validated
+	/// \return true upon success, false in case of failure
+	/// \details Agree() derives an agreed value from your private keys and couterparty's public keys.
+	/// \details The other party's ephemeral public key is validated by default. If you have previously validated
+	///  the static public key, use <tt>validateStaticOtherPublicKey=false</tt> to save time.
+	/// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
+	/// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
+	/// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
+	/// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
+	/// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
+	virtual bool Agree(byte *agreedValue,
+		const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
+		const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
+		bool validateStaticOtherPublicKey=true) const =0;
+};
+
+// interface for password authenticated key agreement protocols, not implemented yet
+#if 0
+/// \brief Interface for protocol sessions
+/*! The methods should be called in the following order:
+
+	InitializeSession(rng, parameters);	// or call initialize method in derived class
+	while (true)
+	{
+		if (OutgoingMessageAvailable())
+		{
+			length = GetOutgoingMessageLength();
+			GetOutgoingMessage(message);
+			; // send outgoing message
+		}
+
+		if (LastMessageProcessed())
+			break;
+
+		; // receive incoming message
+		ProcessIncomingMessage(message);
+	}
+	; // call methods in derived class to obtain result of protocol session
+*/
+class ProtocolSession
+{
+public:
+	/// Exception thrown when an invalid protocol message is processed
+	class ProtocolError : public Exception
+	{
+	public:
+		ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {}
+	};
+
+	/// Exception thrown when a function is called unexpectedly
+	/*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */
+	class UnexpectedMethodCall : public Exception
+	{
+	public:
+		UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {}
+	};
+
+	virtual ~ProtocolSession() {}
+
+	ProtocolSession() : m_rng(NULLPTR), m_throwOnProtocolError(true), m_validState(false) {}
+
+	virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs &parameters) =0;
+
+	bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;}
+	void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;}
+
+	bool HasValidState() const {return m_validState;}
+
+	virtual bool OutgoingMessageAvailable() const =0;
+	virtual unsigned int GetOutgoingMessageLength() const =0;
+	virtual void GetOutgoingMessage(byte *message) =0;
+
+	virtual bool LastMessageProcessed() const =0;
+	virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0;
+
+protected:
+	void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const;
+	void CheckAndHandleInvalidState() const;
+	void SetValidState(bool valid) {m_validState = valid;}
+
+	RandomNumberGenerator *m_rng;
+
+private:
+	bool m_throwOnProtocolError, m_validState;
+};
+
+class KeyAgreementSession : public ProtocolSession
+{
+public:
+	virtual ~KeyAgreementSession() {}
+
+	virtual unsigned int GetAgreedValueLength() const =0;
+	virtual void GetAgreedValue(byte *agreedValue) const =0;
+};
+
+class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession
+{
+public:
+	virtual ~PasswordAuthenticatedKeyAgreementSession() {}
+
+	void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng,
+		const byte *myId, unsigned int myIdLength,
+		const byte *counterPartyId, unsigned int counterPartyIdLength,
+		const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength);
+};
+
+/// \brief Password based key agreement domain
+/// \since Crypto++ 3.0
+class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm
+{
+public:
+	virtual ~PasswordAuthenticatedKeyAgreementDomain() {}
+
+	/// return whether the domain parameters stored in this object are valid
+	virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const
+		{return GetCryptoParameters().Validate(rng, 2);}
+
+	virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0;
+	virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0;
+
+	enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8};
+
+	virtual bool IsValidRole(unsigned int role) =0;
+	virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0;
+};
+#endif
+
+/// \brief Exception thrown when an ASN.1 BER decoing error is encountered
+class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument
+{
+public:
+	BERDecodeErr() : InvalidArgument("BER decode error") {}
+	BERDecodeErr(const std::string &s) : InvalidArgument(s) {}
+};
+
+/// \brief Interface for encoding and decoding ASN1 objects
+/// \details Each class that derives from ASN1Object should provide a serialization format
+///  that controls subobject layout. Most of the time the serialization format is
+///  taken from a standard, like P1363 or an RFC.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1Object
+{
+public:
+	virtual ~ASN1Object() {}
+
+	/// \brief Decode this object from a BufferedTransformation
+	/// \param bt BufferedTransformation object
+	/// \details Uses Basic Encoding Rules (BER)
+	virtual void BERDecode(BufferedTransformation &bt) =0;
+
+	/// \brief Encode this object into a BufferedTransformation
+	/// \param bt BufferedTransformation object
+	/// \details Uses Distinguished Encoding Rules (DER)
+	virtual void DEREncode(BufferedTransformation &bt) const =0;
+
+	/// \brief Encode this object into a BufferedTransformation
+	/// \param bt BufferedTransformation object
+	/// \details Uses Basic Encoding Rules (BER).
+	/// \details This may be useful if DEREncode() would be too inefficient.
+	virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);}
+};
+
+/// \brief Specifies the build-time version of the library
+/// \return integer representing the build-time version
+/// \details LibraryVersion can help detect inadvertent mixing and matching of library
+///  versions. When using Crypto++ distributed by a third party, LibraryVersion()
+///  records the version of the shared object that was built by the third party.
+///  The LibraryVersion() record resides in <tt>cryptlib.o</tt> on Unix compatibles
+///  and <tt>cryptlib.obj</tt> on Windows. It does not change when an app links
+///  to the library.
+/// \details LibraryVersion() is declared with C linkage (<tt>extern "C"</tt>) within the
+///  CryptoPP namespace to help programs locate the symbol. If the symbol is present, then
+///  the library version is 5.7 or above. If it is missing, then the library version is
+///  5.6.5 or below.
+/// \details The function could be used as shown below.
+/// <pre>  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// </pre>
+/// \sa HeaderVersion(), <A HREF="http://github.com/weidai11/cryptopp/issues/371">GitHub Issue 371</A>.
+/// \since Crypto++ 6.0
+extern "C" {
+	int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT);
+} // C linkage
+
+/// \brief Specifies the runtime version of the library
+/// \return integer representing the runtime version
+/// \details HeaderVersion() can help detect inadvertent mixing and matching of library
+///  versions. When using Crypto++ distributed by a third party, HeaderVersion()
+///  records the version of the headers used by the app when the app is compiled.
+/// \details HeaderVersion() is declared with C linkage (<tt>extern "C"</tt>) within the
+///  CryptoPP namespace to help programs locate the symbol. If the symbol is present, then
+///  the library version is 5.7 or above. If it is missing, then the library version is
+///  5.6.5 or below.
+/// \details The function could be used as shown below.
+/// <pre>  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// </pre>
+/// \sa LibraryVersion(), <A HREF="http://github.com/weidai11/cryptopp/issues/371">GitHub Issue 371</A>.
+/// \since Crypto++ 6.0
+extern "C" {
+inline int HeaderVersion()
+{
+	return CRYPTOPP_VERSION;
+}
+} // C linkage
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 95 - 0
cryptopp/darn.h

@@ -0,0 +1,95 @@
+// darn.h - written and placed in public domain by Jeffrey Walton
+//          DARN requires POWER9/ISA 3.0.
+
+// At the moment only GCC 7.0 (and above) seems to support __builtin_darn()
+// and __builtin_darn_32(). However, GCC generates incorrect code. Clang 7.0
+// does not provide them, but it does support assembly instructions. XLC is
+// unknown, but there are no hits when searching IBM's site. To cover more
+// platforms we provide GCC inline assembly like we do with RDRAND and RDSEED.
+// Platforms that don't support GCC inline assembly or the builtin will fail
+// to compile. Also see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91481 and
+// https://gcc.gnu.org/onlinedocs/gcc/Basic-PowerPC-Built-in-Functions-Available-on-ISA-3_002e0.html
+
+/// \file darn.h
+/// \brief Classes for DARN RNG
+/// \sa <A HREF="https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0">Power
+///   ISA Version 3.0B</A>
+/// \since Crypto++ 8.0
+
+#ifndef CRYPTOPP_DARN_H
+#define CRYPTOPP_DARN_H
+
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Exception thrown when a DARN generator encounters
+///    a generator related error.
+/// \since Crypto++ 8.0
+class DARN_Err : public Exception
+{
+public:
+    DARN_Err(const std::string &operation)
+        : Exception(OTHER_ERROR, "DARN: " + operation + " operation failed") {}
+};
+
+/// \brief Hardware generated random numbers using DARN instruction
+/// \details DARN() provides access to Power9's random number generator. The
+///   Crypto++ implementation provides conditioned random numbers from the
+///   generator as opposed to raw random numbers. According to Power ISA 3.0B
+///   manual, a conditioned random number has been processed by hardware to
+///   reduce bias. A raw random number is unconditioned noise source output.
+/// \details According to Power ISA 3.0B manual, the random number generator
+///   provided by the <tt>darn</tt> instruction is NIST SP800-90B and SP800-90C
+///   compliant to the extent possible given the completeness of the standards
+///   at the time the hardware is designed. The random number generator provides
+///   a minimum of 0.5 bits of entropy per bit.
+/// \par Wraps
+///   darn instruction
+/// \sa <A HREF="https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0">Power
+///   ISA Version 3.0B</A>, MaurerRandomnessTest() for random bit generators
+/// \since Crypto++ 8.0
+class DARN : public RandomNumberGenerator
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "DARN"; }
+
+    virtual ~DARN() {}
+
+    /// \brief Construct a DARN generator
+     /// \throw DARN_Err if the random number generator is not available
+    DARN();
+
+    /// \brief Generate random array of bytes
+    /// \param output the byte buffer
+    /// \param size the length of the buffer, in bytes
+    virtual void GenerateBlock(byte *output, size_t size);
+
+    /// \brief Generate and discard n bytes
+    /// \param n the number of bytes to generate and discard
+    /// \details the RDSEED generator discards words, not bytes. If n is
+    ///   not a multiple of a machine word, then it is rounded up to
+    ///   that size.
+    virtual void DiscardBytes(size_t n);
+
+    /// \brief Update RNG state with additional unpredictable values
+    /// \param input unused
+    /// \param length unused
+    /// \details The operation is a nop for this generator.
+    virtual void IncorporateEntropy(const byte *input, size_t length)
+    {
+        // Override to avoid the base class' throw.
+        CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
+    }
+
+    std::string AlgorithmProvider() const {
+        return "Power9";
+    }
+
+private:
+    SecBlock<byte, AllocatorWithCleanup<byte, true> > m_temp;
+};
+
+NAMESPACE_END
+
+#endif // CRYPTOPP_DARN_H

+ 310 - 0
cryptopp/default.h

@@ -0,0 +1,310 @@
+// default.h - originally written and placed in the public domain by Wei Dai
+
+/// \file default.h
+/// \brief Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC
+
+#ifndef CRYPTOPP_DEFAULT_H
+#define CRYPTOPP_DEFAULT_H
+
+#include "sha.h"
+#include "hmac.h"
+#include "aes.h"
+#include "des.h"
+#include "modes.h"
+#include "filters.h"
+#include "smartptr.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Legacy block cipher for LegacyEncryptor, LegacyDecryptor, LegacyEncryptorWithMAC and LegacyDecryptorWithMAC
+typedef DES_EDE2 LegacyBlockCipher;
+/// \brief Legacy hash for use with LegacyEncryptorWithMAC and LegacyDecryptorWithMAC
+typedef SHA1 LegacyHashModule;
+/// \brief Legacy HMAC for use withLegacyEncryptorWithMAC and LegacyDecryptorWithMAC
+typedef HMAC<LegacyHashModule> LegacyMAC;
+
+/// \brief Default block cipher for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC
+typedef AES DefaultBlockCipher;
+/// \brief Default hash for use with DefaultEncryptorWithMAC and DefaultDecryptorWithMAC
+typedef SHA256 DefaultHashModule;
+/// \brief Default HMAC for use withDefaultEncryptorWithMAC and DefaultDecryptorWithMAC
+typedef HMAC<DefaultHashModule> DefaultMAC;
+
+/// \brief Exception thrown when LegacyDecryptorWithMAC or DefaultDecryptorWithMAC decryption error is encountered
+class DataDecryptorErr : public Exception
+{
+public:
+	DataDecryptorErr(const std::string &s)
+		: Exception(DATA_INTEGRITY_CHECK_FAILED, s) {}
+};
+
+/// \brief Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC
+class KeyBadErr : public DataDecryptorErr
+{
+	public: KeyBadErr()
+		: DataDecryptorErr("DataDecryptor: cannot decrypt message with this passphrase") {}
+};
+
+/// \brief Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC
+class MACBadErr : public DataDecryptorErr
+{
+	public: MACBadErr()
+		: DataDecryptorErr("DataDecryptorWithMAC: MAC check failed") {}
+};
+
+/// \brief Algorithm information for password-based encryptors and decryptors
+template <unsigned int BlockSize, unsigned int KeyLength, unsigned int DigestSize, unsigned int SaltSize, unsigned int Iterations>
+struct DataParametersInfo
+{
+	CRYPTOPP_CONSTANT(BLOCKSIZE  = BlockSize);
+	CRYPTOPP_CONSTANT(KEYLENGTH  = KeyLength);
+	CRYPTOPP_CONSTANT(SALTLENGTH = SaltSize);
+	CRYPTOPP_CONSTANT(DIGESTSIZE = DigestSize);
+	CRYPTOPP_CONSTANT(ITERATIONS = Iterations);
+};
+
+typedef DataParametersInfo<LegacyBlockCipher::BLOCKSIZE, LegacyBlockCipher::DEFAULT_KEYLENGTH, LegacyHashModule::DIGESTSIZE, 8, 200> LegacyParametersInfo;
+typedef DataParametersInfo<DefaultBlockCipher::BLOCKSIZE, DefaultBlockCipher::DEFAULT_KEYLENGTH, DefaultHashModule::DIGESTSIZE, 8, 2500> DefaultParametersInfo;
+
+/// \brief Password-based Encryptor
+/// \tparam BC BlockCipher based class used for encryption
+/// \tparam H HashTransformation based class used for mashing
+/// \tparam Info Constants used by the algorithms
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256.
+/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor
+/// \since Crypto++ 2.0
+template <class BC, class H, class Info>
+class DataEncryptor : public ProxyFilter, public Info
+{
+public:
+	CRYPTOPP_CONSTANT(BLOCKSIZE  = Info::BLOCKSIZE);
+	CRYPTOPP_CONSTANT(KEYLENGTH  = Info::KEYLENGTH);
+	CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH);
+	CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE);
+	CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS);
+
+	/// \brief Construct a DataEncryptor
+	/// \param passphrase a C-String password
+	/// \param attachment a BufferedTransformation to attach to this object
+	DataEncryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR);
+
+	/// \brief Construct a DataEncryptor
+	/// \param passphrase a byte string password
+	/// \param passphraseLength the length of the byte string password
+	/// \param attachment a BufferedTransformation to attach to this object
+	DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR);
+
+protected:
+	void FirstPut(const byte *);
+	void LastPut(const byte *inString, size_t length);
+
+private:
+	SecByteBlock m_passphrase;
+	typename CBC_Mode<BC>::Encryption m_cipher;
+};
+
+/// \brief Password-based Decryptor
+/// \tparam BC BlockCipher based class used for encryption
+/// \tparam H HashTransformation based class used for mashing
+/// \tparam Info Constants used by the algorithms
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256.
+/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor
+/// \since Crypto++ 2.0
+template <class BC, class H, class Info>
+class DataDecryptor : public ProxyFilter, public Info
+{
+public:
+	CRYPTOPP_CONSTANT(BLOCKSIZE  = Info::BLOCKSIZE);
+	CRYPTOPP_CONSTANT(KEYLENGTH  = Info::KEYLENGTH);
+	CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH);
+	CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE);
+	CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS);
+
+	/// \brief Constructs a DataDecryptor
+	/// \param passphrase a C-String password
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \param throwException a flag specifying whether an Exception should be thrown on error
+	DataDecryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true);
+
+	/// \brief Constructs a DataDecryptor
+	/// \param passphrase a byte string password
+	/// \param passphraseLength the length of the byte string password
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \param throwException a flag specifying whether an Exception should be thrown on error
+	DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true);
+
+	enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD};
+	State CurrentState() const {return m_state;}
+
+protected:
+	void FirstPut(const byte *inString);
+	void LastPut(const byte *inString, size_t length);
+
+	State m_state;
+
+private:
+	void CheckKey(const byte *salt, const byte *keyCheck);
+
+	SecByteBlock m_passphrase;
+	typename CBC_Mode<BC>::Decryption m_cipher;
+	member_ptr<FilterWithBufferedInput> m_decryptor;
+	bool m_throwException;
+
+};
+
+/// \brief Password-based encryptor with MAC
+/// \tparam BC BlockCipher based class used for encryption
+/// \tparam H HashTransformation based class used for mashing
+/// \tparam MAC HashTransformation based class used for authentication
+/// \tparam Info Constants used by the algorithms
+/// \details DataEncryptorWithMAC uses a non-standard mashup function called Mash() to derive key
+///   bits from the password.
+/// \details The purpose of the function Mash() is to take an arbitrary length input string and
+///   *deterministically* produce an arbitrary length output string such that (1) it looks random,
+///   (2) no information about the input is deducible from it, and (3) it contains as much entropy
+///   as it can hold, or the amount of entropy in the input string, whichever is smaller.
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256.
+/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC
+/// \since Crypto++ 2.0
+template <class BC, class H, class MAC, class Info>
+class DataEncryptorWithMAC : public ProxyFilter
+{
+public:
+	CRYPTOPP_CONSTANT(BLOCKSIZE  = Info::BLOCKSIZE);
+	CRYPTOPP_CONSTANT(KEYLENGTH  = Info::KEYLENGTH);
+	CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH);
+	CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE);
+	CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS);
+
+	/// \brief Constructs a DataEncryptorWithMAC
+	/// \param passphrase a C-String password
+	/// \param attachment a BufferedTransformation to attach to this object
+	DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR);
+
+	/// \brief Constructs a DataEncryptorWithMAC
+	/// \param passphrase a byte string password
+	/// \param passphraseLength the length of the byte string password
+	/// \param attachment a BufferedTransformation to attach to this object
+	DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR);
+
+protected:
+	void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);}
+	void LastPut(const byte *inString, size_t length);
+
+private:
+	member_ptr<MAC> m_mac;
+
+};
+
+/// \brief Password-based decryptor with MAC
+/// \tparam BC BlockCipher based class used for encryption
+/// \tparam H HashTransformation based class used for mashing
+/// \tparam MAC HashTransformation based class used for authentication
+/// \tparam Info Constants used by the algorithms
+/// \details DataDecryptorWithMAC uses a non-standard mashup function called Mash() to derive key
+///   bits from the password.
+/// \details The purpose of the function Mash() is to take an arbitrary length input string and
+///   *deterministically* produce an arbitrary length output string such that (1) it looks random,
+///   (2) no information about the input is deducible from it, and (3) it contains as much entropy
+///   as it can hold, or the amount of entropy in the input string, whichever is smaller.
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256.
+/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC
+/// \since Crypto++ 2.0
+template <class BC, class H, class MAC, class Info>
+class DataDecryptorWithMAC : public ProxyFilter
+{
+public:
+	CRYPTOPP_CONSTANT(BLOCKSIZE  = Info::BLOCKSIZE);
+	CRYPTOPP_CONSTANT(KEYLENGTH  = Info::KEYLENGTH);
+	CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH);
+	CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE);
+	CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS);
+
+	/// \brief Constructs a DataDecryptor
+	/// \param passphrase a C-String password
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \param throwException a flag specifying whether an Exception should be thrown on error
+	DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true);
+
+	/// \brief Constructs a DataDecryptor
+	/// \param passphrase a byte string password
+	/// \param passphraseLength the length of the byte string password
+	/// \param attachment a BufferedTransformation to attach to this object
+	/// \param throwException a flag specifying whether an Exception should be thrown on error
+	DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true);
+
+	typename DataDecryptor<BC,H,Info>::State CurrentState() const;
+	bool CheckLastMAC() const;
+
+protected:
+	void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);}
+	void LastPut(const byte *inString, size_t length);
+
+private:
+	member_ptr<MAC> m_mac;
+	HashVerificationFilter *m_hashVerifier;
+	bool m_throwException;
+};
+
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+/// \brief Password-based encryptor (deprecated)
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct LegacyEncryptor : public DataEncryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo> {};
+/// \brief Password-based decryptor (deprecated)
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct LegacyDecryptor : public DataDecryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo> {};
+/// \brief Password-based encryptor
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct DefaultEncryptor : public DataEncryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo> {};
+/// \brief Password-based decryptor
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct DefaultDecryptor : public DataDecryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo> {};
+/// \brief Password-based encryptor with MAC (deprecated)
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct LegacyEncryptorWithMAC : public DataEncryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo> {};
+/// \brief Password-based decryptor with MAC (deprecated)
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct LegacyDecryptorWithMAC : public DataDecryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo> {};
+/// \brief Password-based encryptor with MAC
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct DefaultEncryptorWithMAC : public DataEncryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo> {};
+/// \brief Password-based decryptor with MAC
+/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1.
+///   Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the
+///   <tt>Default*</tt> classes, and the old algorithms are available with the <tt>Legacy*</tt> classes.
+struct DefaultDecryptorWithMAC : public DataDecryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo> {};
+#else
+typedef DataEncryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo> LegacyEncryptor;
+typedef DataDecryptor<LegacyBlockCipher,LegacyHashModule,LegacyParametersInfo> LegacyDecryptor;
+
+typedef DataEncryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo> DefaultEncryptor;
+typedef DataDecryptor<DefaultBlockCipher,DefaultHashModule,DefaultParametersInfo> DefaultDecryptor;
+
+typedef DataEncryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo> LegacyEncryptorWithMAC;
+typedef DataDecryptorWithMAC<LegacyBlockCipher,LegacyHashModule,LegacyMAC,LegacyParametersInfo> LegacyDecryptorWithMAC;
+
+typedef DataEncryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo> DefaultEncryptorWithMAC;
+typedef DataDecryptorWithMAC<DefaultBlockCipher,DefaultHashModule,DefaultMAC,DefaultParametersInfo> DefaultDecryptorWithMAC;
+#endif
+
+NAMESPACE_END
+
+#endif

+ 163 - 0
cryptopp/des.h

@@ -0,0 +1,163 @@
+// des.h - originally written and placed in the public domain by Wei Dai
+
+/// \file des.h
+/// \brief Classes for DES, 2-key Triple-DES, 3-key Triple-DES and DESX
+
+#ifndef CRYPTOPP_DES_H
+#define CRYPTOPP_DES_H
+
+#include "seckey.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief DES block cipher base class
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL RawDES
+{
+public:
+	void RawSetKey(CipherDir direction, const byte *userKey);
+	void RawProcessBlock(word32 &l, word32 &r) const;
+
+protected:
+	static const word32 Spbox[8][64];
+
+	FixedSizeSecBlock<word32, 32> k;
+};
+
+/// \brief DES block cipher information
+/// \since Crypto++ 1.0
+struct DES_Info : public FixedBlockSize<8>, public FixedKeyLength<8>
+{
+	// disable DES in DLL version by not exporting this function
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES";}
+};
+
+/// \brief DES block cipher
+/// \details The DES implementation in Crypto++ ignores the parity bits
+///   (the least significant bits of each byte) in the key. However you can use CheckKeyParityBits()
+///   and CorrectKeyParityBits() to	check or correct the parity bits if you wish.
+/// \sa <a href="http://www.cryptopp.com/wiki/TripleDES">DES</a>
+/// \since Crypto++ 1.0
+class DES : public DES_Info, public BlockCipherDocumentation
+{
+	/// \brief DES block cipher default operation
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<DES_Info>, public RawDES
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+	};
+
+public:
+	/// check DES key parity bits
+	static bool CheckKeyParityBits(const byte *key);
+	/// correct DES key parity bits
+	static void CorrectKeyParityBits(byte *key);
+
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+/// \brief 2-key TripleDES block cipher information
+/// \since Crypto++ 1.0
+struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16>
+{
+	CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE2";}
+};
+
+/// \brief 2-key TripleDES block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/TripleDES">DES-EDE2</a>
+/// \since Crypto++ 1.0
+class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation
+{
+	/// \brief DES_EDE2 block cipher default operation
+	class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<DES_EDE2_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	protected:
+		RawDES m_des1, m_des2;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+/// \brief 3-key TripleDES block cipher information
+/// \since Crypto++ 1.0
+struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24>
+{
+	CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE3";}
+};
+
+/// \brief 3-key TripleDES block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/TripleDES">DES-EDE3</a>
+/// \since Crypto++ 1.0
+class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation
+{
+	/// \brief DES_EDE3 block cipher default operation
+	class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<DES_EDE3_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	protected:
+		RawDES m_des1, m_des2, m_des3;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+/// \brief DESX block cipher information
+/// \since Crypto++ 3.2
+struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24>
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES-XEX3";}
+};
+
+/// \brief DESX block cipher
+/// \sa <a href="http://www.cryptopp.com/wiki/TripleDES">DES-XEX3</a>, AKA DESX
+/// \since Crypto++ 3.2
+class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation
+{
+	/// \brief DES_XEX3 block cipher default operation
+	class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl<DES_XEX3_Info>
+	{
+	public:
+		void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &params);
+		void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const;
+
+	protected:
+		FixedSizeSecBlock<byte, BLOCKSIZE> m_x1, m_x3;
+		// VS2005 workaround: calling modules compiled with /clr gets unresolved external symbol DES::Base::ProcessAndXorBlock
+		// if we use DES::Encryption here directly without value_ptr.
+		value_ptr<DES::Encryption> m_des;
+	};
+
+public:
+	typedef BlockCipherFinal<ENCRYPTION, Base> Encryption;
+	typedef BlockCipherFinal<DECRYPTION, Base> Decryption;
+};
+
+typedef DES::Encryption DESEncryption;
+typedef DES::Decryption DESDecryption;
+
+typedef DES_EDE2::Encryption DES_EDE2_Encryption;
+typedef DES_EDE2::Decryption DES_EDE2_Decryption;
+
+typedef DES_EDE3::Encryption DES_EDE3_Encryption;
+typedef DES_EDE3::Decryption DES_EDE3_Decryption;
+
+typedef DES_XEX3::Encryption DES_XEX3_Encryption;
+typedef DES_XEX3::Decryption DES_XEX3_Decryption;
+
+NAMESPACE_END
+
+#endif

+ 275 - 0
cryptopp/dh.h

@@ -0,0 +1,275 @@
+// dh.h - originally written and placed in the public domain by Wei Dai
+
+/// \file dh.h
+/// \brief Classes for Diffie-Hellman key exchange
+
+#ifndef CRYPTOPP_DH_H
+#define CRYPTOPP_DH_H
+
+#include "cryptlib.h"
+#include "gfpcrypt.h"
+#include "algebra.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Diffie-Hellman domain
+/// \tparam GROUP_PARAMETERS group parameters
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \details A Diffie-Hellman domain is a set of parameters that must be shared
+///   by two parties in a key agreement protocol, along with the algorithms
+///   for generating key pairs and deriving agreed values.
+/// \details For COFACTOR_OPTION, see CofactorMultiplicationOption.
+/// \sa DL_SimpleKeyAgreementDomainBase
+/// \since Crypto++ 1.0
+template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption>
+class DH_Domain : public DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element>
+{
+	typedef DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element> Base;
+
+public:
+	typedef GROUP_PARAMETERS GroupParameters;
+	typedef typename GroupParameters::Element Element;
+	typedef DL_KeyAgreementAlgorithm_DH<Element, COFACTOR_OPTION> DH_Algorithm;
+	typedef DH_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain;
+
+	virtual ~DH_Domain() {}
+
+	/// \brief Construct a Diffie-Hellman domain
+	DH_Domain() {}
+
+	/// \brief Construct a Diffie-Hellman domain
+	/// \param params group parameters and options
+	DH_Domain(const GroupParameters &params)
+		: m_groupParameters(params) {}
+
+	/// \brief Construct a Diffie-Hellman domain
+	/// \param bt BufferedTransformation with group parameters and options
+	DH_Domain(BufferedTransformation &bt)
+		{m_groupParameters.BERDecode(bt);}
+
+	/// \brief Create a Diffie-Hellman domain
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \param v1 RandomNumberGenerator derived class
+	/// \param v2 second parameter
+	/// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
+	template <class T2>
+	DH_Domain(RandomNumberGenerator &v1, const T2 &v2)
+		{m_groupParameters.Initialize(v1, v2);}
+
+	/// \brief Create a Diffie-Hellman domain
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \tparam T3 template parameter used as a constructor parameter
+	/// \param v1 RandomNumberGenerator derived class
+	/// \param v2 second parameter
+	/// \param v3 third parameter
+	/// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
+	template <class T2, class T3>
+	DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3)
+		{m_groupParameters.Initialize(v1, v2, v3);}
+
+	/// \brief Create a Diffie-Hellman domain
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \tparam T3 template parameter used as a constructor parameter
+	/// \tparam T4 template parameter used as a constructor parameter
+	/// \param v1 RandomNumberGenerator derived class
+	/// \param v2 second parameter
+	/// \param v3 third parameter
+	/// \param v4 fourth parameter
+	/// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
+	template <class T2, class T3, class T4>
+	DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4)
+		{m_groupParameters.Initialize(v1, v2, v3, v4);}
+
+	/// \brief Construct a Diffie-Hellman domain
+	/// \tparam T1 template parameter used as a constructor parameter
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \param v1 first parameter
+	/// \param v2 second parameter
+	/// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
+	template <class T1, class T2>
+	DH_Domain(const T1 &v1, const T2 &v2)
+		{m_groupParameters.Initialize(v1, v2);}
+
+	/// \brief Construct a Diffie-Hellman domain
+	/// \tparam T1 template parameter used as a constructor parameter
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \tparam T3 template parameter used as a constructor parameter
+	/// \param v1 first parameter
+	/// \param v2 second parameter
+	/// \param v3 third parameter
+	/// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
+	template <class T1, class T2, class T3>
+	DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3)
+		{m_groupParameters.Initialize(v1, v2, v3);}
+
+	/// \brief Construct a Diffie-Hellman domain
+	/// \tparam T1 template parameter used as a constructor parameter
+	/// \tparam T2 template parameter used as a constructor parameter
+	/// \tparam T3 template parameter used as a constructor parameter
+	/// \tparam T4 template parameter used as a constructor parameter
+	/// \param v1 first parameter
+	/// \param v2 second parameter
+	/// \param v3 third parameter
+	/// \param v4 fourth parameter
+	/// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
+	template <class T1, class T2, class T3, class T4>
+	DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
+		{m_groupParameters.Initialize(v1, v2, v3, v4);}
+
+	/// \brief Retrieves the group parameters for this domain
+	/// \return the group parameters for this domain as a const reference
+	const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
+	/// \brief Retrieves the group parameters for this domain
+	/// \return the group parameters for this domain as a non-const reference
+	GroupParameters & AccessGroupParameters() {return m_groupParameters;}
+
+	/// \brief Generate a public key from a private key in this domain
+	/// \param rng RandomNumberGenerator derived class
+	/// \param privateKey byte buffer with the previously generated private key
+	/// \param publicKey byte buffer for the generated public key in this domain
+	/// \details If using a FIPS 140-2 validated library on Windows, then this class will perform
+	///   a self test to ensure the key pair is pairwise consistent. Non-FIPS and non-Windows
+	///   builds of the library do not provide FIPS validated cryptography, so the code should be
+	///   removed by the optimizer.
+	/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
+	void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
+	{
+		Base::GeneratePublicKey(rng, privateKey, publicKey);
+
+		if (FIPS_140_2_ComplianceEnabled())
+		{
+			SecByteBlock privateKey2(this->PrivateKeyLength());
+			this->GeneratePrivateKey(rng, privateKey2);
+
+			SecByteBlock publicKey2(this->PublicKeyLength());
+			Base::GeneratePublicKey(rng, privateKey2, publicKey2);
+
+			SecByteBlock agreedValue(this->AgreedValueLength()), agreedValue2(this->AgreedValueLength());
+			bool agreed1 = this->Agree(agreedValue, privateKey, publicKey2);
+			bool agreed2 = this->Agree(agreedValue2, privateKey2, publicKey);
+
+			if (!agreed1 || !agreed2 || agreedValue != agreedValue2)
+				throw SelfTestFailure(this->AlgorithmName() + ": pairwise consistency test failed");
+		}
+	}
+
+	static std::string CRYPTOPP_API StaticAlgorithmName()
+		{return GroupParameters::StaticAlgorithmNamePrefix() + DH_Algorithm::StaticAlgorithmName();}
+	std::string AlgorithmName() const {return StaticAlgorithmName();}
+
+private:
+	const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const
+		{return Singleton<DH_Algorithm>().Ref();}
+	DL_GroupParameters<Element> & AccessAbstractGroupParameters()
+		{return m_groupParameters;}
+
+	GroupParameters m_groupParameters;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime>;
+
+/// \brief Diffie-Hellman in GF(p)
+/// \details DH() class is a typedef of DH_Domain(). The documentation that follows
+///   does not exist. Rather the documentation was created in response to <a href="https://github.com/weidai11/cryptopp/issues/328">Issue
+///   328, Diffie-Hellman example code not compiling</a>.
+/// \details Generally speaking, a DH() object is ephemeral and is intended to execute one instance of the Diffie-Hellman protocol. The
+///   private and public key parts are not intended to be set or persisted. Rather, a new set of domain parameters are generated each
+///   time an object is created.
+/// \details Once a DH() object is created, once can retrieve the ephemeral public key for the other party with code similar to the
+///   following.
+/// <pre>   AutoSeededRandomPool prng;
+///   Integer p, q, g;
+///   PrimeAndGenerator pg;
+///
+///   pg.Generate(1, prng, 512, 511);
+///   p = pg.Prime();
+///   q = pg.SubPrime();
+///   g = pg.Generator();
+///
+///   DH dh(p, q, g);
+///   SecByteBlock t1(dh.PrivateKeyLength()), t2(dh.PublicKeyLength());
+///   dh.GenerateKeyPair(prng, t1, t2);
+///   Integer k1(t1, t1.size()), k2(t2, t2.size());
+///
+///   cout << "Private key:\n";
+///   cout << hex << k1 << endl;
+///
+///   cout << "Public key:\n";
+///   cout << hex << k2 << endl;</pre>
+///
+/// \details Output of the program above will be similar to the following.
+/// <pre>   $ ./cryptest.exe
+///   Private key:
+///   72b45a42371545e9d4880f48589aefh
+///   Public key:
+///   45fdb13f97b1840626f0250cec1dba4a23b894100b51fb5d2dd13693d789948f8bfc88f9200014b2
+///   ba8dd8a6debc471c69ef1e2326c61184a2eca88ec866346bh</pre>
+/// \sa <a href="http://www.cryptopp.com/wiki/Diffie-Hellman">Diffie-Hellman on the Crypto++ wiki</a> and
+///   <a href="http://www.weidai.com/scan-mirror/ka.html#DH">Diffie-Hellman</a> in GF(p) with key validation
+/// \since Crypto++ 1.0
+#if defined(CRYPTOPP_DOXYGEN_PROCESSING)
+struct DH : public DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime>
+{
+	typedef DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime> GroupParameters;
+	typedef GroupParameters::Element Element;
+
+	virtual ~DH() {}
+
+	/// \brief Create an uninitialized Diffie-Hellman object
+	DH() : DH_Domain() {}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param bt BufferedTransformation with group parameters and options
+	DH(BufferedTransformation &bt) : DH_Domain(bt) {}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param params group parameters and options
+	DH(const GroupParameters &params) : DH_Domain(params) {}
+
+	/// \brief Create a Diffie-Hellman object
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param modulusBits the size of the modulus, in bits
+	/// \details This function overload of Initialize() creates a new Diffie-Hellman object because it
+	///   takes a RandomNumberGenerator() as a parameter.
+	DH(RandomNumberGenerator &rng, unsigned int modulusBits) : DH_Domain(rng, modulusBits) {}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param p the modulus
+	/// \param g the generator
+	DH(const Integer &p, const Integer &g) : DH_Domain(p, g) {}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param p the modulus
+	/// \param q the subgroup order
+	/// \param g the generator
+	DH(const Integer &p, const Integer &q, const Integer &g) : DH_Domain(p, q, g) {}
+
+	/// \brief Creates a Diffie-Hellman object
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param modulusBits the size of the modulus, in bits
+	/// \details This function overload of Initialize() creates a new Diffie-Hellman object because it
+	///   takes a RandomNumberGenerator() as a parameter.
+	void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits)
+		{AccessGroupParameters().Initialize(rng, modulusBits);}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param p the modulus
+	/// \param g the generator
+	void Initialize(const Integer &p, const Integer &g)
+		{AccessGroupParameters().Initialize(p, g);}
+
+	/// \brief Initialize a Diffie-Hellman object
+	/// \param p the modulus
+	/// \param q the subgroup order
+	/// \param g the generator
+	void Initialize(const Integer &p, const Integer &q, const Integer &g)
+		{AccessGroupParameters().Initialize(p, q, g);}
+};
+#else
+// The real DH class is a typedef.
+typedef DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime> DH;
+#endif
+
+NAMESPACE_END
+
+#endif

+ 70 - 0
cryptopp/dh2.h

@@ -0,0 +1,70 @@
+// dh2.h - originally written and placed in the public domain by Wei Dai
+
+/// \file dh2.h
+/// \brief Classes for Unified Diffie-Hellman key exchange
+/// \since Crypto++ 3.0
+
+#ifndef CRYPTOPP_DH2_H
+#define CRYPTOPP_DH2_H
+
+#include "cryptlib.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Unified Diffie-Hellman in GF(p)
+/// \details A Diffie-Hellman domain is a set of parameters that must be shared
+///   by two parties in a key agreement protocol, along with the algorithms
+///   for generating key pairs and deriving agreed values.
+/// \sa AuthenticatedKeyAgreementDomain, <a href="http://www.weidai.com/scan-mirror/ka.html#DH2">Unified Diffie-Hellman</a>
+/// \since Crypto++ 3.0
+class DH2 : public AuthenticatedKeyAgreementDomain
+{
+public:
+	virtual ~DH2() {}
+
+	/// \brief Construct a DH2
+	DH2(SimpleKeyAgreementDomain &domain)
+		: d1(domain), d2(domain) {}
+	/// \brief Construct a DH2
+	DH2(SimpleKeyAgreementDomain &staticDomain, SimpleKeyAgreementDomain &ephemeralDomain)
+		: d1(staticDomain), d2(ephemeralDomain) {}
+
+	CryptoParameters & AccessCryptoParameters() {return d1.AccessCryptoParameters();}
+
+	unsigned int AgreedValueLength() const
+		{return d1.AgreedValueLength() + d2.AgreedValueLength();}
+
+	unsigned int StaticPrivateKeyLength() const
+		{return d1.PrivateKeyLength();}
+	unsigned int StaticPublicKeyLength() const
+		{return d1.PublicKeyLength();}
+	void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
+		{d1.GeneratePrivateKey(rng, privateKey);}
+	void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
+		{d1.GeneratePublicKey(rng, privateKey, publicKey);}
+	void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const
+		{d1.GenerateKeyPair(rng, privateKey, publicKey);}
+
+	unsigned int EphemeralPrivateKeyLength() const
+		{return d2.PrivateKeyLength();}
+	unsigned int EphemeralPublicKeyLength() const
+		{return d2.PublicKeyLength();}
+	void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
+		{d2.GeneratePrivateKey(rng, privateKey);}
+	void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
+		{d2.GeneratePublicKey(rng, privateKey, publicKey);}
+	void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const
+		{d2.GenerateKeyPair(rng, privateKey, publicKey);}
+
+	bool Agree(byte *agreedValue,
+		const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
+		const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
+		bool validateStaticOtherPublicKey=true) const;
+
+protected:
+	SimpleKeyAgreementDomain &d1, &d2;
+};
+
+NAMESPACE_END
+
+#endif

+ 71 - 0
cryptopp/dll.h

@@ -0,0 +1,71 @@
+// dll.h - originally written and placed in the public domain by Wei Dai
+
+/// \file dll.h
+/// \brief Functions and definitions required for building the FIPS-140 DLL on Windows
+
+#ifndef CRYPTOPP_DLL_H
+#define CRYPTOPP_DLL_H
+
+#if !defined(CRYPTOPP_IMPORTS) && !defined(CRYPTOPP_EXPORTS) && !defined(CRYPTOPP_DEFAULT_NO_DLL)
+#ifdef CRYPTOPP_CONFIG_H
+#error To use the DLL version of Crypto++, this file must be included before any other Crypto++ header files.
+#endif
+#define CRYPTOPP_IMPORTS
+#endif
+
+#include "aes.h"
+#include "cbcmac.h"
+#include "ccm.h"
+#include "cmac.h"
+#include "channels.h"
+#include "des.h"
+#include "dh.h"
+#include "dsa.h"
+#include "ec2n.h"
+#include "eccrypto.h"
+#include "ecp.h"
+#include "files.h"
+#include "fips140.h"
+#include "gcm.h"
+#include "hex.h"
+#include "hmac.h"
+#include "modes.h"
+#include "mqueue.h"
+#include "nbtheory.h"
+#include "osrng.h"
+#include "pkcspad.h"
+#include "pssr.h"
+#include "randpool.h"
+#include "rsa.h"
+#include "rw.h"
+#include "sha.h"
+#include "skipjack.h"
+
+#ifdef CRYPTOPP_IMPORTS
+
+#ifdef _DLL
+// cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain()
+#ifdef CRYPTOPP_DEBUG
+# pragma comment(lib, "msvcrtd")
+# pragma comment(lib, "cryptopp")
+#else
+# pragma comment(lib, "msvcrt")
+# pragma comment(lib, "cryptopp")
+#endif
+#endif
+
+#endif		// #ifdef CRYPTOPP_IMPORTS
+
+#include <new>	// for new_handler
+
+NAMESPACE_BEGIN(CryptoPP)
+
+typedef void * (CRYPTOPP_API * PNew)(size_t);
+typedef void (CRYPTOPP_API * PDelete)(void *);
+typedef void (CRYPTOPP_API * PGetNewAndDelete)(PNew &, PDelete &);
+typedef std::new_handler (CRYPTOPP_API * PSetNewHandler)(std::new_handler);
+typedef void (CRYPTOPP_API * PSetNewAndDelete)(PNew, PDelete, PSetNewHandler);
+
+NAMESPACE_END
+
+#endif

+ 114 - 0
cryptopp/dmac.h

@@ -0,0 +1,114 @@
+// dmac.h - originally written and placed in the public domain by Wei Dai
+
+/// \file dmac.h
+/// \brief Classes for DMAC message authentication code
+
+#ifndef CRYPTOPP_DMAC_H
+#define CRYPTOPP_DMAC_H
+
+#include "cbcmac.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief DMAC message authentication code base class
+/// \tparam T class derived from BlockCipherDocumentation
+/// \since Crypto++ 3.1
+template <class T>
+class CRYPTOPP_NO_VTABLE DMAC_Base : public SameKeyLengthAs<T>, public MessageAuthenticationCode
+{
+public:
+	CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE);
+	static std::string StaticAlgorithmName() {return std::string("DMAC(") + T::StaticAlgorithmName() + ")";}
+
+	virtual~DMAC_Base() {}
+	DMAC_Base() : m_subkeylength(0), m_counter(0) {}
+
+	void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
+	void Update(const byte *input, size_t length);
+	void TruncatedFinal(byte *mac, size_t size);
+	unsigned int DigestSize() const {return DIGESTSIZE;}
+
+	std::string AlgorithmProvider() const;
+
+private:
+	byte *GenerateSubKeys(const byte *key, size_t keylength);
+
+	size_t m_subkeylength;
+	SecByteBlock m_subkeys;
+	CBC_MAC<T> m_mac1;
+	typename T::Encryption m_f2;
+	unsigned int m_counter;
+};
+
+template <class T>
+std::string DMAC_Base<T>::AlgorithmProvider() const
+{
+	return m_f2.AlgorithmProvider();
+}
+
+/// \brief DMAC message authentication code
+/// \tparam T class derived from BlockCipherDocumentation
+/// \sa <A HREF="https://eprint.iacr.org/1997/010">CBC MAC for Real-Time Data Sources (08.15.1997)</A>
+///   by Erez Petrank and Charles Rackoff
+/// \since Crypto++ 3.1
+template <class T>
+class DMAC : public MessageAuthenticationCodeFinal<DMAC_Base<T> >
+{
+public:
+	/// \brief Construct a DMAC
+	DMAC() {}
+
+	/// \brief Construct a DMAC
+	/// \param key a byte array used to key the cipher
+	/// \param length the size of the byte array, in bytes
+	DMAC(const byte *key, size_t length=DMAC_Base<T>::DEFAULT_KEYLENGTH)
+		{this->SetKey(key, length);}
+};
+
+template <class T>
+void DMAC_Base<T>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
+{
+	m_subkeylength = T::StaticGetValidKeyLength(T::BLOCKSIZE);
+	m_subkeys.resize(2*UnsignedMin((unsigned int)T::BLOCKSIZE, m_subkeylength));
+	m_mac1.SetKey(GenerateSubKeys(key, length), m_subkeylength, params);
+	m_f2.SetKey(m_subkeys+m_subkeys.size()/2, m_subkeylength, params);
+	m_counter = 0;
+	m_subkeys.resize(0);
+}
+
+template <class T>
+void DMAC_Base<T>::Update(const byte *input, size_t length)
+{
+	m_mac1.Update(input, length);
+	m_counter = (unsigned int)((m_counter + length) % T::BLOCKSIZE);
+}
+
+template <class T>
+void DMAC_Base<T>::TruncatedFinal(byte *mac, size_t size)
+{
+	ThrowIfInvalidTruncatedSize(size);
+
+	byte pad[T::BLOCKSIZE];
+	byte padByte = byte(T::BLOCKSIZE-m_counter);
+	std::memset(pad, padByte, padByte);
+	m_mac1.Update(pad, padByte);
+	m_mac1.TruncatedFinal(mac, size);
+	m_f2.ProcessBlock(mac);
+
+	m_counter = 0;	// reset for next message
+}
+
+template <class T>
+byte *DMAC_Base<T>::GenerateSubKeys(const byte *key, size_t keylength)
+{
+	typename T::Encryption cipher(key, keylength);
+	std::memset(m_subkeys, 0, m_subkeys.size());
+	cipher.ProcessBlock(m_subkeys);
+	m_subkeys[m_subkeys.size()/2 + T::BLOCKSIZE - 1] = 1;
+	cipher.ProcessBlock(m_subkeys+m_subkeys.size()/2);
+	return m_subkeys;
+}
+
+NAMESPACE_END
+
+#endif

+ 179 - 0
cryptopp/donna.h

@@ -0,0 +1,179 @@
+// donna.h - written and placed in public domain by Jeffrey Walton
+//           Crypto++ specific implementation wrapped around Andrew
+//           Moon's public domain curve25519-donna and ed25519-donna,
+//           https://github.com/floodyberry/curve25519-donna and
+//           https://github.com/floodyberry/ed25519-donna.
+
+// The curve25519 and ed25519 source files multiplex different repos and
+// architectures using namespaces. The repos are Andrew Moon's
+// curve25519-donna and ed25519-donna. The architectures are 32-bit, 64-bit
+// and SSE. For example, 32-bit x25519 uses symbols from Donna::X25519 and
+// Donna::Arch32.
+
+// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]",
+// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658
+
+/// \file donna.h
+/// \details Functions for curve25519 and ed25519 operations
+/// \details This header provides the entry points into Andrew Moon's
+///   curve25519 and ed25519 curve functions. The Crypto++ classes x25519
+///   and ed25519 use the functions. The functions are in the <tt>Donna</tt>
+///   namespace and are curve25519_mult(), ed25519_publickey(),
+///   ed25519_sign() and ed25519_sign_open().
+/// \details At the moment the hash function for signing is fixed at
+///   SHA512.
+
+#ifndef CRYPTOPP_DONNA_H
+#define CRYPTOPP_DONNA_H
+
+#include "config.h"
+#include "cryptlib.h"
+#include "stdcpp.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+NAMESPACE_BEGIN(Donna)
+
+//***************************** curve25519 *****************************//
+
+/// \brief Generate a public key
+/// \param publicKey byte array for the public key
+/// \param secretKey byte array with the private key
+/// \return 0 on success, non-0 otherwise
+/// \details curve25519_mult() generates a public key from an existing
+///   secret key. Internally curve25519_mult() performs a scalar
+///   multiplication using the base point and writes the result to
+///   <tt>pubkey</tt>.
+int curve25519_mult(byte publicKey[32], const byte secretKey[32]);
+
+/// \brief Generate a shared key
+/// \param sharedKey byte array for the shared secret
+/// \param secretKey byte array with the private key
+/// \param othersKey byte array with the peer's public key
+/// \return 0 on success, non-0 otherwise
+/// \details curve25519_mult() generates a shared key from an existing
+///   secret key and the other party's public key. Internally
+///   curve25519_mult() performs a scalar multiplication using the two keys
+///   and writes the result to <tt>sharedKey</tt>.
+int curve25519_mult(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]);
+
+//******************************* ed25519 *******************************//
+
+/// \brief Creates a public key from a secret key
+/// \param publicKey byte array for the public key
+/// \param secretKey byte array with the private key
+/// \return 0 on success, non-0 otherwise
+/// \details ed25519_publickey() generates a public key from a secret key.
+///   Internally ed25519_publickey() performs a scalar multiplication
+///   using the secret key and then writes the result to <tt>publicKey</tt>.
+int ed25519_publickey(byte publicKey[32], const byte secretKey[32]);
+
+/// \brief Creates a signature on a message
+/// \param message byte array with the message
+/// \param messageLength size of the message, in bytes
+/// \param publicKey byte array with the public key
+/// \param secretKey byte array with the private key
+/// \param signature byte array for the signature
+/// \return 0 on success, non-0 otherwise
+/// \details ed25519_sign() generates a signature on a message using
+///   the public and private keys. The various buffers can be exact
+///   sizes, and do not require extra space like when using the
+///   NaCl library functions.
+/// \details At the moment the hash function for signing is fixed at
+///   SHA512.
+int ed25519_sign(const byte* message, size_t messageLength, const byte secretKey[32], const byte publicKey[32], byte signature[64]);
+
+/// \brief Creates a signature on a message
+/// \param stream std::istream derived class
+/// \param publicKey byte array with the public key
+/// \param secretKey byte array with the private key
+/// \param signature byte array for the signature
+/// \return 0 on success, non-0 otherwise
+/// \details ed25519_sign() generates a signature on a message using
+///   the public and private keys. The various buffers can be exact
+///   sizes, and do not require extra space like when using the
+///   NaCl library functions.
+/// \details This ed25519_sign() overload handles large streams. It
+///   was added for signing and verifying files that are too large
+///   for a memory allocation.
+/// \details At the moment the hash function for signing is fixed at
+///   SHA512.
+int ed25519_sign(std::istream& stream, const byte secretKey[32], const byte publicKey[32], byte signature[64]);
+
+/// \brief Verifies a signature on a message
+/// \param message byte array with the message
+/// \param messageLength size of the message, in bytes
+/// \param publicKey byte array with the public key
+/// \param signature byte array with the signature
+/// \return 0 on success, non-0 otherwise
+/// \details ed25519_sign_open() verifies a signature on a message using
+///   the public key. The various buffers can be exact sizes, and do not
+///   require extra space like when using the NaCl library functions.
+/// \details At the moment the hash function for signing is fixed at
+///   SHA512.
+int
+ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64]);
+
+/// \brief Verifies a signature on a message
+/// \param stream std::istream derived class
+/// \param publicKey byte array with the public key
+/// \param signature byte array with the signature
+/// \return 0 on success, non-0 otherwise
+/// \details ed25519_sign_open() verifies a signature on a message using
+///   the public key. The various buffers can be exact sizes, and do not
+///   require extra space like when using the NaCl library functions.
+/// \details This ed25519_sign_open() overload handles large streams. It
+///   was added for signing and verifying files that are too large
+///   for a memory allocation.
+/// \details At the moment the hash function for signing is fixed at
+///   SHA512.
+int
+ed25519_sign_open(std::istream& stream, const byte publicKey[32], const byte signature[64]);
+
+//****************************** Internal ******************************//
+
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+
+// CRYPTOPP_WORD128_AVAILABLE mostly depends upon GCC support for
+// __SIZEOF_INT128__. If __SIZEOF_INT128__ is not available then Moon
+// provides routines for MSC and GCC. It should cover most platforms,
+// but there are gaps like MS ARM64 and XLC. We tried to enable the
+// 64-bit path for SunCC from 12.5 but we got the dreaded compile
+// error "The operand ___LCM cannot be assigned to".
+
+#if defined(CRYPTOPP_WORD128_AVAILABLE) || \
+   (defined(CRYPTOPP_MSC_VERSION) && defined(_M_X64))
+# define CRYPTOPP_CURVE25519_64BIT 1
+#else
+# define CRYPTOPP_CURVE25519_32BIT 1
+#endif
+
+// Benchmarking on a modern 64-bit Core i5-6400 @2.7 GHz shows SSE2 on Linux
+// is not profitable. Here are the numbers in milliseconds/operation:
+//
+//   * Langley, C++, 0.050
+//   * Moon, C++: 0.040
+//   * Moon, SSE2: 0.061
+//   * Moon, native: 0.045
+//
+// However, a modern 64-bit Core i5-3200 @2.5 GHz shows SSE2 is profitable
+// for MS compilers. Here are the numbers in milliseconds/operation:
+//
+//   * x86, no SSE2, 0.294
+//   * x86, SSE2, 0.097
+//   * x64, no SSE2, 0.081
+//   * x64, SSE2, 0.071
+
+#if defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
+# define CRYPTOPP_CURVE25519_SSE2 1
+#endif
+
+#if (CRYPTOPP_CURVE25519_SSE2)
+  extern int curve25519_mult_SSE2(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]);
+#endif
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+
+NAMESPACE_END  // Donna
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_DONNA_H

+ 411 - 0
cryptopp/donna_32.h

@@ -0,0 +1,411 @@
+// donna_32.h - written and placed in public domain by Jeffrey Walton
+//              Crypto++ specific implementation wrapped around Andrew
+//              Moon's public domain curve25519-donna and ed25519-donna,
+//              https://github.com/floodyberry/curve25519-donna and
+//              https://github.com/floodyberry/ed25519-donna.
+
+// This source file multiplexes two different repos using namespaces. This
+// was a little easier from a project management standpoint. We only need
+// two files per architecture at the expense of namespaces and bloat.
+
+#ifndef CRYPTOPP_DONNA_32_H
+#define CRYPTOPP_DONNA_32_H
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+
+#include "config.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+NAMESPACE_BEGIN(Donna)
+NAMESPACE_BEGIN(Arch32)
+
+using CryptoPP::byte;
+using CryptoPP::word32;
+using CryptoPP::word64;
+
+// ******************** x25519 Agreement ************************* //
+
+#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n)
+#define mul32x32_64(a,b) (((word64)(a))*(b))
+
+typedef word32 bignum25519[10];
+
+const byte basePoint[32] = {9};
+const word32 reduce_mask_25 = (1 << 25) - 1;
+const word32 reduce_mask_26 = (1 << 26) - 1;
+
+// ****************** ed25519 Signatures *********************** //
+
+typedef byte hash_512bits[64];
+
+const int bignum256modm_bits_per_limb = 30;
+const int bignum256modm_limb_size = 9;
+typedef word32 bignum256modm_element_t;
+typedef bignum256modm_element_t bignum256modm[9];
+
+struct ge25519 {
+    bignum25519 x, y, z, t;
+};
+
+struct ge25519_p1p1 {
+    bignum25519 x, y, z, t;
+};
+
+struct ge25519_niels {
+    bignum25519 ysubx, xaddy, t2d;
+};
+
+struct ge25519_pniels {
+    bignum25519 ysubx, xaddy, z, t2d;
+};
+
+#define S1_SWINDOWSIZE 5
+#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2))
+#define S2_SWINDOWSIZE 7
+#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2))
+
+// *************** ed25519-donna-32bit-tables.h *************** //
+
+ALIGN(16) const ge25519 ge25519_basepoint = {
+    {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db},
+    {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999},
+    {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000},
+    {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c}
+};
+
+ALIGN(16) const bignum25519 ge25519_ecd = {
+    0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3
+};
+
+ALIGN(16) const bignum25519 ge25519_ec2d = {
+    0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67
+};
+
+ALIGN(16) const bignum25519 ge25519_sqrtneg1 = {
+    0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92
+};
+
+ALIGN(16) const ge25519_niels ge25519_niels_sliding_multiples[32] = {
+    {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}},
+    {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}},
+    {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}},
+    {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}},
+    {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}},
+    {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}},
+    {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}},
+    {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}},
+    {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}},
+    {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}},
+    {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}},
+    {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}},
+    {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}},
+    {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}},
+    {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}},
+    {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}},
+    {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}},
+    {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}},
+    {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}},
+    {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}},
+    {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}},
+    {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}},
+    {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}},
+    {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}},
+    {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}},
+    {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}},
+    {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}},
+    {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}},
+    {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}},
+    {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}},
+    {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}},
+    {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}}
+};
+
+// *************** modm-donna-32bit.h *************** //
+
+const bignum256modm modm_m = {
+    0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8,
+    0x00000014, 0x00000000, 0x00000000, 0x00000000,
+    0x00001000
+};
+
+const bignum256modm modm_mu = {
+    0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742,
+    0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff,
+    0x000fffff
+};
+
+/* multiples of p */
+const word32 twoP0       = 0x07ffffda;
+const word32 twoP13579   = 0x03fffffe;
+const word32 twoP2468    = 0x07fffffe;
+const word32 fourP0      = 0x0fffffb4;
+const word32 fourP13579  = 0x07fffffc;
+const word32 fourP2468   = 0x0ffffffc;
+
+// *************** ed25519-donna-basepoint-table.h *************** //
+
+/* multiples of the base point in packed {ysubx, xaddy, t2d} form */
+ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = {
+    {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f},
+    {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49},
+    {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54},
+    {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44},
+    {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68},
+    {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78},
+    {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23},
+    {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58},
+    {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10},
+    {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56},
+    {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14},
+    {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37},
+    {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02},
+    {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12},
+    {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f},
+    {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41},
+    {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e},
+    {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14},
+    {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41},
+    {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59},
+    {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49},
+    {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20},
+    {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b},
+    {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74},
+    {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69},
+    {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b},
+    {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e},
+    {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39},
+    {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33},
+    {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61},
+    {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45},
+    {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d},
+    {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c},
+    {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21},
+    {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a},
+    {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39},
+    {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22},
+    {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50},
+    {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d},
+    {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45},
+    {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d},
+    {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c},
+    {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27},
+    {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f},
+    {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f},
+    {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22},
+    {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c},
+    {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19},
+    {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71},
+    {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c},
+    {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a},
+    {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02},
+    {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31},
+    {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48},
+    {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c},
+    {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f},
+    {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60},
+    {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63},
+    {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70},
+    {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41},
+    {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24},
+    {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16},
+    {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78},
+    {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13},
+    {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a},
+    {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b},
+    {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d},
+    {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74},
+    {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58},
+    {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12},
+    {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d},
+    {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b},
+    {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c},
+    {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04},
+    {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76},
+    {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11},
+    {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f},
+    {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55},
+    {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57},
+    {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21},
+    {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a},
+    {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19},
+    {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60},
+    {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36},
+    {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07},
+    {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57},
+    {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05},
+    {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f},
+    {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72},
+    {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00},
+    {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c},
+    {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06},
+    {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15},
+    {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07},
+    {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51},
+    {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77},
+    {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e},
+    {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09},
+    {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56},
+    {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43},
+    {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27},
+    {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b},
+    {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46},
+    {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69},
+    {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14},
+    {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55},
+    {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13},
+    {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d},
+    {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31},
+    {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05},
+    {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f},
+    {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a},
+    {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10},
+    {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25},
+    {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08},
+    {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a},
+    {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f},
+    {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38},
+    {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65},
+    {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c},
+    {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e},
+    {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35},
+    {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47},
+    {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47},
+    {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74},
+    {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a},
+    {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56},
+    {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d},
+    {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44},
+    {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58},
+    {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70},
+    {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e},
+    {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41},
+    {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11},
+    {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f},
+    {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10},
+    {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72},
+    {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00},
+    {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05},
+    {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00},
+    {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b},
+    {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05},
+    {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f},
+    {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f},
+    {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40},
+    {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b},
+    {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02},
+    {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c},
+    {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f},
+    {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29},
+    {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71},
+    {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a},
+    {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06},
+    {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30},
+    {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b},
+    {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24},
+    {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49},
+    {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53},
+    {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02},
+    {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e},
+    {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d},
+    {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f},
+    {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07},
+    {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f},
+    {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b},
+    {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f},
+    {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12},
+    {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30},
+    {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45},
+    {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a},
+    {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13},
+    {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f},
+    {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a},
+    {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12},
+    {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b},
+    {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10},
+    {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b},
+    {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e},
+    {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f},
+    {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00},
+    {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33},
+    {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63},
+    {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b},
+    {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16},
+    {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57},
+    {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e},
+    {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73},
+    {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76},
+    {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e},
+    {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16},
+    {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45},
+    {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67},
+    {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a},
+    {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a},
+    {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e},
+    {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62},
+    {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e},
+    {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e},
+    {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78},
+    {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46},
+    {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a},
+    {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26},
+    {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b},
+    {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d},
+    {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45},
+    {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26},
+    {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62},
+    {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d},
+    {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61},
+    {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79},
+    {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39},
+    {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63},
+    {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34},
+    {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56},
+    {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e},
+    {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26},
+    {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f},
+    {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f},
+    {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b},
+    {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39},
+    {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51},
+    {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f},
+    {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f},
+    {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13},
+    {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c},
+    {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60},
+    {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15},
+    {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32},
+    {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b},
+    {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02},
+    {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c},
+    {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05},
+    {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67},
+    {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c},
+    {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37},
+    {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63},
+    {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68},
+    {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c},
+    {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c},
+    {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26},
+    {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08},
+    {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19},
+    {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41},
+    {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b},
+    {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08},
+    {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48},
+    {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54},
+    {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c},
+    {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f},
+    {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25},
+    {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55},
+    {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a},
+    {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59},
+    {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70},
+    {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27},
+    {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f}
+};
+
+NAMESPACE_END  // Arch32
+NAMESPACE_END  // Donna
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+#endif  // CRYPTOPP_DONNA_32_H

+ 457 - 0
cryptopp/donna_64.h

@@ -0,0 +1,457 @@
+// donna_64.h - written and placed in public domain by Jeffrey Walton
+//              Crypto++ specific implementation wrapped around Andrew
+//              Moon's public domain curve25519-donna and ed25519-donna,
+//              https://github.com/floodyberry/curve25519-donna and
+//              https://github.com/floodyberry/ed25519-donna.
+
+// This source file multiplexes two different repos using namespaces. This
+// was a little easier from a project management standpoint. We only need
+// two files per architecture at the expense of namespaces and bloat.
+
+#ifndef CRYPTOPP_DONNA_64_H
+#define CRYPTOPP_DONNA_64_H
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+
+#include "config.h"
+
+#if defined(CRYPTOPP_MSC_VERSION)
+# include <intrin.h>
+# pragma intrinsic(_umul128)
+# pragma intrinsic(__shiftright128)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+NAMESPACE_BEGIN(Donna)
+NAMESPACE_BEGIN(Arch64)
+
+using CryptoPP::byte;
+using CryptoPP::word32;
+using CryptoPP::word64;
+
+// ******************** x25519 Agreement ************************* //
+
+#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n)
+typedef word64 bignum25519[5];
+
+const byte basePoint[32] = {9};
+const word64 reduce_mask_40 = ((word64)1 << 40) - 1;
+const word64 reduce_mask_51 = ((word64)1 << 51) - 1;
+const word64 reduce_mask_52 = ((word64)1 << 52) - 1;
+const word64 reduce_mask_56 = ((word64)1 << 56) - 1;
+
+const word64 two54m152      = (((word64)1) << 54) - 152;
+const word64 two54m8        = (((word64)1) << 54) - 8;
+
+#if defined(CRYPTOPP_WORD128_AVAILABLE)
+using CryptoPP::word128;
+# define lo128(a) ((word64)a)
+# define hi128(a) ((word64)(a >> 64))
+# define add128(a,b) a += b;
+# define add128_64(a,b) a += (word64)b;
+# define mul64x64_128(out,a,b) out = (word128)a * b;
+# define shr128(out,in,shift) out = (word64)(in >> (shift));
+# define shl128(out,in,shift) out = (word64)((in << shift) >> 64);
+
+#elif defined(CRYPTOPP_MSC_VERSION)
+struct word128 { word64 lo, hi; };
+# define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi);
+# define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift);
+# define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift);
+# define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift)
+# define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift)
+# define add128(a,b) { word64 p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); }
+# define add128_64(a,b) { word64 p = a.lo; a.lo += b; a.hi += (a.lo < p); }
+# define lo128(a) (a.lo)
+# define hi128(a) (a.hi)
+
+#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
+struct word128 { word64 lo, hi; };
+# define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b));
+# define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo;
+# define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi;
+# define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift)
+# define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift)
+# define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc");
+# define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc");
+# define lo128(a) (a.lo)
+# define hi128(a) (a.hi)
+
+#else
+// https://groups.google.com/forum/#!forum/cryptopp-users
+# error "Unsupported platform"
+#endif
+
+// ****************** ed25519 Signatures *********************** //
+
+typedef byte hash_512bits[64];
+
+const int bignum256modm_bits_per_limb = 56;
+const int bignum256modm_limb_size = 5;
+typedef word64 bignum256modm_element_t;
+typedef bignum256modm_element_t bignum256modm[5];
+
+/* multiples of p */
+const word64 twoP0      = 0x0fffffffffffda;
+const word64 twoP1234   = 0x0ffffffffffffe;
+const word64 fourP0     = 0x1fffffffffffb4;
+const word64 fourP1234  = 0x1ffffffffffffc;
+
+struct ge25519 {
+    bignum25519 x, y, z, t;
+};
+
+struct ge25519_p1p1 {
+    bignum25519 x, y, z, t;
+};
+
+struct ge25519_niels {
+    bignum25519 ysubx, xaddy, t2d;
+};
+
+struct ge25519_pniels {
+    bignum25519 ysubx, xaddy, z, t2d;
+};
+
+#define S1_SWINDOWSIZE 5
+#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2))
+#define S2_SWINDOWSIZE 7
+#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2))
+
+// *************** ed25519-donna-64bit-tables.h *************** //
+
+const ge25519 ge25519_basepoint = {
+    {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5},
+    {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666},
+    {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000},
+    {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7}
+};
+
+const bignum25519 ge25519_ecd = {
+    0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff
+};
+
+const bignum25519 ge25519_ec2d = {
+    0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff
+};
+
+const bignum25519 ge25519_sqrtneg1 = {
+    0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d
+};
+
+const ge25519_niels ge25519_niels_sliding_multiples[32] = {
+    {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}},
+    {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}},
+    {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}},
+    {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}},
+    {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}},
+    {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}},
+    {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}},
+    {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}},
+    {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}},
+    {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}},
+    {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}},
+    {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}},
+    {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}},
+    {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}},
+    {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}},
+    {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}},
+    {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}},
+    {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}},
+    {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}},
+    {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}},
+    {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}},
+    {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}},
+    {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}},
+    {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}},
+    {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}},
+    {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}},
+    {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}},
+    {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}},
+    {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}},
+    {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}},
+    {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}},
+    {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}}
+};
+
+// ****************** modm-donna-64bit.h *********************** //
+
+const bignum256modm modm_m = {
+    0x12631a5cf5d3ed, 0xf9dea2f79cd658,
+    0x000000000014de, 0x00000000000000,
+    0x00000010000000
+};
+
+const bignum256modm modm_mu = {
+    0x9ce5a30a2c131b, 0x215d086329a7ed,
+    0xffffffffeb2106, 0xffffffffffffff,
+    0x00000fffffffff
+};
+
+// *************** ed25519-donna-basepoint-table.h *************** //
+
+/* multiples of the base point in packed {ysubx, xaddy, t2d} form */
+ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = {
+    {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f},
+    {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49},
+    {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54},
+    {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44},
+    {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68},
+    {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78},
+    {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23},
+    {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58},
+    {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10},
+    {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56},
+    {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14},
+    {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37},
+    {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02},
+    {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12},
+    {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f},
+    {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41},
+    {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e},
+    {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14},
+    {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41},
+    {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59},
+    {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49},
+    {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20},
+    {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b},
+    {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74},
+    {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69},
+    {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b},
+    {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e},
+    {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39},
+    {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33},
+    {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61},
+    {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45},
+    {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d},
+    {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c},
+    {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21},
+    {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a},
+    {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39},
+    {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22},
+    {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50},
+    {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d},
+    {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45},
+    {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d},
+    {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c},
+    {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27},
+    {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f},
+    {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f},
+    {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22},
+    {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c},
+    {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19},
+    {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71},
+    {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c},
+    {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a},
+    {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02},
+    {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31},
+    {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48},
+    {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c},
+    {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f},
+    {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60},
+    {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63},
+    {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70},
+    {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41},
+    {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24},
+    {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16},
+    {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78},
+    {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13},
+    {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a},
+    {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b},
+    {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d},
+    {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74},
+    {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58},
+    {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12},
+    {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d},
+    {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b},
+    {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c},
+    {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04},
+    {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76},
+    {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11},
+    {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f},
+    {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55},
+    {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57},
+    {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21},
+    {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a},
+    {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19},
+    {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60},
+    {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36},
+    {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07},
+    {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57},
+    {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05},
+    {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f},
+    {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72},
+    {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00},
+    {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c},
+    {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06},
+    {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15},
+    {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07},
+    {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51},
+    {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77},
+    {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e},
+    {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09},
+    {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56},
+    {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43},
+    {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27},
+    {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b},
+    {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46},
+    {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69},
+    {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14},
+    {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55},
+    {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13},
+    {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d},
+    {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31},
+    {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05},
+    {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f},
+    {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a},
+    {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10},
+    {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25},
+    {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08},
+    {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a},
+    {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f},
+    {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38},
+    {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65},
+    {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c},
+    {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e},
+    {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35},
+    {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47},
+    {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47},
+    {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74},
+    {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a},
+    {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56},
+    {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d},
+    {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44},
+    {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58},
+    {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70},
+    {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e},
+    {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41},
+    {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11},
+    {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f},
+    {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10},
+    {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72},
+    {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00},
+    {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05},
+    {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00},
+    {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b},
+    {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05},
+    {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f},
+    {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f},
+    {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40},
+    {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b},
+    {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02},
+    {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c},
+    {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f},
+    {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29},
+    {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71},
+    {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a},
+    {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06},
+    {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30},
+    {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b},
+    {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24},
+    {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49},
+    {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53},
+    {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02},
+    {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e},
+    {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d},
+    {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f},
+    {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07},
+    {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f},
+    {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b},
+    {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f},
+    {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12},
+    {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30},
+    {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45},
+    {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a},
+    {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13},
+    {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f},
+    {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a},
+    {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12},
+    {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b},
+    {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10},
+    {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b},
+    {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e},
+    {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f},
+    {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00},
+    {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33},
+    {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63},
+    {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b},
+    {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16},
+    {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57},
+    {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e},
+    {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73},
+    {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76},
+    {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e},
+    {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16},
+    {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45},
+    {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67},
+    {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a},
+    {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a},
+    {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e},
+    {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62},
+    {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e},
+    {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e},
+    {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78},
+    {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46},
+    {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a},
+    {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26},
+    {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b},
+    {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d},
+    {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45},
+    {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26},
+    {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62},
+    {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d},
+    {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61},
+    {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79},
+    {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39},
+    {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63},
+    {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34},
+    {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56},
+    {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e},
+    {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26},
+    {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f},
+    {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f},
+    {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b},
+    {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39},
+    {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51},
+    {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f},
+    {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f},
+    {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13},
+    {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c},
+    {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60},
+    {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15},
+    {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32},
+    {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b},
+    {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02},
+    {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c},
+    {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05},
+    {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67},
+    {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c},
+    {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37},
+    {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63},
+    {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68},
+    {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c},
+    {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c},
+    {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26},
+    {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08},
+    {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19},
+    {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41},
+    {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b},
+    {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08},
+    {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48},
+    {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54},
+    {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c},
+    {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f},
+    {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25},
+    {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55},
+    {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a},
+    {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59},
+    {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70},
+    {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27},
+    {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f}
+};
+
+NAMESPACE_END  // Arch64
+NAMESPACE_END  // Donna
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+#endif  // CRYPTOPP_DONNA_64_H

+ 86 - 0
cryptopp/donna_sse.h

@@ -0,0 +1,86 @@
+// donna_sse.h - written and placed in public domain by Jeffrey Walton
+//               Crypto++ specific implementation wrapped around Andrew
+//               Moon's public domain curve25519-donna and ed25519-donna,
+//               https://github.com/floodyberry/curve25519-donna and
+//               https://github.com/floodyberry/ed25519-donna.
+
+// This source file multiplexes two different repos using namespaces. This
+// was a little easier from a project management standpoint. We only need
+// two files per architecture at the expense of namespaces and bloat.
+
+#ifndef CRYPTOPP_DONNA_SSE_H
+#define CRYPTOPP_DONNA_SSE_H
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+
+#include "config.h"
+#include <emmintrin.h>
+
+NAMESPACE_BEGIN(CryptoPP)
+NAMESPACE_BEGIN(Donna)
+NAMESPACE_BEGIN(ArchSSE)
+
+using CryptoPP::byte;
+using CryptoPP::word32;
+
+typedef __m128i xmmi;
+#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n)
+
+typedef union packedelem8_t {
+    byte u[16];
+    xmmi v;
+} packedelem8;
+
+typedef union packedelem32_t {
+    word32 u[4];
+    xmmi v;
+} packedelem32;
+
+typedef union packedelem64_t {
+    word64 u[2];
+    xmmi v;
+} packedelem64;
+
+/* 10 elements + an extra 2 to fit in 3 xmm registers */
+typedef word32 bignum25519[12];
+typedef packedelem32 packed32bignum25519[5];
+typedef packedelem64 packed64bignum25519[10];
+
+const word32 reduce_mask_26 = (1 << 26) - 1;
+const word32 reduce_mask_25 = (1 << 25) - 1;
+
+const packedelem32 sse2_bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}};
+const packedelem32 sse2_top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}};
+const packedelem32 sse2_top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}};
+const packedelem32 sse2_bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}};
+
+/* reduction masks */
+const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}};
+const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}};
+const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}};
+const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}};
+const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}};
+
+/* multipliers */
+const packedelem64 packednineteen = {{19, 19}};
+const packedelem64 packednineteenone = {{19, 1}};
+const packedelem64 packedthirtyeight = {{38, 38}};
+const packedelem64 packed3819 = {{19*2,19}};
+const packedelem64 packed9638 = {{19*4,19*2}};
+
+/* 121666,121665 */
+const packedelem64 packed121666121665 = {{121666, 121665}};
+
+/* 2*(2^255 - 19) = 0 mod p */
+const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}};
+const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}};
+const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}};
+
+const packedelem32 packed32zeromodp0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}};
+const packedelem32 packed32zeromodp1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}};
+
+NAMESPACE_END  // ArchSSE
+NAMESPACE_END  // Donna
+NAMESPACE_END  // CryptoPP
+
+#endif  // CRYPTOPP_DOXYGEN_PROCESSING
+#endif  // CRYPTOPP_DONNA_SSE_H

+ 718 - 0
cryptopp/drbg.h

@@ -0,0 +1,718 @@
+// drbg.h - written and placed in public domain by Jeffrey Walton.
+
+/// \file drbg.h
+/// \brief Classes for NIST DRBGs from SP 800-90A
+/// \sa <A HREF="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">Recommendation
+///  for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)</A>
+/// \since Crypto++ 6.0
+
+#ifndef CRYPTOPP_NIST_DRBG_H
+#define CRYPTOPP_NIST_DRBG_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+#include "hmac.h"
+#include "sha.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Interface for NIST DRBGs from SP 800-90A
+/// \details NIST_DRBG is the base class interface for NIST DRBGs from SP 800-90A Rev 1 (June 2015)
+/// \details You should reseed the generator after a fork() to avoid multiple generators
+///  with the same internal state.
+/// \sa <A HREF="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">Recommendation
+///  for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)</A>
+/// \since Crypto++ 6.0
+class NIST_DRBG : public RandomNumberGenerator
+{
+public:
+    /// \brief Exception thrown when a NIST DRBG encounters an error
+    class Err : public Exception
+    {
+    public:
+        explicit Err(const std::string &c, const std::string &m)
+        : Exception(OTHER_ERROR, c + ": " + m) {}
+    };
+
+public:
+    virtual ~NIST_DRBG() {}
+
+    /// \brief Determines if a generator can accept additional entropy
+    /// \return true
+    /// \details All NIST_DRBG return true
+    virtual bool CanIncorporateEntropy() const {return true;}
+
+    /// \brief Update RNG state with additional unpredictable values
+    /// \param input the entropy to add to the generator
+    /// \param length the size of the input buffer
+    /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy
+    /// \details NIST instantiation and reseed requirements demand the generator is constructed
+    ///  with at least <tt>MINIMUM_ENTROPY</tt> entropy. The byte array for <tt>input</tt> must
+    ///  meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
+    ///  SP 800-90C</A> requirements.
+    virtual void IncorporateEntropy(const byte *input, size_t length)=0;
+
+    /// \brief Update RNG state with additional unpredictable values
+    /// \param entropy the entropy to add to the generator
+    /// \param entropyLength the size of the input buffer
+    /// \param additional additional input to add to the generator
+    /// \param additionaLength the size of the additional input buffer
+    /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy
+    /// \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST
+    ///  instantiation and reseed requirements demand the generator is constructed with at least
+    ///  <tt>MINIMUM_ENTROPY</tt> entropy. The byte array for <tt>entropy</tt> must meet
+    ///  <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
+    ///!  SP 800-90C</A> requirements.
+    virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0;
+
+    /// \brief Generate random array of bytes
+    /// \param output the byte buffer
+    /// \param size the length of the buffer, in bytes
+    /// \throw NIST_DRBG::Err if a reseed is required
+    /// \throw NIST_DRBG::Err if the size exceeds <tt>MAXIMUM_BYTES_PER_REQUEST</tt>
+    virtual void GenerateBlock(byte *output, size_t size)=0;
+
+    /// \brief Generate random array of bytes
+    /// \param additional additional input to add to the generator
+    /// \param additionaLength the size of the additional input buffer
+    /// \param output the byte buffer
+    /// \param size the length of the buffer, in bytes
+    /// \throw NIST_DRBG::Err if a reseed is required
+    /// \throw NIST_DRBG::Err if the size exceeds <tt>MAXIMUM_BYTES_PER_REQUEST</tt>
+    /// \details GenerateBlock() is an overload provided to match NIST requirements. The byte
+    ///  array for <tt>additional</tt> input is optional. If present the additional randomness
+    ///  is mixed before generating the output bytes.
+    virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0;
+
+    /// \brief Provides the security strength
+    /// \return The security strength of the generator, in bytes
+    /// \details The equivalent class constant is <tt>SECURITY_STRENGTH</tt>
+    virtual unsigned int SecurityStrength() const=0;
+
+    /// \brief Provides the seed length
+    /// \return The seed size of the generator, in bytes
+    /// \details The equivalent class constant is <tt>SEED_LENGTH</tt>. The size is
+    ///  used to maintain internal state of <tt>V</tt> and <tt>C</tt>.
+    virtual unsigned int SeedLength() const=0;
+
+    /// \brief Provides the minimum entropy size
+    /// \return The minimum entropy size required by the generator, in bytes
+    /// \details The equivalent class constant is <tt>MINIMUM_ENTROPY</tt>. All NIST DRBGs must
+    ///  be instaniated with at least <tt>MINIMUM_ENTROPY</tt> bytes of entropy. The bytes must
+    ///  meet <A HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
+    ///  SP 800-90C</A> requirements.
+    virtual unsigned int MinEntropyLength() const=0;
+
+    /// \brief Provides the maximum entropy size
+    /// \return The maximum entropy size that can be consumed by the generator, in bytes
+    /// \details The equivalent class constant is <tt>MAXIMUM_ENTROPY</tt>. The bytes must
+    ///  meet <A HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
+    ///  SP 800-90C</A> requirements. <tt>MAXIMUM_ENTROPY</tt> has been reduced from
+    ///  2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype.
+    virtual unsigned int MaxEntropyLength() const=0;
+
+    /// \brief Provides the minimum nonce size
+    /// \return The minimum nonce size recommended for the generator, in bytes
+    /// \details The equivalent class constant is <tt>MINIMUM_NONCE</tt>. If a nonce is not
+    ///  required then <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not require a
+    ///  nonce, while <tt>HMAC_DRBG</tt> and <tt>CTR_DRBG</tt> require a nonce.
+    virtual unsigned int MinNonceLength() const=0;
+
+    /// \brief Provides the maximum nonce size
+    /// \return The maximum nonce that can be consumed by the generator, in bytes
+    /// \details The equivalent class constant is <tt>MAXIMUM_NONCE</tt>. <tt>MAXIMUM_NONCE</tt>
+    ///  has been reduced from 2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype.
+    ///  If a nonce is not required then <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not
+    ///  require a nonce, while <tt>HMAC_DRBG</tt> and <tt>CTR_DRBG</tt> require a nonce.
+    virtual unsigned int MaxNonceLength() const=0;
+
+    /// \brief Provides the maximum size of a request to GenerateBlock
+    /// \return The maximum size of a request to GenerateBlock(), in bytes
+    /// \details The equivalent class constant is <tt>MAXIMUM_BYTES_PER_REQUEST</tt>
+    virtual unsigned int MaxBytesPerRequest() const=0;
+
+    /// \brief Provides the maximum number of requests before a reseed
+    /// \return The maximum number of requests before a reseed, in bytes
+    /// \details The equivalent class constant is <tt>MAXIMUM_REQUESTS_BEFORE_RESEED</tt>.
+    ///  <tt>MAXIMUM_REQUESTS_BEFORE_RESEED</tt> has been reduced from 2<sup>48</sup> to <tt>INT_MAX</tt>
+    ///  to fit the underlying C++ datatype.
+    virtual unsigned int MaxRequestBeforeReseed() const=0;
+
+protected:
+    virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength,
+        const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0;
+
+    virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0;
+};
+
+// *************************************************************
+
+/// \tparam HASH NIST approved hash derived from HashTransformation
+/// \tparam STRENGTH security strength, in bytes
+/// \tparam SEEDLENGTH seed length, in bytes
+/// \brief Hash_DRBG from SP 800-90A Rev 1 (June 2015)
+/// \details The NIST Hash DRBG is instantiated with a number of parameters. Two of the parameters,
+///  Security Strength and Seed Length, depend on the hash and are specified as template parameters.
+///  The remaining parameters are included in the class. The parameters and their values are listed
+///  in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38).
+/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto
+///  2<sup>48</sup> requests before a reseed. However, Hash_DRBG limits it to <tt>INT_MAX</tt> due
+///  to the limited data range of an int.
+/// \details You should reseed the generator after a fork() to avoid multiple generators
+///  with the same internal state.
+/// \sa <A HREF="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">Recommendation
+///  for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)</A>
+/// \since Crypto++ 6.0
+template <typename HASH=SHA256, unsigned int STRENGTH=128/8, unsigned int SEEDLENGTH=440/8>
+class Hash_DRBG : public NIST_DRBG, public NotCopyable
+{
+public:
+    CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH);
+    CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH);
+    CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH);
+    CRYPTOPP_CONSTANT(MINIMUM_NONCE=0);
+    CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0);
+    CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0);
+    CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536);
+    CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX);
+
+    static std::string StaticAlgorithmName() { return std::string("Hash_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); }
+
+    /// \brief Construct a Hash DRBG
+    /// \param entropy the entropy to instantiate the generator
+    /// \param entropyLength the size of the entropy buffer
+    /// \param nonce additional input to instantiate the generator
+    /// \param nonceLength the size of the nonce buffer
+    /// \param personalization additional input to instantiate the generator
+    /// \param personalizationLength the size of the personalization buffer
+    /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy
+    /// \details All NIST DRBGs must be instaniated with at least <tt>MINIMUM_ENTROPY</tt> bytes of entropy.
+    ///  The byte array for <tt>entropy</tt> must meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST
+    ///  SP 800-90B or SP 800-90C</A> requirements.
+    /// \details The <tt>nonce</tt> and <tt>personalization</tt> are optional byte arrays. If <tt>nonce</tt> is supplied,
+    ///  then it should be at least <tt>MINIMUM_NONCE</tt> bytes of entropy.
+    /// \details An example of instantiating a SHA256 generator is shown below.
+    ///  The example provides more entropy than required for SHA256. The <tt>NonblockingRng</tt> meets the
+    ///  requirements of <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or SP 800-90C</A>.
+    ///  RDRAND() and RDSEED() generators would work as well.
+    /// <pre>
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   Hash_DRBG<SHA256, 128/8, 440/8> drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// </pre>
+    Hash_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
+        size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0)
+        : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH), m_reseed(0)
+    {
+        if (m_c.data())  // GCC analyzer warning
+            std::memset(m_c.data(), 0x00, m_c.size());
+        if (m_v.data())  // GCC analyzer warning
+            std::memset(m_v.data(), 0x00, m_v.size());
+
+        if (entropy != NULLPTR && entropyLength != 0)
+            DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+    }
+
+    unsigned int SecurityStrength() const {return SECURITY_STRENGTH;}
+    unsigned int SeedLength() const {return SEED_LENGTH;}
+    unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;}
+    unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;}
+    unsigned int MinNonceLength() const {return MINIMUM_NONCE;}
+    unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;}
+    unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;}
+    unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;}
+
+    void IncorporateEntropy(const byte *input, size_t length)
+        {return DRBG_Reseed(input, length, NULLPTR, 0);}
+
+    void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+        {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);}
+
+    void GenerateBlock(byte *output, size_t size)
+        {return Hash_Generate(NULLPTR, 0, output, size);}
+
+    void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)
+        {return Hash_Generate(additional, additionaLength, output, size);}
+
+    std::string AlgorithmProvider() const
+        {/*Hack*/HASH hash; return hash.AlgorithmProvider();}
+
+protected:
+    // 10.1.1.2 Instantiation of Hash_DRBG (p.39)
+    void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+        const byte* personalization, size_t personalizationLength);
+
+    // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40)
+    void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength);
+
+    // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41)
+    void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size);
+
+    // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49)
+    void Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2,
+        const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen);
+
+private:
+    HASH m_hash;
+    SecByteBlock m_c, m_v, m_temp;
+    word64 m_reseed;
+};
+
+// typedef Hash_DRBG<SHA1,   128/8, 440/8> Hash_SHA1_DRBG;
+// typedef Hash_DRBG<SHA256, 128/8, 440/8> Hash_SHA256_DRBG;
+// typedef Hash_DRBG<SHA384, 256/8, 888/8> Hash_SHA384_DRBG;
+// typedef Hash_DRBG<SHA512, 256/8, 888/8> Hash_SHA512_DRBG;
+
+// *************************************************************
+
+/// \tparam HASH NIST approved hash derived from HashTransformation
+/// \tparam STRENGTH security strength, in bytes
+/// \tparam SEEDLENGTH seed length, in bytes
+/// \brief HMAC_DRBG from SP 800-90A Rev 1 (June 2015)
+/// \details The NIST HMAC DRBG is instantiated with a number of parameters. Two of the parameters,
+///  Security Strength and Seed Length, depend on the hash and are specified as template parameters.
+///  The remaining parameters are included in the class. The parameters and their values are listed
+///  in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38).
+/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 2<sup>48</sup> requests
+///  before a reseed. However, HMAC_DRBG limits it to <tt>INT_MAX</tt> due to the limited data range of an int.
+/// \details You should reseed the generator after a fork() to avoid multiple generators
+///  with the same internal state.
+/// \sa <A HREF="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">Recommendation
+///  for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)</A>
+/// \since Crypto++ 6.0
+template <typename HASH=SHA256, unsigned int STRENGTH=128/8, unsigned int SEEDLENGTH=440/8>
+class HMAC_DRBG : public NIST_DRBG, public NotCopyable
+{
+public:
+    CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH);
+    CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH);
+    CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH);
+    CRYPTOPP_CONSTANT(MINIMUM_NONCE=0);
+    CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0);
+    CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0);
+    CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX);
+    CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536);
+    CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX);
+
+    static std::string StaticAlgorithmName() { return std::string("HMAC_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); }
+
+    /// \brief Construct a HMAC DRBG
+    /// \param entropy the entropy to instantiate the generator
+    /// \param entropyLength the size of the entropy buffer
+    /// \param nonce additional input to instantiate the generator
+    /// \param nonceLength the size of the nonce buffer
+    /// \param personalization additional input to instantiate the generator
+    /// \param personalizationLength the size of the personalization buffer
+    /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy
+    /// \details All NIST DRBGs must be instaniated with at least <tt>MINIMUM_ENTROPY</tt> bytes of entropy.
+    ///  The byte array for <tt>entropy</tt> must meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST
+    ///  SP 800-90B or SP 800-90C</A> requirements.
+    /// \details The <tt>nonce</tt> and <tt>personalization</tt> are optional byte arrays. If <tt>nonce</tt> is supplied,
+    ///  then it should be at least <tt>MINIMUM_NONCE</tt> bytes of entropy.
+    /// \details An example of instantiating a SHA256 generator is shown below.
+    ///  The example provides more entropy than required for SHA256. The <tt>NonblockingRng</tt> meets the
+    ///  requirements of <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or SP 800-90C</A>.
+    ///  RDRAND() and RDSEED() generators would work as well.
+    /// <pre>
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   HMAC_DRBG<SHA256, 128/8, 440/8> drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// </pre>
+    HMAC_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
+        size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0)
+        : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE), m_reseed(0)
+    {
+        if (m_k.data())  // GCC analyzer warning
+            std::memset(m_k, 0x00, m_k.size());
+        if (m_v.data())  // GCC analyzer warning
+            std::memset(m_v, 0x00, m_v.size());
+
+        if (entropy != NULLPTR && entropyLength != 0)
+            DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+    }
+
+    unsigned int SecurityStrength() const {return SECURITY_STRENGTH;}
+    unsigned int SeedLength() const {return SEED_LENGTH;}
+    unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;}
+    unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;}
+    unsigned int MinNonceLength() const {return MINIMUM_NONCE;}
+    unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;}
+    unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;}
+    unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;}
+
+    void IncorporateEntropy(const byte *input, size_t length)
+        {return DRBG_Reseed(input, length, NULLPTR, 0);}
+
+    void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+        {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);}
+
+    void GenerateBlock(byte *output, size_t size)
+        {return HMAC_Generate(NULLPTR, 0, output, size);}
+
+    void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)
+        {return HMAC_Generate(additional, additionaLength, output, size);}
+
+    std::string AlgorithmProvider() const
+        {/*Hack*/HASH hash; return hash.AlgorithmProvider();}
+
+protected:
+    // 10.1.2.3 Instantiation of HMAC_DRBG (p.45)
+    void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+        const byte* personalization, size_t personalizationLength);
+
+    // 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46)
+    void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength);
+
+    // 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46)
+    void HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size);
+
+    // 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44)
+    void HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3);
+
+private:
+    HMAC<HASH> m_hmac;
+    SecByteBlock m_k, m_v;
+    word64 m_reseed;
+};
+
+// typedef HMAC_DRBG<SHA1,   128/8, 440/8> HMAC_SHA1_DRBG;
+// typedef HMAC_DRBG<SHA256, 128/8, 440/8> HMAC_SHA256_DRBG;
+// typedef HMAC_DRBG<SHA384, 256/8, 888/8> HMAC_SHA384_DRBG;
+// typedef HMAC_DRBG<SHA512, 256/8, 888/8> HMAC_SHA512_DRBG;
+
+// *************************************************************
+
+// 10.1.1.2 Instantiation of Hash_DRBG (p.39)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void Hash_DRBG<HASH, STRENGTH, SEEDLENGTH>::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+    const byte* personalization, size_t personalizationLength)
+{
+    //  SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+    //  strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+    //  personalization string during instantiation, or in the additional input during reseeding and generation,
+    //  but this is not required and does not increase the "official" security strength of the DRBG
+    //  instantiation that is recorded in the internal state.
+    CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+    if (entropyLength < MINIMUM_ENTROPY)
+        throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+    CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE);
+    CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION);
+
+    const byte zero = 0;
+    SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
+    Hash_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULLPTR, 0, t1, t1.size());
+    Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size());
+
+    m_v.swap(t1); m_c.swap(t2);
+    m_reseed = 1;
+}
+
+// 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void Hash_DRBG<HASH, STRENGTH, SEEDLENGTH>::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+{
+    //  SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+    //  strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+    //  personalization string during instantiation, or in the additional input during reseeding and generation,
+    //  but this is not required and does not increase the "official" security strength of the DRBG
+    //  instantiation that is recorded in the internal state..
+    CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+    if (entropyLength < MINIMUM_ENTROPY)
+        throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+    CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+    const byte zero = 0, one = 1;
+    SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
+    Hash_Update(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size());
+    Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size());
+
+    m_v.swap(t1); m_c.swap(t2);
+    m_reseed = 1;
+}
+
+// 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void Hash_DRBG<HASH, STRENGTH, SEEDLENGTH>::Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size)
+{
+    // Step 1
+    if (static_cast<word64>(m_reseed) >= static_cast<word64>(MaxRequestBeforeReseed()))
+        throw NIST_DRBG::Err("Hash_DRBG", "Reseed required");
+
+    if (size > MaxBytesPerRequest())
+        throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+    // Step 2
+    if (additional && additionaLength)
+    {
+        const byte two = 2;
+        m_temp.New(HASH::DIGESTSIZE);
+
+        m_hash.Update(&two, 1);
+        m_hash.Update(m_v, m_v.size());
+        m_hash.Update(additional, additionaLength);
+        m_hash.Final(m_temp);
+
+        CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
+        int carry=0, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1;
+        while (j>=0)
+        {
+            carry = m_v[i] + m_temp[j] + carry;
+            m_v[i] = static_cast<byte>(carry);
+            i--; j--; carry >>= 8;
+        }
+        while (i>=0)
+        {
+            carry = m_v[i] + carry;
+            m_v[i] = static_cast<byte>(carry);
+            i--; carry >>= 8;
+        }
+    }
+
+    // Step 3
+    {
+        m_temp.Assign(m_v);
+        while (size)
+        {
+            m_hash.Update(m_temp, m_temp.size());
+            size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE);
+            m_hash.TruncatedFinal(output, count);
+
+            IncrementCounterByOne(m_temp, static_cast<unsigned int>(m_temp.size()));
+            size -= count; output += count;
+        }
+    }
+
+    // Steps 4-7
+    {
+        const byte three = 3;
+        m_temp.New(HASH::DIGESTSIZE);
+
+        m_hash.Update(&three, 1);
+        m_hash.Update(m_v, m_v.size());
+        m_hash.Final(m_temp);
+
+        CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
+        CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed));
+        int carry=0, k=sizeof(m_reseed)-1, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1;
+
+        while (k>=0)
+        {
+            carry = m_v[i] + m_c[i] + m_temp[j] + GetByte<word64>(BIG_ENDIAN_ORDER, m_reseed, k) + carry;
+            m_v[i] = static_cast<byte>(carry);
+            i--; j--; k--; carry >>= 8;
+        }
+
+        while (j>=0)
+        {
+            carry = m_v[i] + m_c[i] + m_temp[j] + carry;
+            m_v[i] = static_cast<byte>(carry);
+            i--; j--; carry >>= 8;
+        }
+
+        while (i>=0)
+        {
+            carry = m_v[i] + m_c[i] + carry;
+            m_v[i] = static_cast<byte>(carry);
+            i--; carry >>= 8;
+        }
+    }
+
+    m_reseed++;
+}
+
+// 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void Hash_DRBG<HASH, STRENGTH, SEEDLENGTH>::Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2,
+    const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen)
+{
+    byte counter = 1;
+    word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast<word32>(outlen*8));
+
+    while (outlen)
+    {
+        m_hash.Update(&counter, 1);
+        m_hash.Update(reinterpret_cast<const byte*>(&bits), 4);
+
+        if (input1 && inlen1)
+            m_hash.Update(input1, inlen1);
+        if (input2 && inlen2)
+            m_hash.Update(input2, inlen2);
+        if (input3 && inlen3)
+            m_hash.Update(input3, inlen3);
+        if (input4 && inlen4)
+            m_hash.Update(input4, inlen4);
+
+        size_t count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE);
+        m_hash.TruncatedFinal(output, count);
+
+        output += count; outlen -= count;
+        counter++;
+    }
+}
+
+// *************************************************************
+
+// 10.1.2.3 Instantiation of HMAC_DRBG (p.45)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void HMAC_DRBG<HASH, STRENGTH, SEEDLENGTH>::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+    const byte* personalization, size_t personalizationLength)
+{
+    //  SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+    //  strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+    //  personalization string during instantiation, or in the additional input during reseeding and generation,
+    //  but this is not required and does not increase the "official" security strength of the DRBG
+    //  instantiation that is recorded in the internal state.
+    CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+    if (entropyLength < MINIMUM_ENTROPY)
+        throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during instantiate");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+    CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE);
+    CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION);
+
+    std::fill(m_k.begin(), m_k.begin()+m_k.size(), byte(0));
+    std::fill(m_v.begin(), m_v.begin()+m_v.size(), byte(1));
+
+    HMAC_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+    m_reseed = 1;
+}
+
+// 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void HMAC_DRBG<HASH, STRENGTH, SEEDLENGTH>::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+{
+    //  SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+    //  strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+    //  personalization string during instantiation, or in the additional input during reseeding and generation,
+    //  but this is not required and does not increase the "official" security strength of the DRBG
+    //  instantiation that is recorded in the internal state..
+    CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+    if (entropyLength < MINIMUM_ENTROPY)
+        throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during reseed");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+    CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+    HMAC_Update(entropy, entropyLength, additional, additionaLength, NULLPTR, 0);
+    m_reseed = 1;
+}
+
+// 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void HMAC_DRBG<HASH, STRENGTH, SEEDLENGTH>::HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size)
+{
+    // Step 1
+    if (static_cast<word64>(m_reseed) >= static_cast<word64>(MaxRequestBeforeReseed()))
+        throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required");
+
+    if (size > MaxBytesPerRequest())
+        throw NIST_DRBG::Err("HMAC_DRBG", "Request size exceeds limit");
+
+    // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+    // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+    CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+    // Step 2
+    if (additional && additionaLength)
+        HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0);
+
+    // Step 3
+    m_hmac.SetKey(m_k, m_k.size());
+
+    while (size)
+    {
+        m_hmac.Update(m_v, m_v.size());
+        m_hmac.TruncatedFinal(m_v, m_v.size());
+
+        size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE);
+        std::memcpy(output, m_v, count);
+        size -= count; output += count;
+    }
+
+    HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0);
+    m_reseed++;
+}
+
+// 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44)
+template <typename HASH, unsigned int STRENGTH, unsigned int SEEDLENGTH>
+void HMAC_DRBG<HASH, STRENGTH, SEEDLENGTH>::HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3)
+{
+    const byte zero = 0, one = 1;
+
+    // Step 1
+    m_hmac.SetKey(m_k, m_k.size());
+    m_hmac.Update(m_v, m_v.size());
+    m_hmac.Update(&zero, 1);
+
+    if (input1 && inlen1)
+        m_hmac.Update(input1, inlen1);
+    if (input2 && inlen2)
+        m_hmac.Update(input2, inlen2);
+    if (input3 && inlen3)
+        m_hmac.Update(input3, inlen3);
+
+    m_hmac.TruncatedFinal(m_k, m_k.size());
+
+    // Step 2
+    m_hmac.SetKey(m_k, m_k.size());
+    m_hmac.Update(m_v, m_v.size());
+
+    m_hmac.TruncatedFinal(m_v, m_v.size());
+
+    // Step 3
+    if ((inlen1 | inlen2 | inlen3) == 0)
+        return;
+
+    // Step 4
+    m_hmac.SetKey(m_k, m_k.size());
+    m_hmac.Update(m_v, m_v.size());
+    m_hmac.Update(&one, 1);
+
+    if (input1 && inlen1)
+        m_hmac.Update(input1, inlen1);
+    if (input2 && inlen2)
+        m_hmac.Update(input2, inlen2);
+    if (input3 && inlen3)
+        m_hmac.Update(input3, inlen3);
+
+    m_hmac.TruncatedFinal(m_k, m_k.size());
+
+    // Step 5
+    m_hmac.SetKey(m_k, m_k.size());
+    m_hmac.Update(m_v, m_v.size());
+
+    m_hmac.TruncatedFinal(m_v, m_v.size());
+}
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_NIST_DRBG_H

+ 53 - 0
cryptopp/dsa.h

@@ -0,0 +1,53 @@
+// dsa.h - originally written and placed in the public domain by Wei Dai
+
+/// \file dsa.h
+/// \brief Classes for the DSA signature algorithm
+
+#ifndef CRYPTOPP_DSA_H
+#define CRYPTOPP_DSA_H
+
+#include "cryptlib.h"
+#include "gfpcrypt.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief DSA Signature Format
+/// \details The DSA signature format used by Crypto++ is as defined by IEEE P1363.
+///  OpenSSL, Java and .Net use the DER format, and OpenPGP uses the OpenPGP format.
+/// \sa <A HREF="http://www.cryptopp.com/wiki/DSAConvertSignatureFormat">DSAConvertSignatureFormat</A>
+///  on the Crypto++ wiki.
+/// \since Crypto++ 1.0
+enum DSASignatureFormat {
+	/// \brief Crypto++ native signature encoding format
+	DSA_P1363,
+	/// \brief signature encoding format used by OpenSSL, Java and .Net
+	DSA_DER,
+	/// \brief OpenPGP signature encoding format
+	DSA_OPENPGP
+};
+
+/// \brief Converts between signature encoding formats
+/// \param buffer byte buffer for the converted signature encoding
+/// \param bufferSize the length of the converted signature encoding buffer
+/// \param toFormat the source signature format
+/// \param signature byte buffer for the existing signature encoding
+/// \param signatureLen the length of the existing signature encoding buffer
+/// \param fromFormat the source signature format
+/// \return the number of bytes written during encoding
+/// \details This function converts between these formats, and returns length
+///  of signature in the target format. If <tt>toFormat == DSA_P1363</tt>, then
+///  <tt>bufferSize</tt> must equal <tt>publicKey.SignatureLength()</tt> or
+///  <tt>verifier.SignatureLength()</tt>.
+/// \details If the destination buffer is too small then the output of the
+///  encoded <tt>r</tt> and <tt>s</tt> will be truncated. Be sure to provide
+///  an adequately sized buffer and check the return value for the number of
+///  bytes written.
+/// \sa <A HREF="http://www.cryptopp.com/wiki/DSAConvertSignatureFormat">DSAConvertSignatureFormat</A>
+///  on the Crypto++ wiki.
+/// \since Crypto++ 1.0
+size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFormat toFormat,
+	const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat);
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_DSA_H

+ 112 - 0
cryptopp/eax.h

@@ -0,0 +1,112 @@
+// eax.h - originally written and placed in the public domain by Wei Dai
+
+/// \file eax.h
+/// \brief EAX block cipher mode of operation
+
+#ifndef CRYPTOPP_EAX_H
+#define CRYPTOPP_EAX_H
+
+#include "authenc.h"
+#include "modes.h"
+#include "cmac.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief EAX block cipher base implementation
+/// \details Base implementation of the AuthenticatedSymmetricCipher interface
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase
+{
+public:
+	// AuthenticatedSymmetricCipher
+	std::string AlgorithmName() const
+		{return GetMAC().GetCipher().AlgorithmName() + std::string("/EAX");}
+	std::string AlgorithmProvider() const
+		{return GetMAC().GetCipher().AlgorithmProvider();}
+	size_t MinKeyLength() const
+		{return GetMAC().MinKeyLength();}
+	size_t MaxKeyLength() const
+		{return GetMAC().MaxKeyLength();}
+	size_t DefaultKeyLength() const
+		{return GetMAC().DefaultKeyLength();}
+	size_t GetValidKeyLength(size_t n) const
+		{return GetMAC().GetValidKeyLength(n);}
+	bool IsValidKeyLength(size_t n) const
+		{return GetMAC().IsValidKeyLength(n);}
+	unsigned int OptimalDataAlignment() const
+		{return GetMAC().OptimalDataAlignment();}
+	IV_Requirement IVRequirement() const
+		{return UNIQUE_IV;}
+	unsigned int IVSize() const
+		{return GetMAC().TagSize();}
+	unsigned int MinIVLength() const
+		{return 0;}
+	unsigned int MaxIVLength() const
+		{return UINT_MAX;}
+	unsigned int DigestSize() const
+		{return GetMAC().TagSize();}
+	lword MaxHeaderLength() const
+		{return LWORD_MAX;}
+	lword MaxMessageLength() const
+		{return LWORD_MAX;}
+
+protected:
+	// AuthenticatedSymmetricCipherBase
+	bool AuthenticationIsOnPlaintext() const
+		{return false;}
+	unsigned int AuthenticationBlockSize() const
+		{return 1;}
+	void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Resync(const byte *iv, size_t len);
+	size_t AuthenticateBlocks(const byte *data, size_t len);
+	void AuthenticateLastHeaderBlock();
+	void AuthenticateLastFooterBlock(byte *mac, size_t macSize);
+	SymmetricCipher & AccessSymmetricCipher() {return m_ctr;}
+	const CMAC_Base & GetMAC() const {return const_cast<EAX_Base *>(this)->AccessMAC();}
+	virtual CMAC_Base & AccessMAC() =0;
+
+	CTR_Mode_ExternalCipher::Encryption m_ctr;
+};
+
+/// \brief EAX block cipher final implementation
+/// \tparam T_BlockCipher block cipher
+/// \tparam T_IsEncryption direction in which to operate the cipher
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher, bool T_IsEncryption>
+class EAX_Final : public EAX_Base
+{
+public:
+	static std::string StaticAlgorithmName()
+		{return T_BlockCipher::StaticAlgorithmName() + std::string("/EAX");}
+	std::string AlgorithmProvider() const
+		{return m_cmac.AlgorithmProvider();}
+	bool IsForwardTransformation() const
+		{return T_IsEncryption;}
+
+private:
+	CMAC_Base & AccessMAC() {return m_cmac;}
+	CMAC<T_BlockCipher> m_cmac;
+};
+
+#ifdef EAX	// EAX is defined to 11 on GCC 3.4.3, OpenSolaris 8.11
+#undef EAX
+#endif
+
+/// \brief EAX block cipher mode of operation
+/// \tparam T_BlockCipher block cipher
+/// \details \p EAX provides the \p Encryption and \p Decryption typedef. See EAX_Base
+///   and EAX_Final for the AuthenticatedSymmetricCipher implementation.
+/// \sa <a href="http://www.cryptopp.com/wiki/EAX_Mode">EAX Mode</a> and
+///   <A HREF="http://www.cryptopp.com/wiki/Modes_of_Operation">Modes of Operation</A>
+///   on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher>
+struct EAX : public AuthenticatedSymmetricCipherDocumentation
+{
+	typedef EAX_Final<T_BlockCipher, true> Encryption;
+	typedef EAX_Final<T_BlockCipher, false> Decryption;
+};
+
+NAMESPACE_END
+
+#endif

+ 136 - 0
cryptopp/ec2n.h

@@ -0,0 +1,136 @@
+// ec2n.h - originally written and placed in the public domain by Wei Dai
+
+/// \file ec2n.h
+/// \brief Classes for Elliptic Curves over binary fields
+
+#ifndef CRYPTOPP_EC2N_H
+#define CRYPTOPP_EC2N_H
+
+#include "cryptlib.h"
+#include "gf2n.h"
+#include "integer.h"
+#include "algebra.h"
+#include "ecpoint.h"
+#include "eprecomp.h"
+#include "smartptr.h"
+#include "pubkey.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4231 4275)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Elliptic Curve over GF(2^n)
+class CRYPTOPP_DLL EC2N : public AbstractGroup<EC2NPoint>, public EncodedPoint<EC2NPoint>
+{
+public:
+	typedef GF2NP Field;
+	typedef Field::Element FieldElement;
+	typedef EC2NPoint Point;
+
+	virtual ~EC2N() {}
+
+	/// \brief Construct an EC2N
+	EC2N() {}
+
+	/// \brief Construct an EC2N
+	/// \param field Field, GF2NP derived class
+	/// \param a Field::Element
+	/// \param b Field::Element
+	EC2N(const Field &field, const Field::Element &a, const Field::Element &b)
+		: m_field(field), m_a(a), m_b(b) {}
+
+	/// \brief Construct an EC2N from BER encoded parameters
+	/// \param bt BufferedTransformation derived object
+	/// \details This constructor will decode and extract the fields fieldID and curve of the sequence ECParameters
+	EC2N(BufferedTransformation &bt);
+
+	/// \brief Encode the fields fieldID and curve of the sequence ECParameters
+	/// \param bt BufferedTransformation derived object
+	void DEREncode(BufferedTransformation &bt) const;
+
+	bool Equal(const Point &P, const Point &Q) const;
+	const Point& Identity() const;
+	const Point& Inverse(const Point &P) const;
+	bool InversionIsFast() const {return true;}
+	const Point& Add(const Point &P, const Point &Q) const;
+	const Point& Double(const Point &P) const;
+
+	Point Multiply(const Integer &k, const Point &P) const
+		{return ScalarMultiply(P, k);}
+	Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const
+		{return CascadeScalarMultiply(P, k1, Q, k2);}
+
+	bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const;
+	bool VerifyPoint(const Point &P) const;
+
+	unsigned int EncodedPointSize(bool compressed = false) const
+		{return 1 + (compressed?1:2)*m_field->MaxElementByteLength();}
+	// returns false if point is compressed and not valid (doesn't check if uncompressed)
+	bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const;
+	bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const;
+	void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const;
+	void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
+
+	Point BERDecodePoint(BufferedTransformation &bt) const;
+	void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
+
+	Integer FieldSize() const {return Integer::Power2(m_field->MaxElementBitLength());}
+	const Field & GetField() const {return *m_field;}
+	const FieldElement & GetA() const {return m_a;}
+	const FieldElement & GetB() const {return m_b;}
+
+	bool operator==(const EC2N &rhs) const
+		{return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;}
+
+private:
+	clonable_ptr<Field> m_field;
+	FieldElement m_a, m_b;
+	mutable Point m_R;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl<EC2N::Point>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation<EC2N::Point>;
+
+/// \brief Elliptic Curve precomputation
+/// \tparam EC elliptic curve field
+template <class EC> class EcPrecomputation;
+
+/// \brief EC2N precomputation specialization
+/// \details Implementation of <tt>DL_GroupPrecomputation<EC2N::Point></tt>
+/// \sa DL_GroupPrecomputation
+template<> class EcPrecomputation<EC2N> : public DL_GroupPrecomputation<EC2N::Point>
+{
+public:
+	typedef EC2N EllipticCurve;
+
+	virtual ~EcPrecomputation() {}
+
+	// DL_GroupPrecomputation
+	const AbstractGroup<Element> & GetGroup() const {return m_ec;}
+	Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec.BERDecodePoint(bt);}
+	void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec.DEREncodePoint(bt, v, false);}
+
+	/// \brief Set the elliptic curve
+	/// \param ec ECP derived class
+	/// \details SetCurve() is not inherited
+	void SetCurve(const EC2N &ec) {m_ec = ec;}
+
+	/// \brief Get the elliptic curve
+	/// \return EC2N curve
+	/// \details GetCurve() is not inherited
+	const EC2N & GetCurve() const {return m_ec;}
+
+private:
+	EC2N m_ec;
+};
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 686 - 0
cryptopp/eccrypto.h

@@ -0,0 +1,686 @@
+// eccrypto.h - originally written and placed in the public domain by Wei Dai
+//              deterministic signatures added by by Douglas Roark
+
+/// \file eccrypto.h
+/// \brief Classes and functions for Elliptic Curves over prime and binary fields
+
+#ifndef CRYPTOPP_ECCRYPTO_H
+#define CRYPTOPP_ECCRYPTO_H
+
+#include "config.h"
+#include "cryptlib.h"
+#include "pubkey.h"
+#include "integer.h"
+#include "asn.h"
+#include "hmac.h"
+#include "sha.h"
+#include "gfpcrypt.h"
+#include "dh.h"
+#include "mqv.h"
+#include "hmqv.h"
+#include "fhmqv.h"
+#include "ecp.h"
+#include "ec2n.h"
+
+#include <iosfwd>
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4231 4275)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Elliptic Curve Parameters
+/// \tparam EC elliptic curve field
+/// \details This class corresponds to the ASN.1 sequence of the same name
+///  in ANSI X9.62 and SEC 1. EC is currently defined for ECP and EC2N.
+template <class EC>
+class DL_GroupParameters_EC : public DL_GroupParametersImpl<EcPrecomputation<EC> >
+{
+	typedef DL_GroupParameters_EC<EC> ThisClass;
+
+public:
+	typedef EC EllipticCurve;
+	typedef typename EllipticCurve::Point Point;
+	typedef Point Element;
+	typedef IncompatibleCofactorMultiplication DefaultCofactorOption;
+
+	virtual ~DL_GroupParameters_EC() {}
+
+	/// \brief Construct an EC GroupParameters
+	DL_GroupParameters_EC() : m_compress(false), m_encodeAsOID(true) {}
+
+	/// \brief Construct an EC GroupParameters
+	/// \param oid the OID of a curve
+	DL_GroupParameters_EC(const OID &oid)
+		: m_compress(false), m_encodeAsOID(true) {Initialize(oid);}
+
+	/// \brief Construct an EC GroupParameters
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param k the cofactor
+	DL_GroupParameters_EC(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero())
+		: m_compress(false), m_encodeAsOID(true) {Initialize(ec, G, n, k);}
+
+	/// \brief Construct an EC GroupParameters
+	/// \param bt BufferedTransformation with group parameters
+	DL_GroupParameters_EC(BufferedTransformation &bt)
+		: m_compress(false), m_encodeAsOID(true) {BERDecode(bt);}
+
+	/// \brief Initialize an EC GroupParameters using {EC,G,n,k}
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param k the cofactor
+	/// \details This Initialize() function overload initializes group parameters from existing parameters.
+	void Initialize(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero())
+	{
+		this->m_groupPrecomputation.SetCurve(ec);
+		this->SetSubgroupGenerator(G);
+		m_n = n;
+		m_k = k;
+	}
+
+	/// \brief Initialize a DL_GroupParameters_EC {EC,G,n,k}
+	/// \param oid the OID of a curve
+	/// \details This Initialize() function overload initializes group parameters from existing parameters.
+	void Initialize(const OID &oid);
+
+	// NameValuePairs
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+	void AssignFrom(const NameValuePairs &source);
+
+	// GeneratibleCryptoMaterial interface
+	/// this implementation doesn't actually generate a curve, it just initializes the parameters with existing values
+	/*! parameters: (Curve, SubgroupGenerator, SubgroupOrder, Cofactor (optional)), or (GroupOID) */
+	void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
+
+	// DL_GroupParameters
+	const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const {return this->m_gpc;}
+	DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() {return this->m_gpc;}
+	const Integer & GetSubgroupOrder() const {return m_n;}
+	Integer GetCofactor() const;
+	bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const;
+	bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation<Element> *precomp) const;
+	bool FastSubgroupCheckAvailable() const {return false;}
+	void EncodeElement(bool reversible, const Element &element, byte *encoded) const
+	{
+		if (reversible)
+			GetCurve().EncodePoint(encoded, element, m_compress);
+		else
+			element.x.Encode(encoded, GetEncodedElementSize(false));
+	}
+	virtual unsigned int GetEncodedElementSize(bool reversible) const
+	{
+		if (reversible)
+			return GetCurve().EncodedPointSize(m_compress);
+		else
+			return GetCurve().GetField().MaxElementByteLength();
+	}
+	Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const
+	{
+		Point result;
+		if (!GetCurve().DecodePoint(result, encoded, GetEncodedElementSize(true)))
+			throw DL_BadElement();
+		if (checkForGroupMembership && !ValidateElement(1, result, NULLPTR))
+			throw DL_BadElement();
+		return result;
+	}
+	Integer ConvertElementToInteger(const Element &element) const;
+	Integer GetMaxExponent() const {return GetSubgroupOrder()-1;}
+	bool IsIdentity(const Element &element) const {return element.identity;}
+	void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
+	static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "EC";}
+
+	// ASN1Key
+	OID GetAlgorithmID() const;
+
+	// used by MQV
+	Element MultiplyElements(const Element &a, const Element &b) const;
+	Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const;
+
+	// non-inherited
+
+	// enumerate OIDs for recommended parameters, use OID() to get first one
+	static OID CRYPTOPP_API GetNextRecommendedParametersOID(const OID &oid);
+
+	void BERDecode(BufferedTransformation &bt);
+	void DEREncode(BufferedTransformation &bt) const;
+
+	void SetPointCompression(bool compress) {m_compress = compress;}
+	bool GetPointCompression() const {return m_compress;}
+
+	void SetEncodeAsOID(bool encodeAsOID) {m_encodeAsOID = encodeAsOID;}
+	bool GetEncodeAsOID() const {return m_encodeAsOID;}
+
+	const EllipticCurve& GetCurve() const {return this->m_groupPrecomputation.GetCurve();}
+
+	bool operator==(const ThisClass &rhs) const
+		{return this->m_groupPrecomputation.GetCurve() == rhs.m_groupPrecomputation.GetCurve() && this->m_gpc.GetBase(this->m_groupPrecomputation) == rhs.m_gpc.GetBase(rhs.m_groupPrecomputation);}
+
+protected:
+	unsigned int FieldElementLength() const {return GetCurve().GetField().MaxElementByteLength();}
+	unsigned int ExponentLength() const {return m_n.ByteCount();}
+
+	OID m_oid;			// set if parameters loaded from a recommended curve
+	Integer m_n;		// order of base point
+	mutable Integer m_k;		// cofactor
+	mutable bool m_compress, m_encodeAsOID;		// presentation details
+};
+
+inline std::ostream& operator<<(std::ostream& os, const DL_GroupParameters_EC<ECP>::Element& obj);
+
+/// \brief Elliptic Curve Discrete Log (DL) public key
+/// \tparam EC elliptic curve field
+template <class EC>
+class DL_PublicKey_EC : public DL_PublicKeyImpl<DL_GroupParameters_EC<EC> >
+{
+public:
+	typedef typename EC::Point Element;
+
+	virtual ~DL_PublicKey_EC() {}
+
+	/// \brief Initialize an EC Public Key using {GP,Q}
+	/// \param params group parameters
+	/// \param Q the public point
+	/// \details This Initialize() function overload initializes a public key from existing parameters.
+	void Initialize(const DL_GroupParameters_EC<EC> &params, const Element &Q)
+		{this->AccessGroupParameters() = params; this->SetPublicElement(Q);}
+
+	/// \brief Initialize an EC Public Key using {EC,G,n,Q}
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param Q the public point
+	/// \details This Initialize() function overload initializes a public key from existing parameters.
+	void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q)
+		{this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);}
+
+	// X509PublicKey
+	void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size);
+	void DEREncodePublicKey(BufferedTransformation &bt) const;
+};
+
+/// \brief Elliptic Curve Discrete Log (DL) private key
+/// \tparam EC elliptic curve field
+template <class EC>
+class DL_PrivateKey_EC : public DL_PrivateKeyImpl<DL_GroupParameters_EC<EC> >
+{
+public:
+	typedef typename EC::Point Element;
+
+	virtual ~DL_PrivateKey_EC();
+
+	/// \brief Initialize an EC Private Key using {GP,x}
+	/// \param params group parameters
+	/// \param x the private exponent
+	/// \details This Initialize() function overload initializes a private key from existing parameters.
+	void Initialize(const DL_GroupParameters_EC<EC> &params, const Integer &x)
+		{this->AccessGroupParameters() = params; this->SetPrivateExponent(x);}
+
+	/// \brief Initialize an EC Private Key using {EC,G,n,x}
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param x the private exponent
+	/// \details This Initialize() function overload initializes a private key from existing parameters.
+	void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x)
+		{this->AccessGroupParameters().Initialize(ec, G, n); this->SetPrivateExponent(x);}
+
+	/// \brief Create an EC private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param params the EC group parameters
+	/// \details This function overload of Initialize() creates a new private key because it
+	///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+	///  then use one of the other Initialize() overloads.
+	void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC<EC> &params)
+		{this->GenerateRandom(rng, params);}
+
+	/// \brief Create an EC private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \details This function overload of Initialize() creates a new private key because it
+	///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+	///  then use one of the other Initialize() overloads.
+	void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n)
+		{this->GenerateRandom(rng, DL_GroupParameters_EC<EC>(ec, G, n));}
+
+	// PKCS8PrivateKey
+	void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size);
+	void DEREncodePrivateKey(BufferedTransformation &bt) const;
+};
+
+// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499
+template<class EC>
+DL_PrivateKey_EC<EC>::~DL_PrivateKey_EC() {}
+
+/// \brief Elliptic Curve Diffie-Hellman
+/// \tparam EC elliptic curve field
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \sa CofactorMultiplicationOption, <a href="http://www.weidai.com/scan-mirror/ka.html#ECDH">Elliptic Curve Diffie-Hellman, AKA ECDH</a>
+/// \since Crypto++ 3.0
+template <class EC, class COFACTOR_OPTION = typename DL_GroupParameters_EC<EC>::DefaultCofactorOption>
+struct ECDH
+{
+	typedef DH_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION> Domain;
+};
+
+/// \brief Elliptic Curve Menezes-Qu-Vanstone
+/// \tparam EC elliptic curve field
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \sa CofactorMultiplicationOption, <a href="http://www.weidai.com/scan-mirror/ka.html#ECMQV">Elliptic Curve Menezes-Qu-Vanstone, AKA ECMQV</a>
+template <class EC, class COFACTOR_OPTION = typename DL_GroupParameters_EC<EC>::DefaultCofactorOption>
+struct ECMQV
+{
+	typedef MQV_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION> Domain;
+};
+
+/// \brief Hashed Elliptic Curve Menezes-Qu-Vanstone
+/// \tparam EC elliptic curve field
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
+///  Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
+/// \sa CofactorMultiplicationOption
+template <class EC, class COFACTOR_OPTION = typename DL_GroupParameters_EC<EC>::DefaultCofactorOption, class HASH = SHA256>
+struct ECHMQV
+{
+	typedef HMQV_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION, HASH> Domain;
+};
+
+typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption,   SHA1 >::Domain ECHMQV160;
+typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECHMQV256;
+typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECHMQV384;
+typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECHMQV512;
+
+/// \brief Fully Hashed Elliptic Curve Menezes-Qu-Vanstone
+/// \tparam EC elliptic curve field
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
+///  <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
+///  Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
+/// \sa CofactorMultiplicationOption
+template <class EC, class COFACTOR_OPTION = typename DL_GroupParameters_EC<EC>::DefaultCofactorOption, class HASH = SHA256>
+struct ECFHMQV
+{
+	typedef FHMQV_Domain<DL_GroupParameters_EC<EC>, COFACTOR_OPTION, HASH> Domain;
+};
+
+typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption,   SHA1 >::Domain ECFHMQV160;
+typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECFHMQV256;
+typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECFHMQV384;
+typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECFHMQV512;
+
+/// \brief Elliptic Curve Discrete Log (DL) keys
+/// \tparam EC elliptic curve field
+template <class EC>
+struct DL_Keys_EC
+{
+	typedef DL_PublicKey_EC<EC> PublicKey;
+	typedef DL_PrivateKey_EC<EC> PrivateKey;
+};
+
+// Forward declaration; documented below
+template <class EC, class H>
+struct ECDSA;
+
+/// \brief Elliptic Curve DSA keys
+/// \tparam EC elliptic curve field
+/// \since Crypto++ 3.2
+template <class EC>
+struct DL_Keys_ECDSA
+{
+	typedef DL_PublicKey_EC<EC> PublicKey;
+	typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC>, ECDSA<EC, SHA256> > PrivateKey;
+};
+
+/// \brief Elliptic Curve DSA (ECDSA) signature algorithm
+/// \tparam EC elliptic curve field
+/// \since Crypto++ 3.2
+template <class EC>
+class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point>
+{
+public:
+  CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";}
+};
+
+/// \brief Elliptic Curve DSA (ECDSA) signature algorithm based on RFC 6979
+/// \tparam EC elliptic curve field
+/// \sa <a href="http://tools.ietf.org/rfc/rfc6979.txt">RFC 6979, Deterministic Usage of the
+///  Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)</a>
+/// \since Crypto++ 6.0
+template <class EC, class H>
+class DL_Algorithm_ECDSA_RFC6979 : public DL_Algorithm_DSA_RFC6979<typename EC::Point, H>
+{
+public:
+  CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA-RFC6979";}
+};
+
+/// \brief Elliptic Curve NR (ECNR) signature algorithm
+/// \tparam EC elliptic curve field
+template <class EC>
+class DL_Algorithm_ECNR : public DL_Algorithm_NR<typename EC::Point>
+{
+public:
+  CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECNR";}
+};
+
+/// \brief Elliptic Curve DSA (ECDSA) signature scheme
+/// \tparam EC elliptic curve field
+/// \tparam H HashTransformation derived class
+/// \sa <a href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a>
+/// \since Crypto++ 3.2
+template <class EC, class H>
+struct ECDSA : public DL_SS<DL_Keys_ECDSA<EC>, DL_Algorithm_ECDSA<EC>, DL_SignatureMessageEncodingMethod_DSA, H>
+{
+};
+
+/// \brief Elliptic Curve DSA (ECDSA) deterministic signature scheme
+/// \tparam EC elliptic curve field
+/// \tparam H HashTransformation derived class
+/// \sa <a href="http://tools.ietf.org/rfc/rfc6979.txt">Deterministic Usage of the
+///  Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)</a>
+/// \since Crypto++ 6.0
+template <class EC, class H>
+struct ECDSA_RFC6979 : public DL_SS<
+	DL_Keys_ECDSA<EC>,
+	DL_Algorithm_ECDSA_RFC6979<EC, H>,
+	DL_SignatureMessageEncodingMethod_DSA,
+	H,
+	ECDSA_RFC6979<EC,H> >
+{
+	static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECDSA-RFC6979/") + H::StaticAlgorithmName();}
+};
+
+/// \brief Elliptic Curve NR (ECNR) signature scheme
+/// \tparam EC elliptic curve field
+/// \tparam H HashTransformation derived class
+template <class EC, class H = SHA1>
+struct ECNR : public DL_SS<DL_Keys_EC<EC>, DL_Algorithm_ECNR<EC>, DL_SignatureMessageEncodingMethod_NR, H>
+{
+};
+
+// ******************************************
+
+template <class EC>
+class DL_PublicKey_ECGDSA;
+template <class EC>
+class DL_PrivateKey_ECGDSA;
+
+/// \brief Elliptic Curve German DSA key for ISO/IEC 15946
+/// \tparam EC elliptic curve field
+/// \sa ECGDSA
+/// \since Crypto++ 6.0
+template <class EC>
+class DL_PrivateKey_ECGDSA : public DL_PrivateKeyImpl<DL_GroupParameters_EC<EC> >
+{
+public:
+	typedef typename EC::Point Element;
+
+	virtual ~DL_PrivateKey_ECGDSA() {}
+
+	/// \brief Initialize an EC Private Key using {GP,x}
+	/// \param params group parameters
+	/// \param x the private exponent
+	/// \details This Initialize() function overload initializes a private key from existing parameters.
+	void Initialize(const DL_GroupParameters_EC<EC> &params, const Integer &x)
+	{
+		this->AccessGroupParameters() = params;
+		this->SetPrivateExponent(x);
+		CRYPTOPP_ASSERT(x>=1 && x<=params.GetSubgroupOrder()-1);
+	}
+
+	/// \brief Initialize an EC Private Key using {EC,G,n,x}
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param x the private exponent
+	/// \details This Initialize() function overload initializes a private key from existing parameters.
+	void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x)
+	{
+		this->AccessGroupParameters().Initialize(ec, G, n);
+		this->SetPrivateExponent(x);
+		CRYPTOPP_ASSERT(x>=1 && x<=this->AccessGroupParameters().GetSubgroupOrder()-1);
+	}
+
+	/// \brief Create an EC private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param params the EC group parameters
+	/// \details This function overload of Initialize() creates a new private key because it
+	///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+	///  then use one of the other Initialize() overloads.
+	void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC<EC> &params)
+		{this->GenerateRandom(rng, params);}
+
+	/// \brief Create an EC private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \details This function overload of Initialize() creates a new private key because it
+	///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+	///  then use one of the other Initialize() overloads.
+	void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n)
+		{this->GenerateRandom(rng, DL_GroupParameters_EC<EC>(ec, G, n));}
+
+	virtual void MakePublicKey(DL_PublicKey_ECGDSA<EC> &pub) const
+	{
+		const DL_GroupParameters<Element>& params = this->GetAbstractGroupParameters();
+		pub.AccessAbstractGroupParameters().AssignFrom(params);
+		const Integer &xInv = this->GetPrivateExponent().InverseMod(params.GetSubgroupOrder());
+		pub.SetPublicElement(params.ExponentiateBase(xInv));
+		CRYPTOPP_ASSERT(xInv.NotZero());
+	}
+
+	virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+	{
+		return GetValueHelper<DL_PrivateKey_ECGDSA<EC>,
+			DL_PrivateKey_ECGDSA<EC> >(this, name, valueType, pValue).Assignable();
+	}
+
+	virtual void AssignFrom(const NameValuePairs &source)
+	{
+		AssignFromHelper<DL_PrivateKey_ECGDSA<EC>,
+			DL_PrivateKey_ECGDSA<EC> >(this, source);
+	}
+
+	// PKCS8PrivateKey
+	void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size);
+	void DEREncodePrivateKey(BufferedTransformation &bt) const;
+};
+
+/// \brief Elliptic Curve German DSA key for ISO/IEC 15946
+/// \tparam EC elliptic curve field
+/// \sa ECGDSA
+/// \since Crypto++ 6.0
+template <class EC>
+class DL_PublicKey_ECGDSA : public DL_PublicKeyImpl<DL_GroupParameters_EC<EC> >
+{
+	typedef DL_PublicKey_ECGDSA<EC> ThisClass;
+
+public:
+	typedef typename EC::Point Element;
+
+	virtual ~DL_PublicKey_ECGDSA() {}
+
+	/// \brief Initialize an EC Public Key using {GP,Q}
+	/// \param params group parameters
+	/// \param Q the public point
+	/// \details This Initialize() function overload initializes a public key from existing parameters.
+	void Initialize(const DL_GroupParameters_EC<EC> &params, const Element &Q)
+		{this->AccessGroupParameters() = params; this->SetPublicElement(Q);}
+
+	/// \brief Initialize an EC Public Key using {EC,G,n,Q}
+	/// \param ec the elliptic curve
+	/// \param G the base point
+	/// \param n the order of the base point
+	/// \param Q the public point
+	/// \details This Initialize() function overload initializes a public key from existing parameters.
+	void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q)
+		{this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);}
+
+	virtual void AssignFrom(const NameValuePairs &source)
+	{
+		DL_PrivateKey_ECGDSA<EC> *pPrivateKey = NULLPTR;
+		if (source.GetThisPointer(pPrivateKey))
+			pPrivateKey->MakePublicKey(*this);
+		else
+		{
+			this->AccessAbstractGroupParameters().AssignFrom(source);
+			AssignFromHelper(this, source)
+				CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement);
+		}
+	}
+
+	// DL_PublicKey<T>
+	virtual void SetPublicElement(const Element &y)
+		{this->AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);}
+
+	// X509PublicKey
+	void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size);
+	void DEREncodePublicKey(BufferedTransformation &bt) const;
+};
+
+/// \brief Elliptic Curve German DSA keys for ISO/IEC 15946
+/// \tparam EC elliptic curve field
+/// \sa ECGDSA
+/// \since Crypto++ 6.0
+template <class EC>
+struct DL_Keys_ECGDSA
+{
+	typedef DL_PublicKey_ECGDSA<EC> PublicKey;
+	typedef DL_PrivateKey_ECGDSA<EC> PrivateKey;
+};
+
+/// \brief Elliptic Curve German DSA signature algorithm
+/// \tparam EC elliptic curve field
+/// \sa ECGDSA
+/// \since Crypto++ 6.0
+template <class EC>
+class DL_Algorithm_ECGDSA : public DL_Algorithm_GDSA_ISO15946<typename EC::Point>
+{
+public:
+  CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECGDSA";}
+};
+
+/// \brief Elliptic Curve German Digital Signature Algorithm signature scheme
+/// \tparam EC elliptic curve field
+/// \tparam H HashTransformation derived class
+/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf <A
+///  HREF="http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf">The Digital Signature Scheme
+///  ECGDSA (October 24, 2006)</A>
+/// \since Crypto++ 6.0
+template <class EC, class H>
+struct ECGDSA : public DL_SS<
+	DL_Keys_ECGDSA<EC>,
+	DL_Algorithm_ECGDSA<EC>,
+	DL_SignatureMessageEncodingMethod_DSA,
+	H>
+{
+	static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECGDSA-ISO15946/") + H::StaticAlgorithmName();}
+};
+
+// ******************************************
+
+/// \brief Elliptic Curve Integrated Encryption Scheme
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \tparam HASH HashTransformation derived class used for key derivation and MAC computation
+/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as <em>u·V</em>, <em>v·U</em> and label
+/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits
+/// \details ECIES is an Elliptic Curve based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation
+///  Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is
+///  <A HREF="http://en.wikipedia.org/wiki/ciphertext_indistinguishability">IND-CCA2</A>, which is a strong notion of security.
+///  You should prefer an Integrated Encryption Scheme over homegrown schemes.
+/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES_P1363.
+///  If you desire an Integrated Encryption Scheme compatible with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES
+///  template class with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=true</tt> and <tt>LABEL_OCTETS=false</tt>.
+/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of
+///  <tt>IncompatibleCofactorMultiplication</tt> and <tt>DHAES_MODE=true</tt> is recommended for best efficiency and security.
+///  SHA1 is used for compatibility reasons, but it can be changed if desired.
+/// \sa DLIES, ECIES_P1363, <a href="http://www.weidai.com/scan-mirror/ca.html#ECIES">Elliptic Curve Integrated Encryption Scheme (ECIES)</a>,
+///  Martínez, Encinas, and Ávila's <A HREF="http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf">A Survey of the Elliptic
+///  Curve Integrated Encryption Schemes</A>
+/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility
+template <class EC, class HASH = SHA1, class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = true, bool LABEL_OCTETS = false>
+struct ECIES
+	: public DL_ES<
+		DL_Keys_EC<EC>,
+		DL_KeyAgreementAlgorithm_DH<typename EC::Point, COFACTOR_OPTION>,
+		DL_KeyDerivationAlgorithm_P1363<typename EC::Point, DHAES_MODE, P1363_KDF2<HASH> >,
+		DL_EncryptionAlgorithm_Xor<HMAC<HASH>, DHAES_MODE, LABEL_OCTETS>,
+		ECIES<EC> >
+{
+	// TODO: fix this after name is standardized
+	CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES";}
+};
+
+/// \brief Elliptic Curve Integrated Encryption Scheme for P1363
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \tparam HASH HashTransformation derived class used for key derivation and MAC computation
+/// \details ECIES_P1363 is an Elliptic Curve based Integrated Encryption Scheme (IES) for P1363. The scheme combines a Key Encapsulation
+///  Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is
+///  <A HREF="http://en.wikipedia.org/wiki/ciphertext_indistinguishability">IND-CCA2</A>, which is a strong notion of security.
+///  You should prefer an Integrated Encryption Scheme over homegrown schemes.
+/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom
+///  SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Enryption
+///  Schemes with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=false</tt> and <tt>LABEL_OCTETS=true</tt>.
+/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES_P1363.
+///  If you desire an Integrated Encryption Scheme compatible with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES
+///  template class with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=true</tt> and <tt>LABEL_OCTETS=false</tt>.
+/// \details The default template parameters ensure compatibility with P1363. The combination of
+///  <tt>IncompatibleCofactorMultiplication</tt> and <tt>DHAES_MODE=true</tt> is recommended for best efficiency and security.
+///  SHA1 is used for compatibility reasons, but it can be changed if desired.
+/// \sa DLIES, ECIES, <a href="http://www.weidai.com/scan-mirror/ca.html#ECIES">Elliptic Curve Integrated Encryption Scheme (ECIES)</a>,
+///  Martínez, Encinas, and Ávila's <A HREF="http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf">A Survey of the Elliptic
+///  Curve Integrated Encryption Schemes</A>
+/// \since Crypto++ 4.0
+template <class EC, class HASH = SHA1, class COFACTOR_OPTION = NoCofactorMultiplication>
+struct ECIES_P1363
+	: public DL_ES<
+		DL_Keys_EC<EC>,
+		DL_KeyAgreementAlgorithm_DH<typename EC::Point, COFACTOR_OPTION>,
+		DL_KeyDerivationAlgorithm_P1363<typename EC::Point, false, P1363_KDF2<HASH> >,
+		DL_EncryptionAlgorithm_Xor<HMAC<HASH>, false, true>,
+		ECIES<EC> >
+{
+	// TODO: fix this after name is standardized
+	CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES-P1363";}
+};
+
+NAMESPACE_END
+
+#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
+#include "eccrypto.cpp"
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<ECP>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<EC2N>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<ECP> >;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<EC2N> >;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<ECP>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<EC2N>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA<ECP>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA<EC2N>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<ECP> >;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<EC2N> >;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA<ECP>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA<EC2N>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<ECP>, ECDSA<ECP, SHA256> >;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >;
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 167 - 0
cryptopp/ecp.h

@@ -0,0 +1,167 @@
+// ecp.h - originally written and placed in the public domain by Wei Dai
+
+/// \file ecp.h
+/// \brief Classes for Elliptic Curves over prime fields
+
+#ifndef CRYPTOPP_ECP_H
+#define CRYPTOPP_ECP_H
+
+#include "cryptlib.h"
+#include "integer.h"
+#include "algebra.h"
+#include "modarith.h"
+#include "ecpoint.h"
+#include "eprecomp.h"
+#include "smartptr.h"
+#include "pubkey.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4231 4275)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Elliptic Curve over GF(p), where p is prime
+class CRYPTOPP_DLL ECP : public AbstractGroup<ECPPoint>, public EncodedPoint<ECPPoint>
+{
+public:
+	typedef ModularArithmetic Field;
+	typedef Integer FieldElement;
+	typedef ECPPoint Point;
+
+	virtual ~ECP() {}
+
+	/// \brief Construct an ECP
+	ECP() {}
+
+	/// \brief Construct an ECP
+	/// \param ecp the other ECP object
+	/// \param convertToMontgomeryRepresentation flag indicating if the curve
+	///  should be converted to a MontgomeryRepresentation.
+	/// \details Prior to Crypto++ 8.3 the default value for
+	///  convertToMontgomeryRepresentation was false. it was changed due to
+	///  two audit tools finding, "Signature-compatible with a copy constructor".
+	/// \sa ModularArithmetic, MontgomeryRepresentation
+	ECP(const ECP &ecp, bool convertToMontgomeryRepresentation);
+
+	/// \brief Construct an ECP
+	/// \param modulus the prime modulus
+	/// \param a Field::Element
+	/// \param b Field::Element
+	ECP(const Integer &modulus, const FieldElement &a, const FieldElement &b)
+		: m_fieldPtr(new Field(modulus)), m_a(a.IsNegative() ? modulus+a : a), m_b(b) {}
+
+	/// \brief Construct an ECP from BER encoded parameters
+	/// \param bt BufferedTransformation derived object
+	/// \details This constructor will decode and extract the fields
+	///  fieldID and curve of the sequence ECParameters
+	ECP(BufferedTransformation &bt);
+
+	/// \brief DER Encode
+	/// \param bt BufferedTransformation derived object
+	/// \details DEREncode encode the fields fieldID and curve of the sequence
+	///  ECParameters
+	void DEREncode(BufferedTransformation &bt) const;
+
+	/// \brief Compare two points
+	/// \param P the first point
+	/// \param Q the second point
+	/// \return true if equal, false otherwise
+	bool Equal(const Point &P, const Point &Q) const;
+
+	const Point& Identity() const;
+	const Point& Inverse(const Point &P) const;
+	bool InversionIsFast() const {return true;}
+	const Point& Add(const Point &P, const Point &Q) const;
+	const Point& Double(const Point &P) const;
+	Point ScalarMultiply(const Point &P, const Integer &k) const;
+	Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const;
+	void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const;
+
+	Point Multiply(const Integer &k, const Point &P) const
+		{return ScalarMultiply(P, k);}
+	Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const
+		{return CascadeScalarMultiply(P, k1, Q, k2);}
+
+	bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const;
+	bool VerifyPoint(const Point &P) const;
+
+	unsigned int EncodedPointSize(bool compressed = false) const
+		{return 1 + (compressed?1:2)*GetField().MaxElementByteLength();}
+	// returns false if point is compressed and not valid (doesn't check if uncompressed)
+	bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const;
+	bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const;
+	void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const;
+	void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
+
+	Point BERDecodePoint(BufferedTransformation &bt) const;
+	void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
+
+	Integer FieldSize() const {return GetField().GetModulus();}
+	const Field & GetField() const {return *m_fieldPtr;}
+	const FieldElement & GetA() const {return m_a;}
+	const FieldElement & GetB() const {return m_b;}
+
+	bool operator==(const ECP &rhs) const
+		{return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;}
+
+private:
+	clonable_ptr<Field> m_fieldPtr;
+	FieldElement m_a, m_b;
+	mutable Point m_R;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl<ECP::Point>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation<ECP::Point>;
+
+/// \brief Elliptic Curve precomputation
+/// \tparam EC elliptic curve field
+template <class EC> class EcPrecomputation;
+
+/// \brief ECP precomputation specialization
+/// \details Implementation of <tt>DL_GroupPrecomputation<ECP::Point></tt> with input and output
+///   conversions for Montgomery modular multiplication.
+/// \sa DL_GroupPrecomputation, ModularArithmetic, MontgomeryRepresentation
+template<> class EcPrecomputation<ECP> : public DL_GroupPrecomputation<ECP::Point>
+{
+public:
+	typedef ECP EllipticCurve;
+
+	virtual ~EcPrecomputation() {}
+
+	// DL_GroupPrecomputation
+	bool NeedConversions() const {return true;}
+	Element ConvertIn(const Element &P) const
+		{return P.identity ? P : ECP::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));};
+	Element ConvertOut(const Element &P) const
+		{return P.identity ? P : ECP::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));}
+	const AbstractGroup<Element> & GetGroup() const {return *m_ec;}
+	Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec->BERDecodePoint(bt);}
+	void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec->DEREncodePoint(bt, v, false);}
+
+	/// \brief Set the elliptic curve
+	/// \param ec ECP derived class
+	/// \details SetCurve() is not inherited
+	void SetCurve(const ECP &ec)
+	{
+		m_ec.reset(new ECP(ec, true));
+		m_ecOriginal = ec;
+	}
+
+	/// \brief Get the elliptic curve
+	/// \return ECP curve
+	/// \details GetCurve() is not inherited
+	const ECP & GetCurve() const {return *m_ecOriginal;}
+
+private:
+	value_ptr<ECP> m_ec, m_ecOriginal;
+};
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 146 - 0
cryptopp/ecpoint.h

@@ -0,0 +1,146 @@
+// ecpoint.h - written and placed in the public domain by Jeffrey Walton
+//             Data structures moved from ecp.h and ec2n.h. Added EncodedPoint interface
+
+/// \file ecpoint.h
+/// \brief Classes for Elliptic Curve points
+/// \since Crypto++ 6.0
+
+#ifndef CRYPTOPP_ECPOINT_H
+#define CRYPTOPP_ECPOINT_H
+
+#include "cryptlib.h"
+#include "integer.h"
+#include "algebra.h"
+#include "gf2n.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Elliptical Curve Point over GF(p), where p is prime
+/// \since Crypto++ 2.0
+struct CRYPTOPP_DLL ECPPoint
+{
+	virtual ~ECPPoint() {}
+
+	/// \brief Construct an ECPPoint
+	/// \details identity is set to <tt>true</tt>
+	ECPPoint() : identity(true) {}
+
+	/// \brief Construct an ECPPoint from coordinates
+	/// \details identity is set to <tt>false</tt>
+	ECPPoint(const Integer &x, const Integer &y)
+		: x(x), y(y), identity(false) {}
+
+	/// \brief Tests points for equality
+	/// \param t the other point
+	/// \return true if the points are equal, false otherwise
+	bool operator==(const ECPPoint &t) const
+		{return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);}
+
+	/// \brief Tests points for ordering
+	/// \param t the other point
+	/// \return true if this point is less than other, false otherwise
+	bool operator< (const ECPPoint &t) const
+		{return identity ? !t.identity : (!t.identity && (x<t.x || (x==t.x && y<t.y)));}
+
+	Integer x, y;
+	bool identity;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup<ECPPoint>;
+
+/// \brief Elliptical Curve Point over GF(2^n)
+/// \since Crypto++ 2.0
+struct CRYPTOPP_DLL EC2NPoint
+{
+	virtual ~EC2NPoint() {}
+
+	/// \brief Construct an EC2NPoint
+	/// \details identity is set to <tt>true</tt>
+	EC2NPoint() : identity(true) {}
+
+	/// \brief Construct an EC2NPoint from coordinates
+	/// \details identity is set to <tt>false</tt>
+	EC2NPoint(const PolynomialMod2 &x, const PolynomialMod2 &y)
+		: x(x), y(y), identity(false) {}
+
+	/// \brief Tests points for equality
+	/// \param t the other point
+	/// \return true if the points are equal, false otherwise
+	bool operator==(const EC2NPoint &t) const
+		{return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);}
+
+	/// \brief Tests points for ordering
+	/// \param t the other point
+	/// \return true if this point is less than other, false otherwise
+	bool operator< (const EC2NPoint &t) const
+		{return identity ? !t.identity : (!t.identity && (x<t.x || (x==t.x && y<t.y)));}
+
+	PolynomialMod2 x, y;
+	bool identity;
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup<EC2NPoint>;
+
+/// \brief Abstract class for encoding and decoding ellicptic curve points
+/// \tparam Point ellicptic curve point
+/// \details EncodedPoint is an interface for encoding and decoding elliptic curve points.
+///   The template parameter <tt>Point</tt> should be a class like ECP or EC2N.
+/// \since Crypto++ 6.0
+template <class Point>
+class EncodedPoint
+{
+public:
+	virtual ~EncodedPoint() {}
+
+	/// \brief Decodes an elliptic curve point
+	/// \param P point which is decoded
+	/// \param bt source BufferedTransformation
+	/// \param len number of bytes to read from the BufferedTransformation
+	/// \return true if a point was decoded, false otherwise
+	virtual bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const =0;
+
+	/// \brief Decodes an elliptic curve point
+	/// \param P point which is decoded
+	/// \param encodedPoint byte array with the encoded point
+	/// \param len the size of the array
+	/// \return true if a point was decoded, false otherwise
+	virtual bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const =0;
+
+	/// \brief Verifies points on elliptic curve
+	/// \param P point to verify
+	/// \return true if the point is valid, false otherwise
+	virtual bool VerifyPoint(const Point &P) const =0;
+
+	/// \brief Determines encoded point size
+	/// \param compressed flag indicating if the point is compressed
+	/// \return the minimum number of bytes required to encode the point
+	virtual unsigned int EncodedPointSize(bool compressed = false) const =0;
+
+	/// \brief Encodes an elliptic curve point
+	/// \param P point which is decoded
+	/// \param encodedPoint byte array for the encoded point
+	/// \param compressed flag indicating if the point is compressed
+	/// \details <tt>encodedPoint</tt> must be at least EncodedPointSize() in length
+	virtual void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const =0;
+
+	/// \brief Encodes an elliptic curve point
+	/// \param bt target BufferedTransformation
+	/// \param P point which is encoded
+	/// \param compressed flag indicating if the point is compressed
+	virtual void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0;
+
+	/// \brief BER Decodes an elliptic curve point
+	/// \param bt source BufferedTransformation
+	/// \return the decoded elliptic curve point
+	virtual Point BERDecodePoint(BufferedTransformation &bt) const =0;
+
+	/// \brief DER Encodes an elliptic curve point
+	/// \param bt target BufferedTransformation
+	/// \param P point which is encoded
+	/// \param compressed flag indicating if the point is compressed
+	virtual void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0;
+};
+
+NAMESPACE_END
+
+#endif  // CRYPTOPP_ECPOINT_H

+ 308 - 0
cryptopp/elgamal.h

@@ -0,0 +1,308 @@
+// elgamal.h - originally written and placed in the public domain by Wei Dai
+
+/// \file elgamal.h
+/// \brief Classes and functions for ElGamal key agreement and encryption schemes
+
+#ifndef CRYPTOPP_ELGAMAL_H
+#define CRYPTOPP_ELGAMAL_H
+
+#include "cryptlib.h"
+#include "modexppc.h"
+#include "integer.h"
+#include "gfpcrypt.h"
+#include "pubkey.h"
+#include "misc.h"
+#include "oids.h"
+#include "dsa.h"
+#include "asn.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief ElGamal key agreement and encryption schemes base class
+/// \since Crypto++ 1.0
+class CRYPTOPP_NO_VTABLE ElGamalBase :
+	public DL_KeyAgreementAlgorithm_DH<Integer, NoCofactorMultiplication>,
+	public DL_KeyDerivationAlgorithm<Integer>,
+	public DL_SymmetricEncryptionAlgorithm
+{
+public:
+	virtual ~ElGamalBase() {}
+
+	void Derive(const DL_GroupParameters<Integer> &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const
+	{
+		CRYPTOPP_UNUSED(groupParams); CRYPTOPP_UNUSED(ephemeralPublicKey);
+		CRYPTOPP_UNUSED(derivationParams);
+		agreedElement.Encode(derivedKey, derivedLength);
+	}
+
+	size_t GetSymmetricKeyLength(size_t plainTextLength) const
+	{
+		CRYPTOPP_UNUSED(plainTextLength);
+		return GetGroupParameters().GetModulus().ByteCount();
+	}
+
+	size_t GetSymmetricCiphertextLength(size_t plainTextLength) const
+	{
+		unsigned int len = GetGroupParameters().GetModulus().ByteCount();
+		if (plainTextLength <= GetMaxSymmetricPlaintextLength(len))
+			return len;
+		else
+			return 0;
+	}
+
+	size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const
+	{
+		unsigned int len = GetGroupParameters().GetModulus().ByteCount();
+		CRYPTOPP_ASSERT(len >= 3);
+
+		if (cipherTextLength == len)
+			return STDMIN(255U, len-3);
+		else
+			return 0;
+	}
+
+	void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs &parameters) const
+	{
+		CRYPTOPP_UNUSED(parameters);
+		const Integer &p = GetGroupParameters().GetModulus();
+		unsigned int modulusLen = p.ByteCount();
+
+		SecByteBlock block(modulusLen-1);
+		rng.GenerateBlock(block, modulusLen-2-plainTextLength);
+		std::memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength);
+		block[modulusLen-2] = (byte)plainTextLength;
+
+		a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen);
+	}
+
+	DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs &parameters) const
+	{
+		CRYPTOPP_UNUSED(parameters);
+		const Integer &p = GetGroupParameters().GetModulus();
+		unsigned int modulusLen = p.ByteCount();
+
+		if (cipherTextLength != modulusLen)
+			return DecodingResult();
+
+		Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p);
+
+		m.Encode(plainText, 1);
+		unsigned int plainTextLength = plainText[0];
+		if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen))
+			return DecodingResult();
+		m >>= 8;
+		m.Encode(plainText, plainTextLength);
+		return DecodingResult(plainTextLength);
+	}
+
+	virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0;
+};
+
+/// \brief ElGamal key agreement and encryption schemes default implementation
+/// \tparam BASE Base class implementation
+/// \tparam SCHEME_OPTIONS Scheme options
+/// \tparam KEY ElGamal key classes
+/// \since Crypto++ 1.0
+template <class BASE, class SCHEME_OPTIONS, class KEY>
+class ElGamalObjectImpl :
+	public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY>,
+	public ElGamalBase
+{
+public:
+	virtual ~ElGamalObjectImpl() {}
+
+	size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());}
+	size_t FixedCiphertextLength() const {return this->CiphertextLength(0);}
+
+	const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();}
+
+	DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const
+		{return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);}
+
+protected:
+	const DL_KeyAgreementAlgorithm<Integer> & GetKeyAgreementAlgorithm() const {return *this;}
+	const DL_KeyDerivationAlgorithm<Integer> & GetKeyDerivationAlgorithm() const {return *this;}
+	const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;}
+};
+
+/// \brief ElGamal Public Key adapter
+/// \tparam BASE PublicKey derived class
+/// \details DL_PublicKey_ElGamal provides an override for GetAlgorithmID()
+///  to utilize 1.3.14.7.2.1.1. Prior to DL_PublicKey_ElGamal, the ElGamal
+///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
+///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+///  the Crypto++ wiki.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
+/// \since Crypto++ 8.3
+template <class BASE>
+struct DL_PublicKey_ElGamal : public BASE
+{
+	virtual ~DL_PublicKey_ElGamal() {}
+
+	/// \brief Retrieves the OID of the algorithm
+	/// \return OID of the algorithm
+	/// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
+	///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
+	///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
+	///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+	///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+	///  the Crypto++ wiki.
+	/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+	///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
+	virtual OID GetAlgorithmID() const {
+		return ASN1::elGamal();
+	}
+};
+
+/// \brief ElGamal Private Key adapter
+/// \tparam BASE PrivateKey derived class
+/// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
+///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
+///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
+///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+///  the Crypto++ wiki.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
+/// \since Crypto++ 8.3
+template <class BASE>
+struct DL_PrivateKey_ElGamal : public BASE
+{
+	virtual ~DL_PrivateKey_ElGamal() {}
+
+	/// \brief Retrieves the OID of the algorithm
+	/// \return OID of the algorithm
+	/// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
+	///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
+	///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
+	///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+	///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+	///  the Crypto++ wiki.
+	/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+	///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
+	virtual OID GetAlgorithmID() const {
+		return ASN1::elGamal();
+	}
+
+	/// \brief Check the key for errors
+	/// \param rng RandomNumberGenerator for objects which use randomized testing
+	/// \param level level of thoroughness
+	/// \return true if the tests succeed, false otherwise
+	/// \details There are four levels of thoroughness:
+	///   <ul>
+	///   <li>0 - using this object won't cause a crash or exception
+	///   <li>1 - this object will probably function, and encrypt, sign, other
+	///           operations correctly
+	///   <li>2 - ensure this object will function correctly, and perform
+	///           reasonable security checks
+	///   <li>3 - perform reasonable security checks, and do checks that may
+	///           take a long time
+	///   </ul>
+	/// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can
+	///  be used for level 0. Level 1 may not check for weak keys and such.
+	///  Levels 2 and 3 are recommended.
+	bool Validate(RandomNumberGenerator &rng, unsigned int level) const
+	{
+		// Validate() formerly used DL_PrivateKey_GFP implementation through
+		// inheritance. However, it would reject keys from other libraries
+		// like BouncyCastle. The failure was x < q. According to ElGamal's
+		// paper and the HAC, the private key is selected in over [1,p-1],
+		// Later Tsiounis and Yung showed the lower limit as [1,q-1] in
+		// "On the Security of EIGamal Based Encryption". As such, Crypto++
+		// will generate a key in the range [1,q-1], but accept a key
+		// in [1,p-1]. Thanks to JPM for finding the reference. Also see
+		// https://github.com/weidai11/cryptopp/commit/a5a684d92986.
+
+		CRYPTOPP_ASSERT(this->GetAbstractGroupParameters().Validate(rng, level));
+		bool pass = this->GetAbstractGroupParameters().Validate(rng, level);
+
+		const Integer &p = this->GetGroupParameters().GetModulus();
+		const Integer &q = this->GetAbstractGroupParameters().GetSubgroupOrder();
+		const Integer &x = this->GetPrivateExponent();
+
+		// Changed to x < p-1 based on ElGamal's paper and the HAC.
+		CRYPTOPP_ASSERT(x.IsPositive());
+		CRYPTOPP_ASSERT(x < p-1);
+		pass = pass && x.IsPositive() && x < p-1;
+
+		if (level >= 1)
+		{
+			// Minimum security level due to Tsiounis and Yung.
+			CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One());
+			pass = pass && Integer::Gcd(x, q) == Integer::One();
+		}
+		return pass;
+	}
+};
+
+/// \brief ElGamal key agreement and encryption schemes keys
+/// \details ElGamalKeys provide the algorithm implementation ElGamal key
+///  agreement and encryption schemes.
+/// \details The ElGamalKeys class used <tt>DL_PrivateKey_GFP_OldFormat</tt>
+///  and <tt>DL_PublicKey_GFP_OldFormat</tt> for the <tt>PrivateKey</tt> and
+///  <tt>PublicKey</tt> from about Crypto++ 1.0 through Crypto++ 5.6.5. At
+///  Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and
+///  X509 encodings.
+/// \details The ElGamalKeys class [mistakenly] used the OID for DSA from
+///  about Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was
+///  fixed and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.
+///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+///  the Crypto++ wiki.
+/// \details At Crypto++ 8.6 ElGamalKeys were changed to use DL_CryptoKeys_ElGamal
+///  due to Issue 1069 and CVE-2021-40530. DL_CryptoKeys_ElGamal group parameters
+///  use the subgroup order, and not an estimated work factor.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/1059">Issue 1059</A>
+/// \since Crypto++ 1.0
+struct ElGamalKeys
+{
+	/// \brief Implements DL_GroupParameters interface
+	typedef DL_CryptoKeys_ElGamal::GroupParameters GroupParameters;
+	/// \brief Implements DL_PrivateKey interface
+	typedef DL_PrivateKey_ElGamal<DL_CryptoKeys_ElGamal::PrivateKey> PrivateKey;
+	/// \brief Implements DL_PublicKey interface
+	typedef DL_PublicKey_ElGamal<DL_CryptoKeys_ElGamal::PublicKey> PublicKey;
+};
+
+/// \brief ElGamal encryption scheme with non-standard padding
+/// \details ElGamal provide the algorithm implementation ElGamal key
+///  agreement and encryption schemes.
+/// \details The ElGamal class [mistakenly] used the OID for DSA from about
+///  Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was fixed
+///  and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.
+///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
+///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
+///  the Crypto++ wiki.
+/// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
+/// \since Crypto++ 1.0
+struct ElGamal
+{
+	typedef DL_CryptoSchemeOptions<ElGamal, ElGamalKeys, int, int, int> SchemeOptions;
+	typedef SchemeOptions::PrivateKey PrivateKey;
+	typedef SchemeOptions::PublicKey PublicKey;
+
+	/// \brief The algorithm name
+	/// \return the algorithm name
+	/// \details StaticAlgorithmName returns the algorithm's name as a static
+	///  member function.
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";}
+
+	/// \brief Implements DL_GroupParameters interface
+	typedef SchemeOptions::GroupParameters GroupParameters;
+	/// \brief Implements PK_Encryptor interface
+	typedef PK_FinalTemplate<ElGamalObjectImpl<DL_EncryptorBase<Integer>, SchemeOptions, SchemeOptions::PublicKey> > Encryptor;
+	/// \brief Implements PK_Encryptor interface
+	typedef PK_FinalTemplate<ElGamalObjectImpl<DL_DecryptorBase<Integer>, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor;
+};
+
+typedef ElGamal::Encryptor ElGamalEncryptor;
+typedef ElGamal::Decryptor ElGamalDecryptor;
+
+NAMESPACE_END
+
+#endif

+ 101 - 0
cryptopp/emsa2.h

@@ -0,0 +1,101 @@
+// emsa2.h - originally written and placed in the public domain by Wei Dai
+
+/// \file emsa2.h
+/// \brief Classes and functions for various padding schemes used in public key algorithms
+
+#ifndef CRYPTOPP_EMSA2_H
+#define CRYPTOPP_EMSA2_H
+
+#include "cryptlib.h"
+#include "pubkey.h"
+#include "hashfwd.h"
+#include "misc.h"
+
+#ifdef CRYPTOPP_IS_DLL
+# include "sha.h"
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief EMSA2 hash identifier
+/// \tparam H HashTransformation derived class
+/// \since Crypto++ 5.0
+template <class H> class EMSA2HashId
+{
+public:
+	static const byte id;
+};
+
+/// \brief EMSA2 padding method
+/// \tparam BASE Message encoding method
+/// \since Crypto++ 5.0
+template <class BASE>
+class EMSA2HashIdLookup : public BASE
+{
+public:
+	struct HashIdentifierLookup
+	{
+		template <class H> struct HashIdentifierLookup2
+		{
+			static HashIdentifier Lookup()
+			{
+				return HashIdentifier(&EMSA2HashId<H>::id, 1);
+			}
+		};
+	};
+};
+
+// EMSA2HashId can be instantiated with the following classes.
+// SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, Whirlpool
+
+#ifdef CRYPTOPP_IS_DLL
+CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId<SHA1>;
+CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId<SHA224>;
+CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId<SHA256>;
+CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId<SHA384>;
+CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId<SHA512>;
+#endif
+
+// https://github.com/weidai11/cryptopp/issues/300 and
+// https://github.com/weidai11/cryptopp/issues/533
+#if defined(__clang__)
+template<> const byte EMSA2HashId<SHA1>::id;
+template<> const byte EMSA2HashId<SHA224>::id;
+template<> const byte EMSA2HashId<SHA256>::id;
+template<> const byte EMSA2HashId<SHA384>::id;
+template<> const byte EMSA2HashId<SHA512>::id;
+#endif
+
+/// \brief EMSA2 padding method
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL EMSA2Pad : public EMSA2HashIdLookup<PK_DeterministicSignatureMessageEncodingMethod>
+{
+public:
+	CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA2";}
+
+	size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const
+		{CRYPTOPP_UNUSED(hashIdentifierLength); return 8*digestLength + 31;}
+
+	void ComputeMessageRepresentative(RandomNumberGenerator &rng,
+		const byte *recoverableMessage, size_t recoverableMessageLength,
+		HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty,
+		byte *representative, size_t representativeBitLength) const;
+};
+
+// EMSA2, for use with RWSS and RSA_ISO
+// Only the following hash functions are supported by this signature standard:
+//  \dontinclude emsa2.h
+//  \skip EMSA2HashId can be instantiated
+//  \until end of list
+
+/// \brief EMSA2/P1363 padding method
+/// \details Use with RWSS and RSA_ISO
+/// \since Crypto++ 5.0
+struct P1363_EMSA2 : public SignatureStandard
+{
+	typedef EMSA2Pad SignatureMessageEncodingMethod;
+};
+
+NAMESPACE_END
+
+#endif

+ 162 - 0
cryptopp/eprecomp.h

@@ -0,0 +1,162 @@
+// eprecomp.h - originally written and placed in the public domain by Wei Dai
+
+/// \file eprecomp.h
+/// \brief Classes for precomputation in a group
+
+#ifndef CRYPTOPP_EPRECOMP_H
+#define CRYPTOPP_EPRECOMP_H
+
+#include "cryptlib.h"
+#include "integer.h"
+#include "algebra.h"
+#include "stdcpp.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief DL_GroupPrecomputation interface
+/// \tparam T Field element
+template <class T>
+class DL_GroupPrecomputation
+{
+public:
+	typedef T Element;
+
+	virtual ~DL_GroupPrecomputation() {}
+
+	/// \brief Determines if elements needs conversion
+	/// \return true if the element needs conversion, false otherwise
+	/// \details NeedConversions determines if an element must convert between representations.
+	virtual bool NeedConversions() const {return false;}
+
+	/// \brief Converts an element between representations
+	/// \param v element to convert
+	/// \return an element converted to an alternate representation for internal use
+	/// \details ConvertIn is used when an element must convert between representations.
+	virtual Element ConvertIn(const Element &v) const {return v;}
+
+	/// \brief Converts an element between representations
+	/// \param v element to convert
+	/// \return an element converted from an alternate representation
+	virtual Element ConvertOut(const Element &v) const {return v;}
+
+	/// \brief Retrieves AbstractGroup interface
+	/// \return GetGroup() returns the AbstractGroup interface
+	virtual const AbstractGroup<Element> & GetGroup() const =0;
+
+	/// \brief Decodes element in DER format
+	/// \param bt BufferedTransformation object
+	/// \return element in the group
+	virtual Element BERDecodeElement(BufferedTransformation &bt) const =0;
+
+	/// \brief Encodes element in DER format
+	/// \param bt BufferedTransformation object
+	/// \param P Element to encode
+	virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0;
+};
+
+/// \brief DL_FixedBasePrecomputation interface
+/// \tparam T Field element
+template <class T>
+class DL_FixedBasePrecomputation
+{
+public:
+	typedef T Element;
+
+	virtual ~DL_FixedBasePrecomputation() {}
+
+	/// \brief Determines whether this object is initialized
+	/// \return true if this object is initialized, false otherwise
+	virtual bool IsInitialized() const =0;
+
+	/// \brief Set the base element
+	/// \param group the group
+	/// \param base element in the group
+	virtual void SetBase(const DL_GroupPrecomputation<Element> &group, const Element &base) =0;
+
+	/// \brief Get the base element
+	/// \param group the group
+	/// \return base element in the group
+	virtual const Element & GetBase(const DL_GroupPrecomputation<Element> &group) const =0;
+
+	/// \brief Perform precomputation
+	/// \param group the group
+	/// \param maxExpBits used to calculate the exponent base
+	/// \param storage the suggested number of objects for the precompute table
+	/// \details The exact semantics of Precompute() varies, but it typically means calculate
+	///   a table of n objects that can be used later to speed up computation.
+	/// \details If a derived class does not override Precompute(), then the base class throws
+	///   NotImplemented.
+	/// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation()
+	virtual void Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage) =0;
+
+	/// \brief Retrieve previously saved precomputation
+	/// \param group the group
+	/// \param storedPrecomputation BufferedTransformation with the saved precomputation
+	/// \throw NotImplemented
+	/// \sa SupportsPrecomputation(), Precompute()
+	virtual void Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) =0;
+
+	/// \brief Save precomputation for later use
+	/// \param group the group
+	/// \param storedPrecomputation BufferedTransformation to write the precomputation
+	/// \throw NotImplemented
+	/// \sa SupportsPrecomputation(), Precompute()
+	virtual void Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) const =0;
+
+	/// \brief Exponentiates an element
+	/// \param group the group
+	/// \param exponent the exponent
+	/// \return the result of the exponentiation
+	virtual Element Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const =0;
+
+	/// \brief Exponentiates an element
+	/// \param pc1 the first the group precomputation
+	/// \param exponent1 the first exponent
+	/// \param pc2 the second the group precomputation
+	/// \param exponent2 the first exponent2
+	/// \return the public element raised to the exponent
+	/// \details CascadeExponentiateBaseAndPublicElement raises the public element to
+	///   the base element and precomputation.
+	virtual Element CascadeExponentiate(const DL_GroupPrecomputation<Element> &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const =0;
+};
+
+/// \brief DL_FixedBasePrecomputation adapter class
+/// \tparam T Field element
+template <class T>
+class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation<T>
+{
+public:
+	typedef T Element;
+
+	virtual ~DL_FixedBasePrecomputationImpl() {}
+
+	DL_FixedBasePrecomputationImpl() : m_windowSize(0) {}
+
+	// DL_FixedBasePrecomputation
+	bool IsInitialized() const
+		{return !m_bases.empty();}
+	void SetBase(const DL_GroupPrecomputation<Element> &group, const Element &base);
+	const Element & GetBase(const DL_GroupPrecomputation<Element> &group) const
+		{return group.NeedConversions() ? m_base : m_bases[0];}
+	void Precompute(const DL_GroupPrecomputation<Element> &group, unsigned int maxExpBits, unsigned int storage);
+	void Load(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation);
+	void Save(const DL_GroupPrecomputation<Element> &group, BufferedTransformation &storedPrecomputation) const;
+	Element Exponentiate(const DL_GroupPrecomputation<Element> &group, const Integer &exponent) const;
+	Element CascadeExponentiate(const DL_GroupPrecomputation<Element> &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation<Element> &pc2, const Integer &exponent2) const;
+
+private:
+	void PrepareCascade(const DL_GroupPrecomputation<Element> &group, std::vector<BaseAndExponent<Element> > &eb, const Integer &exponent) const;
+
+	Element m_base;
+	unsigned int m_windowSize;
+	Integer m_exponentBase;			// what base to represent the exponent in
+	std::vector<Element> m_bases;	// precalculated bases
+};
+
+NAMESPACE_END
+
+#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
+#include "eprecomp.cpp"
+#endif
+
+#endif

+ 169 - 0
cryptopp/esign.h

@@ -0,0 +1,169 @@
+// esign.h - originally written and placed in the public domain by Wei Dai
+
+/// \file esign.h
+/// \brief Classes providing ESIGN signature schemes as defined in IEEE P1363a
+/// \since Crypto++ 5.0
+
+#ifndef CRYPTOPP_ESIGN_H
+#define CRYPTOPP_ESIGN_H
+
+#include "cryptlib.h"
+#include "pubkey.h"
+#include "integer.h"
+#include "asn.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief ESIGN trapdoor function using the public key
+/// \since Crypto++ 5.0
+class ESIGNFunction : public TrapdoorFunction, public ASN1CryptoMaterial<PublicKey>
+{
+	typedef ESIGNFunction ThisClass;
+
+public:
+
+	/// \brief Initialize a ESIGN public key with {n,e}
+	/// \param n the modulus
+	/// \param e the public exponent
+	void Initialize(const Integer &n, const Integer &e)
+		{m_n = n; m_e = e;}
+
+	// PublicKey
+	void BERDecode(BufferedTransformation &bt);
+	void DEREncode(BufferedTransformation &bt) const;
+
+	// CryptoMaterial
+	bool Validate(RandomNumberGenerator &rng, unsigned int level) const;
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+	void AssignFrom(const NameValuePairs &source);
+
+	// TrapdoorFunction
+	Integer ApplyFunction(const Integer &x) const;
+	Integer PreimageBound() const {return m_n;}
+	Integer ImageBound() const {return Integer::Power2(GetK());}
+
+	// non-derived
+	const Integer & GetModulus() const {return m_n;}
+	const Integer & GetPublicExponent() const {return m_e;}
+
+	void SetModulus(const Integer &n) {m_n = n;}
+	void SetPublicExponent(const Integer &e) {m_e = e;}
+
+protected:
+	// Covertiy finding on overflow. The library allows small values for research purposes.
+	unsigned int GetK() const {return SaturatingSubtract(m_n.BitCount()/3, 1U);}
+
+	Integer m_n, m_e;
+};
+
+/// \brief ESIGN trapdoor function using the private key
+/// \since Crypto++ 5.0
+class InvertibleESIGNFunction : public ESIGNFunction, public RandomizedTrapdoorFunctionInverse, public PrivateKey
+{
+	typedef InvertibleESIGNFunction ThisClass;
+
+public:
+
+	/// \brief Initialize a ESIGN private key with {n,e,p,q}
+	/// \param n modulus
+	/// \param e public exponent
+	/// \param p first prime factor
+	/// \param q second prime factor
+	/// \details This Initialize() function overload initializes a private key from existing parameters.
+	void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q)
+		{m_n = n; m_e = e; m_p = p; m_q = q;}
+
+	/// \brief Create a ESIGN private key
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param modulusBits the size of the modulud, in bits
+	/// \details This function overload of Initialize() creates a new private key because it
+	///   takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+	///   then use one of the other Initialize() overloads.
+	void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits)
+		{GenerateRandomWithKeySize(rng, modulusBits);}
+
+	// Squash Visual Studio C4250 warning
+	void Save(BufferedTransformation &bt) const
+		{BEREncode(bt);}
+
+	// Squash Visual Studio C4250 warning
+	void Load(BufferedTransformation &bt)
+		{BERDecode(bt);}
+
+	void BERDecode(BufferedTransformation &bt);
+	void DEREncode(BufferedTransformation &bt) const;
+
+	Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const;
+
+	// GeneratibleCryptoMaterial
+	bool Validate(RandomNumberGenerator &rng, unsigned int level) const;
+	bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+	void AssignFrom(const NameValuePairs &source);
+	/*! parameters: (ModulusSize) */
+	void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
+
+	const Integer& GetPrime1() const {return m_p;}
+	const Integer& GetPrime2() const {return m_q;}
+
+	void SetPrime1(const Integer &p) {m_p = p;}
+	void SetPrime2(const Integer &q) {m_q = q;}
+
+protected:
+	Integer m_p, m_q;
+};
+
+/// \brief EMSA5 padding method
+/// \tparam T Mask Generation Function
+/// \since Crypto++ 5.0
+template <class T>
+class EMSA5Pad : public PK_DeterministicSignatureMessageEncodingMethod
+{
+public:
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EMSA5";}
+
+	void ComputeMessageRepresentative(RandomNumberGenerator &rng,
+		const byte *recoverableMessage, size_t recoverableMessageLength,
+		HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty,
+		byte *representative, size_t representativeBitLength) const
+	{
+		CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength);
+		CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier);
+		SecByteBlock digest(hash.DigestSize());
+		hash.Final(digest);
+		size_t representativeByteLength = BitsToBytes(representativeBitLength);
+		T mgf;
+		mgf.GenerateAndMask(hash, representative, representativeByteLength, digest, digest.size(), false);
+		if (representativeBitLength % 8 != 0)
+			representative[0] = (byte)Crop(representative[0], representativeBitLength % 8);
+	}
+};
+
+/// \brief EMSA5 padding method, for use with ESIGN
+/// \since Crypto++ 5.0
+struct P1363_EMSA5 : public SignatureStandard
+{
+	typedef EMSA5Pad<P1363_MGF1> SignatureMessageEncodingMethod;
+};
+
+/// \brief ESIGN keys
+/// \since Crypto++ 5.0
+struct ESIGN_Keys
+{
+	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ESIGN";}
+	typedef ESIGNFunction PublicKey;
+	typedef InvertibleESIGNFunction PrivateKey;
+};
+
+/// \brief ESIGN signature scheme, IEEE P1363a
+/// \tparam H HashTransformation derived class
+/// \tparam STANDARD Signature encoding method
+/// \since Crypto++ 5.0
+template <class H, class STANDARD = P1363_EMSA5>
+struct ESIGN : public TF_SS<ESIGN_Keys, STANDARD, H>
+{
+};
+
+NAMESPACE_END
+
+#endif

+ 179 - 0
cryptopp/factory.h

@@ -0,0 +1,179 @@
+// factory.h - originally written and placed in the public domain by Wei Dai
+
+/// \file factory.h
+/// \brief Classes and functions for registering and locating library objects
+
+#ifndef CRYPTOPP_OBJFACT_H
+#define CRYPTOPP_OBJFACT_H
+
+#include "cryptlib.h"
+#include "misc.h"
+#include "stdcpp.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Object factory interface for registering objects
+/// \tparam AbstractClass Base class interface of the object
+template <class AbstractClass>
+class ObjectFactory
+{
+public:
+	virtual ~ObjectFactory () {}
+	virtual AbstractClass * CreateObject() const =0;
+};
+
+/// \brief Object factory for registering objects
+/// \tparam AbstractClass Base class interface of the object
+/// \tparam ConcreteClass Class object
+template <class AbstractClass, class ConcreteClass>
+class DefaultObjectFactory : public ObjectFactory<AbstractClass>
+{
+public:
+	AbstractClass * CreateObject() const
+	{
+		return new ConcreteClass;
+	}
+};
+
+/// \brief Object factory registry
+/// \tparam AbstractClass Base class interface of the object
+/// \tparam instance unique identifier
+template <class AbstractClass, int instance=0>
+class ObjectFactoryRegistry
+{
+public:
+	class FactoryNotFound : public Exception
+	{
+	public:
+		FactoryNotFound(const char *name) : Exception(OTHER_ERROR, std::string("ObjectFactoryRegistry: could not find factory for algorithm ") + name)  {}
+	};
+
+	~ObjectFactoryRegistry()
+	{
+		for (typename Map::iterator i = m_map.begin(); i != m_map.end(); ++i)
+		{
+			delete (ObjectFactory<AbstractClass> *)i->second;
+			i->second = NULLPTR;
+		}
+	}
+
+	void RegisterFactory(const std::string &name, ObjectFactory<AbstractClass> *factory)
+	{
+		m_map[name] = factory;
+	}
+
+	const ObjectFactory<AbstractClass> * GetFactory(const char *name) const
+	{
+		typename Map::const_iterator i = m_map.find(name);
+		return i == m_map.end() ? NULLPTR : (ObjectFactory<AbstractClass> *)i->second;
+	}
+
+	AbstractClass *CreateObject(const char *name) const
+	{
+		const ObjectFactory<AbstractClass> *factory = GetFactory(name);
+		if (!factory)
+			throw FactoryNotFound(name);
+		return factory->CreateObject();
+	}
+
+	// Return a vector containing the factory names. This is easier than returning an iterator.
+	// from Andrew Pitonyak
+	std::vector<std::string> GetFactoryNames() const
+	{
+		std::vector<std::string> names;
+		typename Map::const_iterator iter;
+		for (iter = m_map.begin(); iter != m_map.end(); ++iter)
+			names.push_back(iter->first);
+		return names;
+	}
+
+	CRYPTOPP_NOINLINE static ObjectFactoryRegistry<AbstractClass, instance> & Registry(CRYPTOPP_NOINLINE_DOTDOTDOT);
+
+private:
+	// use void * instead of ObjectFactory<AbstractClass> * to save code size
+	typedef std::map<std::string, void *> Map;
+	Map m_map;
+};
+
+template <class AbstractClass, int instance>
+ObjectFactoryRegistry<AbstractClass, instance> & ObjectFactoryRegistry<AbstractClass, instance>::Registry(CRYPTOPP_NOINLINE_DOTDOTDOT)
+{
+	static ObjectFactoryRegistry<AbstractClass, instance> s_registry;
+	return s_registry;
+}
+
+/// \brief Object factory registry helper
+/// \tparam AbstractClass Base class interface of the object
+/// \tparam ConcreteClass Class object
+/// \tparam instance unique identifier
+template <class AbstractClass, class ConcreteClass, int instance = 0>
+struct RegisterDefaultFactoryFor
+{
+	RegisterDefaultFactoryFor(const char *name=NULLPTR)
+	{
+		// BCB2006 workaround
+		std::string n = name ? std::string(name) : std::string(ConcreteClass::StaticAlgorithmName());
+		ObjectFactoryRegistry<AbstractClass, instance>::Registry().
+		RegisterFactory(n, new DefaultObjectFactory<AbstractClass, ConcreteClass>);
+	}
+};
+
+/// \fn RegisterAsymmetricCipherDefaultFactories
+/// \brief Register asymmetric ciphers
+/// \tparam SchemeClass interface of the object under a scheme
+/// \details Schemes include asymmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   signature schemes (registers <tt>SchemeClass::Signer</tt> and <tt>SchemeClass::Verifier</tt>),
+///   symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   authenticated symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>), etc.
+template <class SchemeClass>
+void RegisterAsymmetricCipherDefaultFactories(const char *name=NULLPTR)
+{
+	RegisterDefaultFactoryFor<PK_Encryptor, typename SchemeClass::Encryptor>((const char *)name);
+	RegisterDefaultFactoryFor<PK_Decryptor, typename SchemeClass::Decryptor>((const char *)name);
+}
+
+/// \fn RegisterSignatureSchemeDefaultFactories
+/// \brief Register signature schemes
+/// \tparam SchemeClass interface of the object under a scheme
+/// \details Schemes include asymmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   signature schemes (registers <tt>SchemeClass::Signer</tt> and <tt>SchemeClass::Verifier</tt>),
+///   symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   authenticated symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>), etc.
+template <class SchemeClass>
+void RegisterSignatureSchemeDefaultFactories(const char *name=NULLPTR)
+{
+	RegisterDefaultFactoryFor<PK_Signer, typename SchemeClass::Signer>((const char *)name);
+	RegisterDefaultFactoryFor<PK_Verifier, typename SchemeClass::Verifier>((const char *)name);
+}
+
+/// \fn RegisterSymmetricCipherDefaultFactories
+/// \brief Register symmetric ciphers
+/// \tparam SchemeClass interface of the object under a scheme
+/// \details Schemes include asymmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   signature schemes (registers <tt>SchemeClass::Signer</tt> and <tt>SchemeClass::Verifier</tt>),
+///   symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   authenticated symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>), etc.
+template <class SchemeClass>
+void RegisterSymmetricCipherDefaultFactories(const char *name=NULLPTR)
+{
+	RegisterDefaultFactoryFor<SymmetricCipher, typename SchemeClass::Encryption, ENCRYPTION>((const char *)name);
+	RegisterDefaultFactoryFor<SymmetricCipher, typename SchemeClass::Decryption, DECRYPTION>((const char *)name);
+}
+
+/// \fn RegisterAuthenticatedSymmetricCipherDefaultFactories
+/// \brief Register authenticated symmetric ciphers
+/// \tparam SchemeClass interface of the object under a scheme
+/// \details Schemes include asymmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   signature schemes (registers <tt>SchemeClass::Signer</tt> and <tt>SchemeClass::Verifier</tt>),
+///   symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>),
+///   authenticated symmetric ciphers (registers <tt>SchemeClass::Encryptor</tt> and <tt>SchemeClass::Decryptor</tt>), etc.
+template <class SchemeClass>
+void RegisterAuthenticatedSymmetricCipherDefaultFactories(const char *name=NULLPTR)
+{
+	RegisterDefaultFactoryFor<AuthenticatedSymmetricCipher, typename SchemeClass::Encryption, ENCRYPTION>((const char *)name);
+	RegisterDefaultFactoryFor<AuthenticatedSymmetricCipher, typename SchemeClass::Decryption, DECRYPTION>((const char *)name);
+}
+
+NAMESPACE_END
+
+#endif

+ 408 - 0
cryptopp/fhmqv.h

@@ -0,0 +1,408 @@
+// fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal
+//           Shamelessly based upon Wei Dai's MQV source files
+
+#ifndef CRYPTOPP_FHMQV_H
+#define CRYPTOPP_FHMQV_H
+
+/// \file fhmqv.h
+/// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p)
+/// \since Crypto++ 5.6.4
+
+#include "gfpcrypt.h"
+#include "algebra.h"
+#include "sha.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
+/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
+///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
+///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
+/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
+/// \since Crypto++ 5.6.4
+template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
+class FHMQV_Domain : public AuthenticatedKeyAgreementDomain
+{
+public:
+  typedef GROUP_PARAMETERS GroupParameters;
+  typedef typename GroupParameters::Element Element;
+  typedef FHMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
+
+  virtual ~FHMQV_Domain() {}
+
+  /// \brief Construct a FHMQV domain
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  FHMQV_Domain(bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer) {}
+
+  /// \brief Construct a FHMQV domain
+  /// \param params group parameters and options
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  FHMQV_Domain(const GroupParameters &params, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
+
+  /// \brief Construct a FHMQV domain
+  /// \param bt BufferedTransformation with group parameters and options
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer)
+    {m_groupParameters.BERDecode(bt);}
+
+  /// \brief Construct a FHMQV domain
+  /// \tparam T1 template parameter used as a constructor parameter
+  /// \param v1 first parameter
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details v1 is passed directly to the GROUP_PARAMETERS object.
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  template <class T1>
+  FHMQV_Domain(T1 v1, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer)
+    {m_groupParameters.Initialize(v1);}
+
+  /// \brief Construct a FHMQV domain
+  /// \tparam T1 template parameter used as a constructor parameter
+  /// \tparam T2 template parameter used as a constructor parameter
+  /// \param v1 first parameter
+  /// \param v2 second parameter
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  template <class T1, class T2>
+  FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer)
+    {m_groupParameters.Initialize(v1, v2);}
+
+  /// \brief Construct a FHMQV domain
+  /// \tparam T1 template parameter used as a constructor parameter
+  /// \tparam T2 template parameter used as a constructor parameter
+  /// \tparam T3 template parameter used as a constructor parameter
+  /// \param v1 first parameter
+  /// \param v2 second parameter
+  /// \param v3 third parameter
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  template <class T1, class T2, class T3>
+  FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer)
+    {m_groupParameters.Initialize(v1, v2, v3);}
+
+  /// \brief Construct a FHMQV domain
+  /// \tparam T1 template parameter used as a constructor parameter
+  /// \tparam T2 template parameter used as a constructor parameter
+  /// \tparam T3 template parameter used as a constructor parameter
+  /// \tparam T4 template parameter used as a constructor parameter
+  /// \param v1 first parameter
+  /// \param v2 second parameter
+  /// \param v3 third parameter
+  /// \param v4 third parameter
+  /// \param clientRole flag indicating initiator or recipient
+  /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
+  /// \details <tt>clientRole = true</tt> indicates initiator, and
+  ///  <tt>clientRole = false</tt> indicates recipient or server.
+  template <class T1, class T2, class T3, class T4>
+  FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
+    : m_role(clientRole ? RoleClient : RoleServer)
+    {m_groupParameters.Initialize(v1, v2, v3, v4);}
+
+public:
+
+  /// \brief Retrieves the group parameters for this domain
+  /// \return the group parameters for this domain as a const reference
+  const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
+
+  /// \brief Retrieves the group parameters for this domain
+  /// \return the group parameters for this domain as a non-const reference
+  GroupParameters & AccessGroupParameters() {return m_groupParameters;}
+
+  /// \brief Retrieves the crypto parameters for this domain
+  /// \return the crypto parameters for this domain as a non-const reference
+  CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
+
+  /// \brief Provides the size of the agreed value
+  /// \return size of agreed value produced in this domain
+  /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,
+  ///  which means the element is encoded in a non-reversible format. A
+  ///  non-reversible format means its a raw byte array, and it lacks presentation
+  ///  format like an ASN.1 BIT_STRING or OCTET_STRING.
+  unsigned int AgreedValueLength() const
+    {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
+
+  /// \brief Provides the size of the static private key
+  /// \return size of static private keys in this domain
+  /// \details The length is calculated using the byte count of the subgroup order.
+  unsigned int StaticPrivateKeyLength() const
+    {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
+
+  /// \brief Provides the size of the static public key
+  /// \return size of static public keys in this domain
+  /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,
+  ///  which means the element is encoded in a reversible format. A reversible
+  ///  format means it has a presentation format, and its an ANS.1 encoded element
+  ///  or point.
+  unsigned int StaticPublicKeyLength() const
+    {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
+
+  /// \brief Generate static private key in this domain
+  /// \param rng a RandomNumberGenerator derived class
+  /// \param privateKey a byte buffer for the generated private key in this domain
+  /// \details The private key is a random scalar used as an exponent in the range
+  ///  <tt>[1,MaxExponent()]</tt>.
+  /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
+  void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
+  {
+    Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
+    x.Encode(privateKey, StaticPrivateKeyLength());
+  }
+
+  /// \brief Generate a static public key from a private key in this domain
+  /// \param rng a RandomNumberGenerator derived class
+  /// \param privateKey a byte buffer with the previously generated private key
+  /// \param publicKey a byte buffer for the generated public key in this domain
+  /// \details The public key is an element or point on the curve, and its stored
+  ///  in a revrsible format. A reversible format means it has a presentation
+  ///  format, and its an ANS.1 encoded element or point.
+  /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
+  void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
+  {
+    CRYPTOPP_UNUSED(rng);
+    const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
+    Integer x(privateKey, StaticPrivateKeyLength());
+    Element y = params.ExponentiateBase(x);
+    params.EncodeElement(true, y, publicKey);
+  }
+
+  /// \brief Provides the size of the ephemeral private key
+  /// \return size of ephemeral private keys in this domain
+  /// \details An ephemeral private key is a private key and public key.
+  ///  The serialized size is different than a static private key.
+  unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
+
+  /// \brief Provides the size of the ephemeral public key
+  /// \return size of ephemeral public keys in this domain
+  /// \details An ephemeral public key is a public key.
+  ///  The serialized size is the same as a static public key.
+  unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
+
+  /// \brief Generate ephemeral private key in this domain
+  /// \param rng a RandomNumberGenerator derived class
+  /// \param privateKey a byte buffer for the generated private key in this domain
+  /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>
+  void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
+  {
+    const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
+    Integer x(rng, Integer::One(), params.GetMaxExponent());
+    x.Encode(privateKey, StaticPrivateKeyLength());
+    Element y = params.ExponentiateBase(x);
+    params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
+  }
+
+  /// \brief Generate ephemeral public key from a private key in this domain
+  /// \param rng a RandomNumberGenerator derived class
+  /// \param privateKey a byte buffer with the previously generated private key
+  /// \param publicKey a byte buffer for the generated public key in this domain
+  /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>
+  void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
+  {
+    CRYPTOPP_UNUSED(rng);
+    std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
+  }
+
+  /// \brief Derive agreed value or shared secret
+  /// \param agreedValue the shared secret
+  /// \param staticPrivateKey your long term private key
+  /// \param ephemeralPrivateKey your ephemeral private key
+  /// \param staticOtherPublicKey couterparty's long term public key
+  /// \param ephemeralOtherPublicKey couterparty's ephemeral public key
+  /// \param validateStaticOtherPublicKey flag indicating validation
+  /// \return true upon success, false in case of failure
+  /// \details Agree() performs the authenticated key agreement. Agree()
+  ///  derives a shared secret from your private keys and couterparty's
+  ///  public keys. Each instance or run of the protocol should use a new
+  ///  ephemeral key pair.
+  /// \details The other's ephemeral public key will always be validated at
+  ///  Level 1 to ensure it is a point on the curve.
+  ///  <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's
+  ///  static public key is validated. If you have previously validated the
+  ///  couterparty's static public key, then use
+  ///  <tt>validateStaticOtherPublicKey=false</tt> to save time.
+  /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
+  /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
+  /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
+  /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
+  /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
+  bool Agree(byte *agreedValue,
+    const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
+    const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
+    bool validateStaticOtherPublicKey=true) const
+  {
+    const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
+    size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
+
+    // Depending on the role, this will hold either A's or B's static
+    // (long term) public key. AA or BB will then point into tt.
+    SecByteBlock tt(StaticPublicKeyLength());
+
+    try
+    {
+      this->GetMaterial().DoQuickSanityCheck();
+      const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
+
+      if(m_role == RoleServer)
+      {
+        Integer b(staticPrivateKey, StaticPrivateKeyLength());
+        Element B = params.ExponentiateBase(b);
+        params.EncodeElement(true, B, tt);
+
+        XX = ephemeralOtherPublicKey;
+        xxs = EphemeralPublicKeyLength();
+        YY = ephemeralPrivateKey + StaticPrivateKeyLength();
+        yys = EphemeralPublicKeyLength();
+        AA = staticOtherPublicKey;
+        aas = StaticPublicKeyLength();
+        BB = tt.BytePtr();
+        bbs = tt.SizeInBytes();
+      }
+      else
+      {
+        Integer a(staticPrivateKey, StaticPrivateKeyLength());
+        Element A = params.ExponentiateBase(a);
+        params.EncodeElement(true, A, tt);
+
+        XX = ephemeralPrivateKey + StaticPrivateKeyLength();
+        xxs = EphemeralPublicKeyLength();
+        YY = ephemeralOtherPublicKey;
+        yys = EphemeralPublicKeyLength();
+        AA = tt.BytePtr();
+        aas = tt.SizeInBytes();
+        BB = staticOtherPublicKey;
+        bbs = StaticPublicKeyLength();
+      }
+
+      Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
+      Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
+
+      const Integer& q = params.GetSubgroupOrder();
+      const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
+      SecByteBlock dd(len), ee(len);
+
+      Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
+      Integer d(dd.BytePtr(), dd.SizeInBytes());
+
+      Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
+      Integer e(ee.BytePtr(), ee.SizeInBytes());
+
+      Element sigma;
+      if(m_role == RoleServer)
+      {
+        Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
+        Integer b(staticPrivateKey, StaticPrivateKeyLength());
+        Integer s_B = (y + e * b) % q;
+
+        Element A = params.DecodeElement(AA, false);
+        Element X = params.DecodeElement(XX, false);
+
+        Element t1 = params.ExponentiateElement(A, d);
+        Element t2 = m_groupParameters.MultiplyElements(X, t1);
+
+        sigma = params.ExponentiateElement(t2, s_B);
+      }
+      else
+      {
+        Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
+        Integer a(staticPrivateKey, StaticPrivateKeyLength());
+        Integer s_A = (x + d * a) % q;
+
+        Element B = params.DecodeElement(BB, false);
+        Element Y = params.DecodeElement(YY, false);
+
+        Element t1 = params.ExponentiateElement(B, e);
+        Element t2 = m_groupParameters.MultiplyElements(Y, t1);
+
+        sigma = params.ExponentiateElement(t2, s_A);
+      }
+
+      Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
+    }
+    catch (DL_BadElement &)
+    {
+      CRYPTOPP_ASSERT(0);
+      return false;
+    }
+    return true;
+  }
+
+protected:
+
+  inline void Hash(const Element* sigma,
+    const byte* e1, size_t e1len, const byte* e2, size_t e2len,
+    const byte* s1, size_t s1len, const byte* s2, size_t s2len,
+    byte* digest, size_t dlen) const
+  {
+    HASH hash;
+    size_t idx = 0, req = dlen;
+    size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
+
+    if(sigma)
+    {
+      //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
+      //SecByteBlock sbb(x.MinEncodedSize());
+      //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
+      SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
+      GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
+      hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
+    }
+
+    hash.Update(e1, e1len);
+    hash.Update(e2, e2len);
+    hash.Update(s1, s1len);
+    hash.Update(s2, s2len);
+
+    hash.TruncatedFinal(digest, blk);
+    req -= blk;
+
+    // All this to catch tail bytes for large curves and small hashes
+    while(req != 0)
+    {
+      hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
+
+      idx += (size_t)HASH::DIGESTSIZE;
+      blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
+      hash.TruncatedFinal(&digest[idx], blk);
+
+      req -= blk;
+    }
+  }
+
+private:
+
+  // The paper uses Initiator and Recipient - make it classical.
+  enum KeyAgreementRole { RoleServer = 1, RoleClient };
+
+  DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
+  const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
+
+  GroupParameters m_groupParameters;
+  KeyAgreementRole m_role;
+};
+
+/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
+/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
+///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
+///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
+/// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
+/// \since Crypto++ 5.6.4
+typedef FHMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> FHMQV;
+
+NAMESPACE_END
+
+#endif

+ 181 - 0
cryptopp/files.h

@@ -0,0 +1,181 @@
+// files.h - originally written and placed in the public domain by Wei Dai
+
+/// \file files.h
+/// \brief Classes providing file-based library services
+/// \since Crypto++ 1.0
+
+#ifndef CRYPTOPP_FILES_H
+#define CRYPTOPP_FILES_H
+
+#include "cryptlib.h"
+#include "filters.h"
+#include "argnames.h"
+#include "smartptr.h"
+
+#include <iostream>
+#include <fstream>
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Implementation of Store interface
+/// \details file-based implementation of Store interface
+class CRYPTOPP_DLL FileStore : public Store, private FilterPutSpaceHelper, public NotCopyable
+{
+public:
+	/// \brief Exception thrown when file-based error is encountered
+	class Err : public Exception
+	{
+	public:
+		Err(const std::string &s) : Exception(IO_ERROR, s) {}
+	};
+	/// \brief Exception thrown when file-based open error is encountered
+	class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}};
+	/// \brief Exception thrown when file-based read error is encountered
+	class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}};
+
+	/// \brief Construct a FileStore
+	FileStore() : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) {}
+
+	/// \brief Construct a FileStore
+	/// \param in an existing stream
+	FileStore(std::istream &in) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0)
+		{StoreInitialize(MakeParameters(Name::InputStreamPointer(), &in));}
+
+	/// \brief Construct a FileStore
+	/// \param filename the narrow name of the file to open
+	FileStore(const char *filename) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0)
+		{StoreInitialize(MakeParameters(Name::InputFileName(), filename ? filename : ""));}
+
+#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || (CRYPTOPP_MSC_VERSION >= 1400)
+	/// \brief Construct a FileStore
+	/// \param filename the Unicode name of the file to open
+	/// \details On non-Windows OS, this function assumes that setlocale() has been called.
+	FileStore(const wchar_t *filename)
+		{StoreInitialize(MakeParameters(Name::InputFileNameWide(), filename));}
+#endif
+
+	/// \brief Retrieves the internal stream
+	/// \return the internal stream pointer
+	std::istream* GetStream() {return m_stream;}
+
+	/// \brief Retrieves the internal stream
+	/// \return the internal stream pointer
+	const std::istream* GetStream() const {return m_stream;}
+
+	/// \brief Provides the number of bytes ready for retrieval
+	/// \return the number of bytes ready for retrieval
+	/// \details All retrieval functions return the actual number of bytes retrieved, which is
+	///  the lesser of the request number and  MaxRetrievable()
+	lword MaxRetrievable() const;
+	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
+	lword Skip(lword skipMax=ULONG_MAX);
+
+private:
+	void StoreInitialize(const NameValuePairs &parameters);
+
+	member_ptr<std::ifstream> m_file;
+	std::istream *m_stream;
+	byte *m_space;
+	size_t m_len;
+	bool m_waiting;
+};
+
+/// \brief Implementation of Store interface
+/// \details file-based implementation of Store interface
+class CRYPTOPP_DLL FileSource : public SourceTemplate<FileStore>
+{
+public:
+	typedef FileStore::Err Err;
+	typedef FileStore::OpenErr OpenErr;
+	typedef FileStore::ReadErr ReadErr;
+
+	/// \brief Construct a FileSource
+	FileSource(BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<FileStore>(attachment) {}
+
+	/// \brief Construct a FileSource
+	/// \param in an existing stream
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), &in));}
+
+	/// \brief Construct a FileSource
+	/// \param filename the narrow name of the file to open
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	/// \param binary flag indicating if the file is binary
+	FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true)
+		: SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(), filename)(Name::InputBinaryMode(), binary));}
+
+#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || (CRYPTOPP_MSC_VERSION >= 1400)
+	/// \brief Construct a FileSource
+	/// \param filename the Unicode name of the file to open
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	/// \param binary flag indicating if the file is binary
+	/// \details On non-Windows OS, this function assumes that setlocale() has been called.
+	FileSource(const wchar_t *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true)
+		: SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileNameWide(), filename)(Name::InputBinaryMode(), binary));}
+#endif
+
+	/// \brief Retrieves the internal stream
+	/// \return the internal stream pointer
+	std::istream* GetStream() {return m_store.GetStream();}
+};
+
+/// \brief Implementation of Store interface
+/// \details file-based implementation of Sink interface
+class CRYPTOPP_DLL FileSink : public Sink, public NotCopyable
+{
+public:
+	/// \brief Exception thrown when file-based error is encountered
+	class Err : public Exception
+	{
+	public:
+		Err(const std::string &s) : Exception(IO_ERROR, s) {}
+	};
+	/// \brief Exception thrown when file-based open error is encountered
+	class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}};
+	/// \brief Exception thrown when file-based write error is encountered
+	class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}};
+
+	/// \brief Construct a FileSink
+	FileSink() : m_stream(NULLPTR) {}
+
+	/// \brief Construct a FileSink
+	/// \param out an existing stream
+	FileSink(std::ostream &out)
+		{IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(), &out));}
+
+	/// \brief Construct a FileSink
+	/// \param filename the narrow name of the file to open
+	/// \param binary flag indicating if the file is binary
+	FileSink(const char *filename, bool binary=true)
+		{IsolatedInitialize(MakeParameters(Name::OutputFileName(), filename)(Name::OutputBinaryMode(), binary));}
+
+#if defined(CRYPTOPP_UNIX_AVAILABLE) || (CRYPTOPP_MSC_VERSION >= 1400)
+	/// \brief Construct a FileSink
+	/// \param filename the Unicode name of the file to open
+	/// \details On non-Windows OS, this function assumes that setlocale() has been called.
+	FileSink(const wchar_t *filename, bool binary=true)
+		{IsolatedInitialize(MakeParameters(Name::OutputFileNameWide(), filename)(Name::OutputBinaryMode(), binary));}
+#endif
+
+	/// \brief Retrieves the internal stream
+	/// \return the internal stream pointer
+	std::ostream* GetStream() {return m_stream;}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+	bool IsolatedFlush(bool hardFlush, bool blocking);
+
+private:
+	member_ptr<std::ofstream> m_file;
+	std::ostream *m_stream;
+};
+
+NAMESPACE_END
+
+#endif

+ 1529 - 0
cryptopp/filters.h

@@ -0,0 +1,1529 @@
+// filters.h - originally written and placed in the public domain by Wei Dai
+
+/// \file filters.h
+/// \brief Implementation of BufferedTransformation's attachment interface.
+
+#ifndef CRYPTOPP_FILTERS_H
+#define CRYPTOPP_FILTERS_H
+
+#include "config.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4127 4189 4231 4275 4514)
+#endif
+
+#include "cryptlib.h"
+#include "simple.h"
+#include "secblock.h"
+#include "misc.h"
+#include "smartptr.h"
+#include "queue.h"
+#include "algparam.h"
+#include "stdcpp.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Implementation of BufferedTransformation's attachment interface
+/// \details Filter is a cornerstone of the Pipeline trinity. Data flows from
+///  Sources, through Filters, and then terminates in Sinks. The difference
+///  between a Source and Filter is a Source \a pumps data, while a Filter does
+///  not. The difference between a Filter and a Sink is a Filter allows an
+///  attached transformation, while a Sink does not.
+/// \details See the discussion of BufferedTransformation in cryptlib.h for
+///  more details.
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Filter : public BufferedTransformation, public NotCopyable
+{
+public:
+	virtual ~Filter() {}
+
+	///	\name ATTACHMENT
+	//@{
+
+	/// \brief Construct a Filter
+	/// \param attachment an optional attached transformation
+	/// \details attachment can be NULL.
+	Filter(BufferedTransformation *attachment = NULLPTR);
+
+	/// \brief Determine if attachable
+	/// \return true if the object allows attached transformations, false otherwise.
+	/// \note Source and Filter offer attached transformations; while Sink does not.
+	bool Attachable() {return true;}
+
+	/// \brief Retrieve attached transformation
+	/// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise.
+	BufferedTransformation *AttachedTransformation();
+
+	/// \brief Retrieve attached transformation
+	/// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise.
+	const BufferedTransformation *AttachedTransformation() const;
+
+	/// \brief Replace an attached transformation
+	/// \param newAttachment an optional attached transformation
+	/// \details newAttachment can be a single filter, a chain of filters or NULL.
+	///  Pass NULL to remove an existing BufferedTransformation or chain of filters
+	void Detach(BufferedTransformation *newAttachment = NULLPTR);
+
+	//@}
+
+	///	\name RETRIEVAL OF ONE MESSAGE
+	//@{
+
+	// BufferedTransformation in cryptlib.h
+	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
+
+	//@}
+
+	///	\name SIGNALS
+	//@{
+
+	// BufferedTransformation in cryptlib.h
+	void Initialize(const NameValuePairs &parameters=g_nullNameValuePairs, int propagation=-1);
+	bool Flush(bool hardFlush, int propagation=-1, bool blocking=true);
+	bool MessageSeriesEnd(int propagation=-1, bool blocking=true);
+
+	//@}
+
+protected:
+	virtual BufferedTransformation * NewDefaultAttachment() const;
+	void Insert(Filter *nextFilter);	// insert filter after this one
+
+	virtual bool ShouldPropagateMessageEnd() const {return true;}
+	virtual bool ShouldPropagateMessageSeriesEnd() const {return true;}
+
+	void PropagateInitialize(const NameValuePairs &parameters, int propagation);
+
+	/// \brief Forward processed data on to attached transformation
+	/// \param outputSite unknown, system crash between keyboard and chair...
+	/// \param inString the byte buffer to process
+	/// \param length the size of the string, in bytes
+	/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
+	/// \param blocking specifies whether the object should block when processing input
+	/// \param channel the channel to process the data
+	/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+	///  0 indicates all bytes were processed.
+	size_t Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
+
+	/// \brief Output multiple bytes that may be modified by callee.
+	/// \param outputSite unknown, system crash between keyboard and chair...
+	/// \param inString the byte buffer to process
+	/// \param length the size of the string, in bytes
+	/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
+	/// \param blocking specifies whether the object should block when processing input
+	/// \param channel the channel to process the data
+	/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+	///  0 indicates all bytes were processed.
+	size_t OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
+
+	/// \brief Signals the end of messages to the object
+	/// \param outputSite unknown, system crash between keyboard and chair...
+	/// \param propagation the number of attached transformations the  MessageEnd() signal should be passed
+	/// \param blocking specifies whether the object should block when processing input
+	/// \param channel the channel to process the data
+	/// \return true is the MessageEnd signal was successful, false otherwise.
+	/// \details propagation count includes this object. Setting  propagation to <tt>1</tt> means this
+	///  object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
+	bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
+
+	/// \brief Flush buffered input and/or output, with signal propagation
+	/// \param outputSite unknown, system crash between keyboard and chair...
+	/// \param hardFlush is used to indicate whether all data should be flushed
+	/// \param propagation the number of attached transformations the  Flush() signal should be passed
+	/// \param blocking specifies whether the object should block when processing input
+	/// \param channel the channel to process the data
+	/// \return true is the Flush signal was successful, false otherwise.
+	/// \details propagation count includes this object. Setting  propagation to <tt>1</tt> means this
+	///  object only. Setting  propagation to <tt>-1</tt> means unlimited propagation.
+	/// \note Hard flushes must be used with care. It means try to process and output everything, even if
+	///  there may not be enough data to complete the action. For example, hard flushing a  HexDecoder
+	///  would cause an error if you do it after inputing an odd number of hex encoded characters.
+	/// \note For some types of filters, like  ZlibDecompressor, hard flushes can only
+	///  be done at "synchronization points". These synchronization points are positions in the data
+	///  stream that are created by hard flushes on the corresponding reverse filters, in this
+	///  example ZlibCompressor. This is useful when zlib compressed data is moved across a
+	///  network in packets and compression state is preserved across packets, as in the SSH2 protocol.
+	bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
+
+	/// \brief Marks the end of a series of messages, with signal propagation
+	/// \param outputSite unknown, system crash between keyboard and chair...
+	/// \param propagation the number of attached transformations the  MessageSeriesEnd() signal should be passed
+	/// \param blocking specifies whether the object should block when processing input
+	/// \param channel the channel to process the data
+	/// \return true is the MessageEnd signal was successful, false otherwise.
+	/// \details Each object that receives the signal will perform its processing, decrement
+	///  propagation, and then pass the signal on to attached transformations if the value is not 0.
+	/// \details propagation count includes this object. Setting  propagation to <tt>1</tt> means this
+	///  object only. Setting  propagation to <tt>-1</tt> means unlimited propagation.
+	/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
+	bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
+
+private:
+	member_ptr<BufferedTransformation> m_attachment;
+
+protected:
+	size_t m_inputPosition;
+	int m_continueAt;
+};
+
+/// \brief Create a working space in a BufferedTransformation
+struct CRYPTOPP_DLL FilterPutSpaceHelper
+{
+	virtual ~FilterPutSpaceHelper() {}
+
+	/// \brief Create a working space in a BufferedTransformation
+	/// \param target BufferedTransformation for the working space
+	/// \param channel channel for the working space
+	/// \param minSize minimum size of the allocation, in bytes
+	/// \param desiredSize preferred size of the allocation, in bytes
+	/// \param bufferSize actual size of the allocation, in bytes
+	/// \pre <tt>desiredSize >= minSize</tt> and <tt>bufferSize >= minSize</tt>.
+	/// \details bufferSize is an IN and OUT parameter. If HelpCreatePutSpace() returns a non-NULL value, then
+	///  bufferSize is valid and provides the size of the working space created for the caller.
+	/// \details Internally, HelpCreatePutSpace() calls \ref BufferedTransformation::ChannelCreatePutSpace
+	///  "ChannelCreatePutSpace()" using desiredSize. If the target returns desiredSize with a size less
+	///  than minSize (i.e., the request could not be fulfilled), then an internal SecByteBlock
+	///  called m_tempSpace is resized and used for the caller.
+	byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize)
+	{
+		CRYPTOPP_ASSERT(desiredSize >= minSize && bufferSize >= minSize);
+		if (m_tempSpace.size() < minSize)
+		{
+			byte *result = target.ChannelCreatePutSpace(channel, desiredSize);
+			if (desiredSize >= minSize)
+			{
+				bufferSize = desiredSize;
+				return result;
+			}
+			m_tempSpace.New(bufferSize);
+		}
+
+		bufferSize = m_tempSpace.size();
+		return m_tempSpace.begin();
+	}
+
+	/// \brief Create a working space in a BufferedTransformation
+	/// \param target the BufferedTransformation for the working space
+	/// \param channel channel for the working space
+	/// \param minSize minimum size of the allocation, in bytes
+	/// \return pointer to the created space
+	/// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments.
+	/// \details The filter will delete the space. The caller does not need to delete the space.
+	byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize)
+		{return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);}
+
+	/// \brief Create a working space in a BufferedTransformation
+	/// \param target the BufferedTransformation for the working space
+	/// \param channel channel for the working space
+	/// \param minSize minimum size of the allocation, in bytes
+	/// \param bufferSize the actual size of the allocation, in bytes
+	/// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments.
+	/// \details The filter will delete the space. The caller does not need to delete the space.
+	byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t bufferSize)
+		{return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);}
+
+	/// \brief Temporary working space
+	SecByteBlock m_tempSpace;
+};
+
+/// \brief Measure how many bytes and messages pass through the filter
+/// \details measure how many bytes and messages pass through the filter. The filter also serves as valve by
+///  maintaining a list of ranges to skip during processing.
+class CRYPTOPP_DLL MeterFilter : public Bufferless<Filter>
+{
+public:
+	virtual ~MeterFilter() {}
+
+	/// \brief Construct a MeterFilter
+	/// \param attachment an optional attached transformation
+	/// \param transparent flag indicating if the filter should function transparently
+	/// \details attachment can be NULL. The filter is transparent by default. If the filter is
+	///  transparent, then PutMaybeModifiable() does not process a request and always returns 0.
+	MeterFilter(BufferedTransformation *attachment=NULLPTR, bool transparent=true)
+		: m_transparent(transparent), m_currentMessageBytes(0), m_totalBytes(0)
+		, m_currentSeriesMessages(0), m_totalMessages(0), m_totalMessageSeries(0)
+		, m_begin(NULLPTR), m_length(0) {Detach(attachment); ResetMeter();}
+
+	/// \brief Set or change the transparent mode of this object
+	/// \param transparent the new transparent mode
+	void SetTransparent(bool transparent) {m_transparent = transparent;}
+
+	/// \brief Adds a range to skip during processing
+	/// \param message the message to apply the range
+	/// \param position the 0-based index in the current stream
+	/// \param size the length of the range
+	/// \param sortNow flag indicating whether the range should be sorted
+	/// \details Internally, MeterFilter maitains a deque of ranges to skip. As messages are processed,
+	///  ranges of bytes are skipped according to the list of ranges.
+	void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true);
+
+	/// \brief Resets the meter
+	/// \details ResetMeter() reinitializes the meter by setting counters to 0 and removing previous
+	///  skip ranges.
+	void ResetMeter();
+
+	// BufferedTransformation in cryptlib.h
+	void IsolatedInitialize(const NameValuePairs &parameters)
+		{CRYPTOPP_UNUSED(parameters); ResetMeter();}
+
+	/// \brief Number of bytes in the current message
+	/// \return the number of bytes in the current message
+	lword GetCurrentMessageBytes() const {return m_currentMessageBytes;}
+
+	/// \brief Number of bytes processed by the filter
+	/// \return the number of bytes processed by the filter
+	lword GetTotalBytes() const {return m_totalBytes;}
+
+	/// \brief Message number in the series
+	/// \return the message number in the series
+	unsigned int GetCurrentSeriesMessages() const {return m_currentSeriesMessages;}
+
+	/// \brief Number of messages in the message series
+	/// \return the number of messages in the message series
+	unsigned int GetTotalMessages() const {return m_totalMessages;}
+
+	/// \brief Number of messages processed by the filter
+	/// \return the number of messages processed by the filter
+	unsigned int GetTotalMessageSeries() const {return m_totalMessageSeries;}
+
+	// BufferedTransformation in cryptlib.h
+	byte * CreatePutSpace(size_t &size) {return AttachedTransformation()->CreatePutSpace(size);}
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+	size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking);
+	bool IsolatedMessageSeriesEnd(bool blocking);
+
+private:
+	size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable);
+	bool ShouldPropagateMessageEnd() const {return m_transparent;}
+	bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;}
+
+	struct MessageRange
+	{
+		inline bool operator<(const MessageRange &b) const	// BCB2006 workaround: this has to be a member function
+			{return message < b.message || (message == b.message && position < b.position);}
+		unsigned int message; lword position; lword size;
+	};
+
+	bool m_transparent;
+	lword m_currentMessageBytes, m_totalBytes;
+	unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries;
+	std::deque<MessageRange> m_rangesToSkip;
+	byte *m_begin;
+	size_t m_length;
+};
+
+/// \brief A transparent MeterFilter
+/// \sa MeterFilter, OpaqueFilter
+class CRYPTOPP_DLL TransparentFilter : public MeterFilter
+{
+public:
+	/// \brief Construct a TransparentFilter
+	/// \param attachment an optional attached transformation
+	TransparentFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, true) {}
+};
+
+/// \brief A non-transparent MeterFilter
+/// \sa MeterFilter, TransparentFilter
+class CRYPTOPP_DLL OpaqueFilter : public MeterFilter
+{
+public:
+	/// \brief Construct an OpaqueFilter
+	/// \param attachment an optional attached transformation
+	OpaqueFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, false) {}
+};
+
+/// \brief Divides an input stream into discrete blocks
+/// \details FilterWithBufferedInput divides the input stream into a first block, a number of
+///  middle blocks, and a last block. First and last blocks are optional, and middle blocks may
+///  be a stream instead (i.e. <tt>blockSize == 1</tt>).
+/// \sa AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashVerificationFilter,
+///  SignatureVerificationFilter, StreamTransformationFilter
+class CRYPTOPP_DLL FilterWithBufferedInput : public Filter
+{
+public:
+	virtual ~FilterWithBufferedInput() {}
+
+	/// \brief Construct a FilterWithBufferedInput with an attached transformation
+	/// \param attachment an attached transformation
+	FilterWithBufferedInput(BufferedTransformation *attachment);
+
+	/// \brief Construct a FilterWithBufferedInput with an attached transformation
+	/// \param firstSize the size of the first block
+	/// \param blockSize the size of middle blocks
+	/// \param lastSize the size of the last block
+	/// \param attachment an attached transformation
+	/// \details firstSize and lastSize may be 0. blockSize must be at least 1.
+	FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment);
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
+	{
+		return PutMaybeModifiable(const_cast<byte *>(inString), length, messageEnd, blocking, false);
+	}
+
+	size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
+	{
+		return PutMaybeModifiable(inString, length, messageEnd, blocking, true);
+	}
+
+	/// \brief Flushes data buffered by this object, without signal propagation
+	/// \param hardFlush indicates whether all data should be flushed
+	/// \param blocking specifies whether the object should block when processing input
+	/// \return true if the Flush was successful, false otherwise
+	/// \details IsolatedFlush() calls ForceNextPut() if hardFlush is true
+	/// \note  hardFlush must be used with care
+	bool IsolatedFlush(bool hardFlush, bool blocking);
+
+	/// \brief Flushes data buffered by this object
+	/// \details The input buffer may contain more than blockSize bytes if <tt>lastSize != 0</tt>.
+	///  ForceNextPut() forces a call to NextPut() if this is the case.
+	void ForceNextPut();
+
+protected:
+	virtual bool DidFirstPut() const {return m_firstInputDone;}
+	virtual size_t GetFirstPutSize() const {return m_firstSize;}
+	virtual size_t GetBlockPutSize() const {return m_blockSize;}
+	virtual size_t GetLastPutSize() const {return m_lastSize;}
+
+	virtual void InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, size_t &firstSize, size_t &blockSize, size_t &lastSize)
+		{CRYPTOPP_UNUSED(parameters); CRYPTOPP_UNUSED(firstSize); CRYPTOPP_UNUSED(blockSize); CRYPTOPP_UNUSED(lastSize); InitializeDerived(parameters);}
+	virtual void InitializeDerived(const NameValuePairs &parameters)
+		{CRYPTOPP_UNUSED(parameters);}
+	// FirstPut() is called if (firstSize != 0 and totalLength >= firstSize)
+	// or (firstSize == 0 and (totalLength > 0 or a MessageEnd() is received)).
+	// inString is m_firstSize in length.
+	virtual void FirstPut(const byte *inString) =0;
+	// NextPut() is called if totalLength >= firstSize+blockSize+lastSize
+	virtual void NextPutSingle(const byte *inString)
+		{CRYPTOPP_UNUSED(inString); CRYPTOPP_ASSERT(false);}
+	// Same as NextPut() except length can be a multiple of blockSize
+	// Either NextPut() or NextPutMultiple() must be overridden
+	virtual void NextPutMultiple(const byte *inString, size_t length);
+	// Same as NextPutMultiple(), but inString can be modified
+	virtual void NextPutModifiable(byte *inString, size_t length)
+		{NextPutMultiple(inString, length);}
+	/// \brief Input the last block of data
+	/// \param inString the input byte buffer
+	/// \param length the size of the input buffer, in bytes
+	/// \details LastPut() processes the last block of data and signals attached filters to do the same.
+	///  LastPut() is always called. The pseudo algorithm for the logic is:
+	/// <pre>
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// </pre>
+	virtual void LastPut(const byte *inString, size_t length) =0;
+	virtual void FlushDerived() {}
+
+protected:
+	size_t PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable);
+	void NextPutMaybeModifiable(byte *inString, size_t length, bool modifiable)
+	{
+		if (modifiable) NextPutModifiable(inString, length);
+		else NextPutMultiple(inString, length);
+	}
+
+	// This function should no longer be used, put this here to cause a compiler error
+	// if someone tries to override NextPut().
+	virtual int NextPut(const byte *inString, size_t length)
+		{CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(false); return 0;}
+
+	class BlockQueue
+	{
+	public:
+		void ResetQueue(size_t blockSize, size_t maxBlocks);
+		byte *GetBlock();
+		byte *GetContigousBlocks(size_t &numberOfBytes);
+		size_t GetAll(byte *outString);
+		void Put(const byte *inString, size_t length);
+		size_t CurrentSize() const {return m_size;}
+		size_t MaxSize() const {return m_buffer.size();}
+
+	private:
+		SecByteBlock m_buffer;
+		size_t m_blockSize, m_maxBlocks, m_size;
+		byte *m_begin;
+	};
+
+	size_t m_firstSize, m_blockSize, m_lastSize;
+	bool m_firstInputDone;
+	BlockQueue m_queue;
+};
+
+/// \brief A filter that buffers input using a ByteQueue
+/// \details FilterWithInputQueue will buffer input using a ByteQueue. When the filter receives
+///  a \ref BufferedTransformation::MessageEnd() "MessageEnd()" signal it will pass the data
+///  on to its attached transformation.
+class CRYPTOPP_DLL FilterWithInputQueue : public Filter
+{
+public:
+	virtual ~FilterWithInputQueue() {}
+
+	/// \brief Construct a FilterWithInputQueue
+	/// \param attachment an optional attached transformation
+	FilterWithInputQueue(BufferedTransformation *attachment=NULLPTR) : Filter(attachment) {}
+
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
+	{
+		if (!blocking)
+			throw BlockingInputOnly("FilterWithInputQueue");
+
+		m_inQueue.Put(inString, length);
+		if (messageEnd)
+		{
+			IsolatedMessageEnd(blocking);
+			Output(0, NULLPTR, 0, messageEnd, blocking);
+		}
+		return 0;
+	}
+
+protected:
+	virtual bool IsolatedMessageEnd(bool blocking) =0;
+	void IsolatedInitialize(const NameValuePairs &parameters)
+		{CRYPTOPP_UNUSED(parameters); m_inQueue.Clear();}
+
+	ByteQueue m_inQueue;
+};
+
+/// \struct BlockPaddingSchemeDef
+/// \brief Padding schemes used for block ciphers
+/// \since Crypto++ 5.0
+struct BlockPaddingSchemeDef
+{
+	/// \enum BlockPaddingScheme
+	/// \brief Padding schemes used for block ciphers.
+	/// \details DEFAULT_PADDING means PKCS_PADDING if <tt>cipher.MandatoryBlockSize() > 1 &&
+	///  cipher.MinLastBlockSize() == 0</tt>, which holds for ECB or CBC mode. Otherwise,
+	///  NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS.
+	/// \sa <A HREF="http://www.weidai.com/scan-mirror/csp.html">Block Cipher Padding</A> for
+	///  additional details.
+	/// \since Crypto++ 5.0
+	enum BlockPaddingScheme {
+		/// \brief No padding added to a block
+		/// \since Crypto++ 5.0
+		NO_PADDING,
+		/// \brief 0's padding added to a block
+		/// \since Crypto++ 5.0
+		ZEROS_PADDING,
+		/// \brief PKCS padding added to a block
+		/// \since Crypto++ 5.0
+		PKCS_PADDING,
+		/// \brief 1 and 0's padding added to a block
+		/// \since Crypto++ 5.0
+		ONE_AND_ZEROS_PADDING,
+		/// \brief W3C padding added to a block
+		/// \sa <A HREF="http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html">XML
+		///  Encryption Syntax and Processing</A>
+		/// \since Crypto++ 6.0
+		W3C_PADDING,
+		/// \brief Default padding scheme
+		/// \since Crypto++ 5.0
+		DEFAULT_PADDING
+	};
+};
+
+/// \brief Filter wrapper for StreamTransformation
+/// \details StreamTransformationFilter() is a filter wrapper for StreamTransformation(). It is used when
+///  pipelining data for stream ciphers and confidentiality-only block ciphers. The filter will optionally
+///  handle padding and unpadding when needed. If you are using an authenticated encryption mode of operation,
+///  then use AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter()
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL StreamTransformationFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef, private FilterPutSpaceHelper
+{
+public:
+	virtual ~StreamTransformationFilter() {}
+
+	/// \brief Construct a StreamTransformationFilter
+	/// \param c reference to a StreamTransformation
+	/// \param attachment an optional attached transformation
+	/// \param padding the \ref BlockPaddingSchemeDef "padding scheme"
+	/// \details This constructor creates a StreamTransformationFilter() for stream ciphers and
+	///  confidentiality-only block cipher modes of operation. If you are using an authenticated
+	///  encryption mode of operation, then use either AuthenticatedEncryptionFilter() or
+	///  AuthenticatedDecryptionFilter().
+	/// \sa AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter()
+	StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment = NULLPTR, BlockPaddingScheme padding = DEFAULT_PADDING);
+
+	std::string AlgorithmName() const {return m_cipher.AlgorithmName();}
+
+protected:
+
+	friend class AuthenticatedEncryptionFilter;
+	friend class AuthenticatedDecryptionFilter;
+
+	/// \brief Construct a StreamTransformationFilter
+	/// \param c reference to a StreamTransformation
+	/// \param attachment an optional attached transformation
+	/// \param padding the \ref BlockPaddingSchemeDef "padding scheme"
+	/// \param authenticated flag indicating whether the filter should allow authenticated encryption schemes
+	/// \details This constructor is used for authenticated encryption mode of operation and by
+	///  AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter().
+	StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding, bool authenticated);
+
+	void InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, size_t &firstSize, size_t &blockSize, size_t &lastSize);
+	void FirstPut(const byte *inString);
+	void NextPutMultiple(const byte *inString, size_t length);
+	void NextPutModifiable(byte *inString, size_t length);
+	void LastPut(const byte *inString, size_t length);
+
+	static size_t LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding);
+
+	StreamTransformation &m_cipher;
+	BlockPaddingScheme m_padding;
+	unsigned int m_mandatoryBlockSize;
+	unsigned int m_optimalBufferSize;
+	unsigned int m_reservedBufferSize;
+	bool m_isSpecial;
+};
+
+/// \brief Filter wrapper for HashTransformation
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL HashFilter : public Bufferless<Filter>, private FilterPutSpaceHelper
+{
+public:
+	virtual ~HashFilter() {}
+
+	/// \brief Construct a HashFilter
+	/// \param hm reference to a HashTransformation
+	/// \param attachment an optional attached transformation
+	/// \param putMessage flag indicating whether the original message should be passed to an attached transformation
+	/// \param truncatedDigestSize the size of the digest
+	/// \param messagePutChannel the channel on which the message should be output
+	/// \param hashPutChannel the channel on which the digest should be output
+	HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, bool putMessage=false, int truncatedDigestSize=-1, const std::string &messagePutChannel=DEFAULT_CHANNEL, const std::string &hashPutChannel=DEFAULT_CHANNEL);
+
+	std::string AlgorithmName() const {return m_hashModule.AlgorithmName();}
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+	byte * CreatePutSpace(size_t &size) {return m_hashModule.CreateUpdateSpace(size);}
+
+private:
+	HashTransformation &m_hashModule;
+	bool m_putMessage;
+	unsigned int m_digestSize;
+	byte *m_space;
+	std::string m_messagePutChannel, m_hashPutChannel;
+};
+
+/// \brief Filter wrapper for HashTransformation
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL HashVerificationFilter : public FilterWithBufferedInput
+{
+public:
+	virtual ~HashVerificationFilter() {}
+
+	/// \brief Exception thrown when a data integrity check failure is encountered
+	class HashVerificationFailed : public Exception
+	{
+	public:
+		HashVerificationFailed()
+			: Exception(DATA_INTEGRITY_CHECK_FAILED, "HashVerificationFilter: message hash or MAC not valid") {}
+	};
+
+	/// \enum Flags
+	/// \brief Flags controlling filter behavior.
+	/// \details The flags are a bitmask and can be OR'd together.
+	enum Flags {
+		/// \brief The hash is at the end of the message (i.e., concatenation of message+hash)
+		HASH_AT_END=0,
+		/// \brief The hash is at the beginning of the message (i.e., concatenation of hash+message)
+		HASH_AT_BEGIN=1,
+		/// \brief The message should be passed to an attached transformation
+		PUT_MESSAGE=2,
+		/// \brief The hash should be passed to an attached transformation
+		PUT_HASH=4,
+		/// \brief The result of the verification should be passed to an attached transformation
+		PUT_RESULT=8,
+		/// \brief The filter should throw a HashVerificationFailed if a failure is encountered
+		THROW_EXCEPTION=16,
+		/// \brief Default flags using HASH_AT_BEGIN and PUT_RESULT
+		DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT
+	};
+
+	/// \brief Construct a HashVerificationFilter
+	/// \param hm reference to a HashTransformation
+	/// \param attachment an optional attached transformation
+	/// \param flags flags indicating behaviors for the filter
+	/// \param truncatedDigestSize the size of the digest
+	/// \details <tt>truncatedDigestSize = -1</tt> indicates \ref HashTransformation::DigestSize() "DigestSize" should be used.
+	HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1);
+
+	std::string AlgorithmName() const {return m_hashModule.AlgorithmName();}
+	bool GetLastResult() const {return m_verified;}
+
+protected:
+	void InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, size_t &firstSize, size_t &blockSize, size_t &lastSize);
+	void FirstPut(const byte *inString);
+	void NextPutMultiple(const byte *inString, size_t length);
+	void LastPut(const byte *inString, size_t length);
+
+private:
+	friend class AuthenticatedDecryptionFilter;
+
+	HashTransformation &m_hashModule;
+	word32 m_flags;
+	unsigned int m_digestSize;
+	bool m_verified;
+	SecByteBlock m_expectedHash;
+};
+
+/// \brief Filter wrapper for encrypting with AuthenticatedSymmetricCipher
+/// \details AuthenticatedEncryptionFilter() is a wrapper for encrypting with
+///  AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when needed.
+/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier
+///  had a bug where a FileSource() would cause an exception, but a StringSource()
+///  was OK. Also see <A HREF=
+///  "https://github.com/weidai11/cryptopp/issues/817">Issue 817</A> and <A HREF=
+///  "https://github.com/weidai11/cryptopp/commit/ff110c6e183e">Commit ff110c6e183e</A>.
+/// \sa AuthenticatedSymmetricCipher, AuthenticatedDecryptionFilter, EAX, CCM, GCM,
+///  and <A HREF="https://www.cryptopp.com/wiki/AadSource">AadSource</A> on the
+///  Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL AuthenticatedEncryptionFilter : public StreamTransformationFilter
+{
+public:
+	virtual ~AuthenticatedEncryptionFilter() {}
+
+	/// \brief Construct a AuthenticatedEncryptionFilter
+	/// \param c reference to a AuthenticatedSymmetricCipher
+	/// \param attachment an optional attached transformation
+	/// \param putAAD flag indicating whether the AAD should be passed to an attached transformation
+	/// \param truncatedDigestSize the size of the digest
+	/// \param macChannel the channel on which the MAC should be output
+	/// \param padding the \ref BlockPaddingSchemeDef "padding scheme"
+	/// \details <tt>truncatedDigestSize = -1</tt> indicates \ref HashTransformation::DigestSize() "DigestSize" should be used.
+	/// \since Crypto++ 5.6.0
+	AuthenticatedEncryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, bool putAAD=false, int truncatedDigestSize=-1, const std::string &macChannel=DEFAULT_CHANNEL, BlockPaddingScheme padding = DEFAULT_PADDING);
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
+	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking);
+
+	/// \brief Input the last block of data
+	/// \param inString the input byte buffer
+	/// \param length the size of the input buffer, in bytes
+	/// \details LastPut() processes the last block of data and signals attached filters to do the same.
+	///  LastPut() is always called. The pseudo algorithm for the logic is:
+	/// <pre>
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// </pre>
+	void LastPut(const byte *inString, size_t length);
+
+protected:
+	HashFilter m_hf;
+};
+
+/// \brief Filter wrapper for decrypting with AuthenticatedSymmetricCipher
+/// \details AuthenticatedDecryptionFilter() is a wrapper for decrypting with
+///  AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when
+///  needed.
+/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier
+///  had a bug where a FileSource() would cause an exception, but a StringSource()
+///  was OK. Also see <A HREF=
+///  "https://github.com/weidai11/cryptopp/issues/817">Issue 817</A> and <A HREF=
+///  "https://github.com/weidai11/cryptopp/commit/ff110c6e183e">Commit ff110c6e183e</A>.
+/// \sa AuthenticatedSymmetricCipher, AuthenticatedEncryptionFilter, EAX, CCM, GCM,
+///  and <A HREF="https://www.cryptopp.com/wiki/AadSource">AadSource</A> on the
+///  Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL AuthenticatedDecryptionFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef
+{
+public:
+	/// \enum Flags
+	/// \brief Flags controlling filter behavior.
+	/// \details The flags are a bitmask and can be OR'd together.
+	enum Flags {
+		/// \brief The MAC is at the end of the message (i.e., concatenation of message+mac)
+		MAC_AT_END=0,
+		/// \brief The MAC is at the beginning of the message (i.e., concatenation of mac+message)
+		MAC_AT_BEGIN=1,
+		/// \brief The filter should throw a HashVerificationFailed if a failure is encountered
+		THROW_EXCEPTION=16,
+		/// \brief Default flags using THROW_EXCEPTION
+		DEFAULT_FLAGS = THROW_EXCEPTION
+	};
+
+	virtual ~AuthenticatedDecryptionFilter() {}
+
+	/// \brief Construct a AuthenticatedDecryptionFilter
+	/// \param c reference to a AuthenticatedSymmetricCipher
+	/// \param attachment an optional attached transformation
+	/// \param flags flags indicating behaviors for the filter
+	/// \param truncatedDigestSize the size of the digest
+	/// \param padding the \ref BlockPaddingSchemeDef "padding scheme"
+	/// \details Additional authenticated data should be given in channel "AAD".
+	/// \details <tt>truncatedDigestSize = -1</tt> indicates \ref HashTransformation::DigestSize() "DigestSize" should be used.
+	/// \since Crypto++ 5.6.0
+	AuthenticatedDecryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1, BlockPaddingScheme padding = DEFAULT_PADDING);
+
+	std::string AlgorithmName() const {return m_hashVerifier.AlgorithmName();}
+	byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
+	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking);
+	size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking)
+		{ return ChannelPut2(channel, begin, length, messageEnd, blocking); }
+	/// \brief Get verifier result
+	/// \return true if the digest on the previosus message was valid, false otherwise
+	bool GetLastResult() const {return m_hashVerifier.GetLastResult();}
+
+protected:
+	void InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, size_t &firstSize, size_t &blockSize, size_t &lastSize);
+	void FirstPut(const byte *inString);
+	void NextPutMultiple(const byte *inString, size_t length);
+
+	/// \brief Input the last block of data
+	/// \param inString the input byte buffer
+	/// \param length the size of the input buffer, in bytes
+	/// \details LastPut() processes the last block of data and signals attached filters to do the same.
+	///  LastPut() is always called. The pseudo algorithm for the logic is:
+	/// <pre>
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// </pre>
+	void LastPut(const byte *inString, size_t length);
+
+	HashVerificationFilter m_hashVerifier;
+	StreamTransformationFilter m_streamFilter;
+};
+
+/// \brief Filter wrapper for PK_Signer
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL SignerFilter : public Unflushable<Filter>
+{
+public:
+	virtual ~SignerFilter() {}
+
+	/// \brief Construct a SignerFilter
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param signer a PK_Signer derived class
+	/// \param attachment an optional attached transformation
+	/// \param putMessage flag indicating whether the original message should be passed to an attached transformation
+	SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULLPTR, bool putMessage=false)
+		: m_rng(rng), m_signer(signer), m_messageAccumulator(signer.NewSignatureAccumulator(rng)), m_putMessage(putMessage) {Detach(attachment);}
+
+	std::string AlgorithmName() const {return m_signer.AlgorithmName();}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+
+private:
+	RandomNumberGenerator &m_rng;
+	const PK_Signer &m_signer;
+	member_ptr<PK_MessageAccumulator> m_messageAccumulator;
+	bool m_putMessage;
+	SecByteBlock m_buf;
+};
+
+/// \brief Filter wrapper for PK_Verifier
+/// \details This filter was formerly named <tt>VerifierFilter</tt>. The name changed at Crypto++ 5.0.
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL SignatureVerificationFilter : public FilterWithBufferedInput
+{
+public:
+	/// \brief Exception thrown when an invalid signature is encountered
+	class SignatureVerificationFailed : public Exception
+	{
+	public:
+		SignatureVerificationFailed()
+			: Exception(DATA_INTEGRITY_CHECK_FAILED, "VerifierFilter: digital signature not valid") {}
+	};
+
+	/// \enum Flags
+	/// \brief Flags controlling filter behavior.
+	/// \details The flags are a bitmask and can be OR'd together.
+	enum Flags {
+		/// \brief The signature is at the end of the message (i.e., concatenation of message+signature)
+		SIGNATURE_AT_END=0,
+		/// \brief The signature is at the beginning of the message (i.e., concatenation of signature+message)
+		SIGNATURE_AT_BEGIN=1,
+		/// \brief The message should be passed to an attached transformation
+		PUT_MESSAGE=2,
+		/// \brief The signature should be passed to an attached transformation
+		PUT_SIGNATURE=4,
+		/// \brief The result of the verification should be passed to an attached transformation
+		PUT_RESULT=8,
+		/// \brief The filter should throw a HashVerificationFailed if a failure is encountered
+		THROW_EXCEPTION=16,
+		/// \brief Default flags using SIGNATURE_AT_BEGIN and PUT_RESULT
+		DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT
+	};
+
+	virtual ~SignatureVerificationFilter() {}
+
+	/// \brief Construct a SignatureVerificationFilter
+	/// \param verifier a PK_Verifier derived class
+	/// \param attachment an optional attached transformation
+	/// \param flags flags indicating behaviors for the filter
+	SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS);
+
+	std::string AlgorithmName() const {return m_verifier.AlgorithmName();}
+
+	/// \brief Retrieves the result of the last verification
+	/// \return true if the signature on the previosus message was valid, false otherwise
+	bool GetLastResult() const {return m_verified;}
+
+protected:
+	void InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, size_t &firstSize, size_t &blockSize, size_t &lastSize);
+	void FirstPut(const byte *inString);
+	void NextPutMultiple(const byte *inString, size_t length);
+	void LastPut(const byte *inString, size_t length);
+
+private:
+	const PK_Verifier &m_verifier;
+	member_ptr<PK_MessageAccumulator> m_messageAccumulator;
+	word32 m_flags;
+	SecByteBlock m_signature;
+	bool m_verified;
+};
+
+/// \brief Redirect input to another BufferedTransformation without owning it
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL Redirector : public CustomSignalPropagation<Sink>
+{
+public:
+	/// \enum Behavior
+	/// \brief Controls signal propagation behavior
+	enum Behavior
+	{
+		/// \brief Pass data only
+		DATA_ONLY = 0x00,
+		/// \brief Pass signals
+		PASS_SIGNALS = 0x01,
+		/// \brief Pass wait events
+		PASS_WAIT_OBJECTS = 0x02,
+		/// \brief Pass everything
+		/// \details PASS_EVERYTHING is default
+		PASS_EVERYTHING = PASS_SIGNALS | PASS_WAIT_OBJECTS
+	};
+
+	virtual ~Redirector() {}
+
+	/// \brief Construct a Redirector
+	Redirector() : m_target(NULLPTR), m_behavior(PASS_EVERYTHING) {}
+
+	/// \brief Construct a Redirector
+	/// \param target the destination BufferedTransformation
+	/// \param behavior Behavior "flags" specifying signal propagation
+	Redirector(BufferedTransformation &target, Behavior behavior=PASS_EVERYTHING)
+		: m_target(&target), m_behavior(behavior) {}
+
+	/// \brief Redirect input to another BufferedTransformation
+	/// \param target the destination BufferedTransformation
+	void Redirect(BufferedTransformation &target) {m_target = &target;}
+	/// \brief Stop redirecting input
+	void StopRedirection() {m_target = NULLPTR;}
+
+	/// \brief Retrieve signal propagation behavior
+	/// \return the current signal propagation behavior
+	Behavior GetBehavior() {return static_cast<Behavior>(m_behavior);}
+	/// \brief Set signal propagation behavior
+	/// \param behavior the new signal propagation behavior
+	void SetBehavior(Behavior behavior) {m_behavior=behavior;}
+	/// \brief Retrieve signal propagation behavior
+	/// \return true if the Redirector passes signals, false otherwise.
+	bool GetPassSignals() const {return (m_behavior & PASS_SIGNALS) != 0;}
+	/// \brief Set signal propagation behavior
+	/// \param pass flag indicating if the Redirector should pass signals
+	void SetPassSignals(bool pass) { if (pass) m_behavior |= PASS_SIGNALS; else m_behavior &= ~static_cast<word32>(PASS_SIGNALS); }
+	/// \brief Retrieve signal propagation behavior
+	/// \return true if the Redirector passes wait objects, false otherwise.
+	bool GetPassWaitObjects() const {return (m_behavior & PASS_WAIT_OBJECTS) != 0;}
+	/// \brief Set signal propagation behavior
+	/// \param pass flag indicating if the Redirector should pass wait objects
+	void SetPassWaitObjects(bool pass) { if (pass) m_behavior |= PASS_WAIT_OBJECTS; else m_behavior &= ~static_cast<word32>(PASS_WAIT_OBJECTS); }
+
+	bool CanModifyInput() const
+		{return m_target ? m_target->CanModifyInput() : false;}
+
+	void Initialize(const NameValuePairs &parameters, int propagation);
+	byte * CreatePutSpace(size_t &size)
+	{
+		if (m_target)
+			return m_target->CreatePutSpace(size);
+		else
+		{
+			size = 0;
+			return NULLPTR;
+		}
+	}
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
+		{return m_target ? m_target->Put2(inString, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;}
+	bool Flush(bool hardFlush, int propagation=-1, bool blocking=true)
+		{return m_target && GetPassSignals() ? m_target->Flush(hardFlush, propagation, blocking) : false;}
+	bool MessageSeriesEnd(int propagation=-1, bool blocking=true)
+		{return m_target && GetPassSignals() ? m_target->MessageSeriesEnd(propagation, blocking) : false;}
+
+	byte * ChannelCreatePutSpace(const std::string &channel, size_t &size)
+	{
+		if (m_target)
+			return m_target->ChannelCreatePutSpace(channel, size);
+		else
+		{
+			size = 0;
+			return NULLPTR;
+		}
+	}
+	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking)
+		{return m_target ? m_target->ChannelPut2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;}
+	size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking)
+		{return m_target ? m_target->ChannelPutModifiable2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;}
+	bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true)
+		{return m_target && GetPassSignals() ? m_target->ChannelFlush(channel, completeFlush, propagation, blocking) : false;}
+	bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true)
+		{return m_target && GetPassSignals() ? m_target->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;}
+
+	unsigned int GetMaxWaitObjectCount() const
+		{ return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; }
+	void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
+		{ if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container, callStack); }
+
+private:
+	BufferedTransformation *m_target;
+	word32 m_behavior;
+};
+
+/// \brief Filter class that is a proxy for a sink
+/// \details Used By ProxyFilter
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL OutputProxy : public CustomSignalPropagation<Sink>
+{
+public:
+	virtual ~OutputProxy() {}
+
+	/// \brief Construct an OutputProxy
+	/// \param owner the owning transformation
+	/// \param passSignal flag indicating if signals should be passed
+	OutputProxy(BufferedTransformation &owner, bool passSignal) : m_owner(owner), m_passSignal(passSignal) {}
+
+	/// \brief Retrieve passSignal flag
+	/// \return flag indicating if signals should be passed
+	bool GetPassSignal() const {return m_passSignal;}
+	/// \brief Set passSignal flag
+	/// \param passSignal flag indicating if signals should be passed
+	void SetPassSignal(bool passSignal) {m_passSignal = passSignal;}
+
+	byte * CreatePutSpace(size_t &size)
+		{return m_owner.AttachedTransformation()->CreatePutSpace(size);}
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
+		{return m_owner.AttachedTransformation()->Put2(inString, length, m_passSignal ? messageEnd : 0, blocking);}
+	size_t PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking)
+		{return m_owner.AttachedTransformation()->PutModifiable2(begin, length, m_passSignal ? messageEnd : 0, blocking);}
+	void Initialize(const NameValuePairs &parameters=g_nullNameValuePairs, int propagation=-1)
+		{if (m_passSignal) m_owner.AttachedTransformation()->Initialize(parameters, propagation);}
+	bool Flush(bool hardFlush, int propagation=-1, bool blocking=true)
+		{return m_passSignal ? m_owner.AttachedTransformation()->Flush(hardFlush, propagation, blocking) : false;}
+	bool MessageSeriesEnd(int propagation=-1, bool blocking=true)
+		{return m_passSignal ? m_owner.AttachedTransformation()->MessageSeriesEnd(propagation, blocking) : false;}
+
+	byte * ChannelCreatePutSpace(const std::string &channel, size_t &size)
+		{return m_owner.AttachedTransformation()->ChannelCreatePutSpace(channel, size);}
+	size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking)
+		{return m_owner.AttachedTransformation()->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);}
+	size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking)
+		{return m_owner.AttachedTransformation()->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);}
+	bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true)
+		{return m_passSignal ? m_owner.AttachedTransformation()->ChannelFlush(channel, completeFlush, propagation, blocking) : false;}
+	bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true)
+		{return m_passSignal ? m_owner.AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;}
+
+private:
+	BufferedTransformation &m_owner;
+	bool m_passSignal;
+};
+
+/// \brief Base class for Filter classes that are proxies for a chain of other filters
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL ProxyFilter : public FilterWithBufferedInput
+{
+public:
+	virtual ~ProxyFilter() {}
+
+	/// \brief Construct a ProxyFilter
+	/// \param filter an output filter
+	/// \param firstSize the first Put size
+	/// \param lastSize the last Put size
+	/// \param attachment an attached transformation
+	ProxyFilter(BufferedTransformation *filter, size_t firstSize, size_t lastSize, BufferedTransformation *attachment);
+
+	bool IsolatedFlush(bool hardFlush, bool blocking);
+
+	/// \brief Sets the OutputProxy filter
+	/// \param filter an OutputProxy filter
+	void SetFilter(Filter *filter);
+	void NextPutMultiple(const byte *s, size_t len);
+	void NextPutModifiable(byte *inString, size_t length);
+
+protected:
+	member_ptr<BufferedTransformation> m_filter;
+};
+
+/// \brief Proxy filter that doesn't modify the underlying filter's input or output
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL SimpleProxyFilter : public ProxyFilter
+{
+public:
+	/// \brief Construct a SimpleProxyFilter
+	/// \param filter an output filter
+	/// \param attachment an attached transformation
+	SimpleProxyFilter(BufferedTransformation *filter, BufferedTransformation *attachment)
+		: ProxyFilter(filter, 0, 0, attachment) {}
+
+	void FirstPut(const byte * inString)
+		{CRYPTOPP_UNUSED(inString);}
+
+	/// \brief Input the last block of data
+	/// \param inString the input byte buffer
+	/// \param length the size of the input buffer, in bytes
+	/// \details LastPut() processes the last block of data and signals attached filters to do the same.
+	///  LastPut() is always called. The pseudo algorithm for the logic is:
+	/// <pre>
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// </pre>
+	void LastPut(const byte *inString, size_t length)
+		{CRYPTOPP_UNUSED(inString), CRYPTOPP_UNUSED(length); m_filter->MessageEnd();}
+};
+
+/// \brief Filter wrapper for PK_Encryptor
+/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Encryptor::CreateEncryptionFilter.
+///  This class provides symmetry with VerifierFilter.
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL PK_EncryptorFilter : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a PK_EncryptorFilter
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param encryptor a PK_Encryptor derived class
+	/// \param attachment an optional attached transformation
+	PK_EncryptorFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment = NULLPTR)
+		: SimpleProxyFilter(encryptor.CreateEncryptionFilter(rng), attachment) {}
+};
+
+/// \brief Filter wrapper for PK_Decryptor
+/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Decryptor::CreateDecryptionFilter.
+///  This class provides symmetry with SignerFilter.
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL PK_DecryptorFilter : public SimpleProxyFilter
+{
+public:
+	/// \brief Construct a PK_DecryptorFilter
+	/// \param rng a RandomNumberGenerator derived class
+	/// \param decryptor a PK_Decryptor derived class
+	/// \param attachment an optional attached transformation
+	PK_DecryptorFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULLPTR)
+		: SimpleProxyFilter(decryptor.CreateDecryptionFilter(rng), attachment) {}
+};
+
+/// \brief Append input to a string object
+/// \tparam T std::basic_string<char> type
+/// \details StringSinkTemplate is a StringSinkTemplate typedef
+/// \since Crypto++ 5.0
+template <class T>
+class StringSinkTemplate : public Bufferless<Sink>
+{
+public:
+	typedef typename T::value_type value_type;
+	virtual ~StringSinkTemplate() {}
+
+	/// \brief Construct a StringSinkTemplate
+	/// \param output std::basic_string<char> or std::vector<byte> type
+	StringSinkTemplate(T &output)
+		: m_output(&output) {CRYPTOPP_ASSERT(sizeof(value_type)==1);}
+
+	void IsolatedInitialize(const NameValuePairs &parameters)
+		{if (!parameters.GetValue("OutputStringPointer", m_output)) throw InvalidArgument("StringSink: OutputStringPointer not specified");}
+
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
+	{
+		CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking);
+		if (length > 0)
+		{
+			typename T::size_type size = m_output->size();
+			if (length < size && size + length > m_output->capacity())
+				m_output->reserve(2*size);
+			m_output->insert(m_output->end(), (const value_type *)inString, (const value_type *)inString+length);
+		}
+		return 0;
+	}
+
+private:
+	T *m_output;
+};
+
+/// \brief Append input to a string object
+/// \details StringSink is a typedef for StringSinkTemplate<std::string>.
+/// \sa ArraySink, ArrayXorSink
+/// \since Crypto++ 4.0
+DOCUMENTED_TYPEDEF(StringSinkTemplate<std::string>, StringSink);
+CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate<std::string>;
+
+/// \brief Append input to a std::vector<byte> object
+/// \details VectorSink is a typedef for StringSinkTemplate<std::vector<byte> >.
+/// \since Crypto++ 8.0
+DOCUMENTED_TYPEDEF(StringSinkTemplate<std::vector<byte> >, VectorSink);
+CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate<std::vector<byte> >;
+
+/// \brief Incorporates input into RNG as additional entropy
+/// \since Crypto++ 4.0
+class RandomNumberSink : public Bufferless<Sink>
+{
+public:
+	virtual ~RandomNumberSink() {}
+
+	/// \brief Construct a RandomNumberSink
+	RandomNumberSink()
+		: m_rng(NULLPTR) {}
+
+	/// \brief Construct a RandomNumberSink
+	/// \param rng a RandomNumberGenerator derived class
+	RandomNumberSink(RandomNumberGenerator &rng)
+		: m_rng(&rng) {}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+
+private:
+	RandomNumberGenerator *m_rng;
+};
+
+/// \brief Copy input to a memory buffer
+/// \details ArraySink wraps a fixed size buffer. The buffer is full once Put returns non-0.
+///  When used in a pipeline, ArraySink silently discards input if the buffer is full.
+///  AvailableSize() can be used to determine how much space remains in the buffer.
+///  TotalPutLength() can be used to determine how many bytes were processed.
+/// \sa StringSink, ArrayXorSink
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL ArraySink : public Bufferless<Sink>
+{
+public:
+	virtual ~ArraySink() {}
+
+	/// \brief Construct an ArraySink
+	/// \param parameters a set of NameValuePairs to initialize this object
+	/// \details Name::OutputBuffer() is a mandatory parameter using this constructor.
+	ArraySink(const NameValuePairs &parameters = g_nullNameValuePairs)
+		: m_buf(NULLPTR), m_size(0), m_total(0) {IsolatedInitialize(parameters);}
+
+	/// \brief Construct an ArraySink
+	/// \param buf pointer to a memory buffer
+	/// \param size length of the memory buffer
+	ArraySink(byte *buf, size_t size)
+		: m_buf(buf), m_size(size), m_total(0) {}
+
+	/// \brief Provides the size remaining in the Sink
+	/// \return size remaining in the Sink, in bytes
+	size_t AvailableSize() {return SaturatingSubtract(m_size, m_total);}
+
+	/// \brief Provides the number of bytes written to the Sink
+	/// \return number of bytes written to the Sink, in bytes
+	lword TotalPutLength() {return m_total;}
+
+	void IsolatedInitialize(const NameValuePairs &parameters);
+	byte * CreatePutSpace(size_t &size);
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+
+protected:
+	byte *m_buf;
+	size_t m_size;
+	lword m_total;
+};
+
+/// \brief Xor input to a memory buffer
+/// \details ArrayXorSink wraps a fixed size buffer. The buffer is full once Put returns non-0.
+///  When used in a pipeline, ArrayXorSink silently discards input if the buffer is full.
+///  AvailableSize() can be used to determine how much space remains in the buffer.
+///  TotalPutLength() can be used to determine how many bytes were processed.
+/// \sa StringSink, ArraySink
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL ArrayXorSink : public ArraySink
+{
+public:
+	virtual ~ArrayXorSink() {}
+
+	/// \brief Construct an ArrayXorSink
+	/// \param buf pointer to a memory buffer
+	/// \param size length of the memory buffer
+	ArrayXorSink(byte *buf, size_t size)
+		: ArraySink(buf, size) {}
+
+	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
+	byte * CreatePutSpace(size_t &size) {return BufferedTransformation::CreatePutSpace(size);}
+};
+
+/// \brief String-based implementation of Store interface
+/// \since Crypto++ 4.0
+class StringStore : public Store
+{
+public:
+	/// \brief Construct a StringStore
+	/// \param string pointer to a C-String
+	StringStore(const char *string = NULLPTR)
+		{StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
+
+	/// \brief Construct a StringStore
+	/// \param string pointer to a memory buffer
+	/// \param length size of the memory buffer
+	StringStore(const byte *string, size_t length)
+		{StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));}
+
+	/// \brief Construct a StringStore
+	/// \tparam T std::basic_string<char> type
+	/// \param string reference to a std::basic_string<char> type
+	template <class T> StringStore(const T &string)
+		{StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
+
+	CRYPTOPP_DLL size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	CRYPTOPP_DLL size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
+
+private:
+	CRYPTOPP_DLL void StoreInitialize(const NameValuePairs &parameters);
+
+	const byte *m_store;
+	size_t m_length, m_count;
+};
+
+/// \brief RNG-based implementation of Source interface
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL RandomNumberStore : public Store
+{
+public:
+	virtual ~RandomNumberStore() {}
+
+	RandomNumberStore()
+		: m_rng(NULLPTR), m_length(0), m_count(0) {}
+
+	RandomNumberStore(RandomNumberGenerator &rng, lword length)
+		: m_rng(&rng), m_length(length), m_count(0) {}
+
+	bool AnyRetrievable() const {return MaxRetrievable() != 0;}
+	lword MaxRetrievable() const {return m_length-m_count;}
+
+	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
+	{
+		CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking);
+		throw NotImplemented("RandomNumberStore: CopyRangeTo2() is not supported by this store");
+	}
+
+private:
+	void StoreInitialize(const NameValuePairs &parameters);
+
+	RandomNumberGenerator *m_rng;
+	lword m_length, m_count;
+};
+
+/// \brief Empty store
+/// \since Crypto++ 5.0
+class CRYPTOPP_DLL NullStore : public Store
+{
+public:
+	NullStore(lword size = ULONG_MAX) : m_size(size) {}
+	void StoreInitialize(const NameValuePairs &parameters)
+		{CRYPTOPP_UNUSED(parameters);}
+	lword MaxRetrievable() const {return m_size;}
+	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
+	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
+
+private:
+	lword m_size;
+};
+
+/// \brief Implementation of BufferedTransformation's attachment interface
+/// \details Source is a cornerstone of the Pipeline trinitiy. Data flows from
+///  Sources, through Filters, and then terminates in Sinks. The difference
+///  between a Source and Filter is a Source \a pumps data, while a Filter does
+///  not. The difference between a Filter and a Sink is a Filter allows an
+///  attached transformation, while a Sink does not.
+/// \details See the discussion of BufferedTransformation in cryptlib.h for
+///  more details.
+/// \sa Store and SourceTemplate
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Source : public InputRejecting<Filter>
+{
+public:
+	virtual ~Source() {}
+
+	/// \brief Construct a Source
+	/// \param attachment an optional attached transformation
+	Source(BufferedTransformation *attachment = NULLPTR)
+		{Source::Detach(attachment);}
+
+	///	\name PIPELINE
+	//@{
+
+	/// \brief Pump data to attached transformation
+	/// \param pumpMax the maximum number of bytes to pump
+	/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+	///  0 indicates all bytes were processed.
+	/// \details Internally, Pump() calls Pump2().
+	/// \note pumpMax is a <tt>lword</tt>, which is a 64-bit value that typically uses
+	///  <tt>LWORD_MAX</tt>. The default argument is <tt>SIZE_MAX</tt>, and it can be
+	///  32-bits or 64-bits.
+	/// \sa Pump2, PumpAll, AnyRetrievable, MaxRetrievable
+	lword Pump(lword pumpMax=SIZE_MAX)
+		{Pump2(pumpMax); return pumpMax;}
+
+	/// \brief Pump messages to attached transformation
+	/// \param count the maximum number of messages to pump
+	/// \return TODO
+	/// \details Internally, PumpMessages() calls PumpMessages2().
+	unsigned int PumpMessages(unsigned int count=UINT_MAX)
+		{PumpMessages2(count); return count;}
+
+	/// \brief Pump all data to attached transformation
+	/// \details Pumps all data to the attached transformation and signal the end of the current
+	///  message. To avoid the MessageEnd() signal call \ref Pump "Pump(LWORD_MAX)" or \ref Pump2
+	///  "Pump2(LWORD_MAX, bool)".
+	/// \details Internally, PumpAll() calls PumpAll2(), which calls PumpMessages().
+	/// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable
+	void PumpAll()
+		{PumpAll2();}
+
+	/// \brief Pump data to attached transformation
+	/// \param byteCount the maximum number of bytes to pump
+	/// \param blocking specifies whether the object should block when processing input
+	/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+	///  0 indicates all bytes were processed.
+	/// \details byteCount is an \a IN and \a OUT parameter. When the call is made, byteCount is the
+	///  requested size of the pump. When the call returns, byteCount is the number of bytes that
+	///  were pumped.
+	/// \sa Pump, PumpAll, AnyRetrievable, MaxRetrievable
+	virtual size_t Pump2(lword &byteCount, bool blocking=true) =0;
+
+	/// \brief Pump messages to attached transformation
+	/// \param messageCount the maximum number of messages to pump
+	/// \param blocking specifies whether the object should block when processing input
+	/// \details messageCount is an IN and OUT parameter.
+	virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) =0;
+
+	/// \brief Pump all data to attached transformation
+	/// \param blocking specifies whether the object should block when processing input
+	/// \return the number of bytes that remain to be processed (i.e., bytes not processed).
+	///  0 indicates all bytes were processed.
+	/// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable
+	virtual size_t PumpAll2(bool blocking=true);
+
+	/// \brief Determines if the Source is exhausted
+	/// \return true if the source has been exhausted
+	virtual bool SourceExhausted() const =0;
+
+	//@}
+
+protected:
+	void SourceInitialize(bool pumpAll, const NameValuePairs &parameters)
+	{
+		IsolatedInitialize(parameters);
+		if (pumpAll)
+			PumpAll();
+	}
+};
+
+/// \brief Transform a Store into a Source
+/// \tparam T the class or type
+/// \since Crypto++ 5.0
+template <class T>
+class SourceTemplate : public Source
+{
+public:
+	virtual ~SourceTemplate() {}
+
+	/// \brief Construct a SourceTemplate
+	/// \param attachment an attached transformation
+	SourceTemplate(BufferedTransformation *attachment)
+		: Source(attachment) {}
+	void IsolatedInitialize(const NameValuePairs &parameters)
+		{m_store.IsolatedInitialize(parameters);}
+	size_t Pump2(lword &byteCount, bool blocking=true)
+		{return m_store.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);}
+	size_t PumpMessages2(unsigned int &messageCount, bool blocking=true)
+		{return m_store.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);}
+	size_t PumpAll2(bool blocking=true)
+		{return m_store.TransferAllTo2(*AttachedTransformation(), DEFAULT_CHANNEL, blocking);}
+	bool SourceExhausted() const
+		{return !m_store.AnyRetrievable() && !m_store.AnyMessages();}
+	void SetAutoSignalPropagation(int propagation)
+		{m_store.SetAutoSignalPropagation(propagation);}
+	int GetAutoSignalPropagation() const
+		{return m_store.GetAutoSignalPropagation();}
+
+protected:
+	T m_store;
+};
+
+/// \brief String-based implementation of the Source interface
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL StringSource : public SourceTemplate<StringStore>
+{
+public:
+	/// \brief Construct a StringSource
+	/// \param attachment an optional attached transformation
+	StringSource(BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {}
+
+	/// \brief Construct a StringSource
+	/// \param string C-String
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
+
+	/// \brief Construct a StringSource
+	/// \param string binary byte array
+	/// \param length size of the byte array
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	StringSource(const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));}
+
+	/// \brief Construct a StringSource
+	/// \param string std::string
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
+};
+
+/// \brief Pointer-based implementation of the Source interface
+/// \details ArraySource is a typedef for StringSource. Use the third constructor for an array source.
+///  The third constructor takes a pointer and length.
+/// \since Crypto++ 5.6.0
+DOCUMENTED_TYPEDEF(StringSource, ArraySource);
+
+/// \brief std::vector-based implementation of the Source interface
+/// \since Crypto++ 8.0
+class CRYPTOPP_DLL VectorSource : public SourceTemplate<StringStore>
+{
+public:
+	/// \brief Construct a VectorSource
+	/// \param attachment an optional attached transformation
+	VectorSource(BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {}
+
+	/// \brief Construct a VectorSource
+	/// \param vec vector of bytes
+	/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
+	/// \param attachment an optional attached transformation
+	VectorSource(const std::vector<byte> &vec, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(vec)));}
+};
+
+/// \brief RNG-based implementation of Source interface
+/// \since Crypto++ 4.0
+class CRYPTOPP_DLL RandomNumberSource : public SourceTemplate<RandomNumberStore>
+{
+public:
+	RandomNumberSource(RandomNumberGenerator &rng, int length, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
+		: SourceTemplate<RandomNumberStore>(attachment)
+		{SourceInitialize(pumpAll, MakeParameters("RandomNumberGeneratorPointer", &rng)("RandomNumberStoreSize", length));}
+};
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 112 - 0
cryptopp/fips140.h

@@ -0,0 +1,112 @@
+// fips140.h - originally written and placed in the public domain by Wei Dai
+
+/// \file fips140.h
+/// \brief Classes and functions for the FIPS 140-2 validated library
+/// \details The FIPS validated library is only available on Windows as a DLL. Once compiled,
+///   the library is always in FIPS mode contingent upon successful execution of
+///   DoPowerUpSelfTest() or DoDllPowerUpSelfTest().
+/// \sa <A HREF="http://cryptopp.com/wiki/Visual_Studio">Visual Studio</A> and
+///   <A HREF="http://cryptopp.com/wiki/config.h">config.h</A> on the Crypto++ wiki.
+
+#ifndef CRYPTOPP_FIPS140_H
+#define CRYPTOPP_FIPS140_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// Exception thrown when a crypto algorithm is used after a self test fails
+/// \details The self tests for an algorithm are performed by Algorithm class
+///   when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined.
+class CRYPTOPP_DLL SelfTestFailure : public Exception
+{
+public:
+	explicit SelfTestFailure(const std::string &s) : Exception(OTHER_ERROR, s) {}
+};
+
+/// \brief Determines whether the library provides FIPS validated cryptography
+/// \return true if FIPS 140-2 validated features were enabled at compile time.
+/// \details true if FIPS 140-2 validated features were enabled at compile time,
+///   false otherwise.
+/// \note FIPS mode is enabled at compile time. A program or other module cannot
+///   arbitrarily enter or exit the mode.
+CRYPTOPP_DLL bool CRYPTOPP_API FIPS_140_2_ComplianceEnabled();
+
+/// \brief Status of the power-up self test
+enum PowerUpSelfTestStatus {
+
+	/// \brief The self tests have not been performed.
+	POWER_UP_SELF_TEST_NOT_DONE,
+	/// \brief The self tests were executed via DoPowerUpSelfTest() or
+	///   DoDllPowerUpSelfTest(), but the result was failure.
+	POWER_UP_SELF_TEST_FAILED,
+	/// \brief The self tests were executed via DoPowerUpSelfTest() or
+	///   DoDllPowerUpSelfTest(), and the result was success.
+	POWER_UP_SELF_TEST_PASSED
+};
+
+/// \brief Performs the power-up self test
+/// \param moduleFilename the fully qualified name of the module
+/// \param expectedModuleMac the expected MAC of the components protected by the integrity check
+/// \details Performs the power-up self test, and sets the self test status to
+///   POWER_UP_SELF_TEST_PASSED or POWER_UP_SELF_TEST_FAILED.
+/// \details The self tests for an algorithm are performed by the Algorithm class
+///   when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined.
+CRYPTOPP_DLL void CRYPTOPP_API DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleMac);
+
+/// \brief Performs the power-up self test on the DLL
+/// \details Performs the power-up self test using the filename of this DLL and the
+///   embedded module MAC, and sets the self test status to POWER_UP_SELF_TEST_PASSED or
+///   POWER_UP_SELF_TEST_FAILED.
+/// \details The self tests for an algorithm are performed by the Algorithm class
+///   when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined.
+CRYPTOPP_DLL void CRYPTOPP_API DoDllPowerUpSelfTest();
+
+/// \brief Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED
+/// \details Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED to simulate failure.
+CRYPTOPP_DLL void CRYPTOPP_API SimulatePowerUpSelfTestFailure();
+
+/// \brief Provides the current power-up self test status
+/// \return the current power-up self test status
+CRYPTOPP_DLL PowerUpSelfTestStatus CRYPTOPP_API GetPowerUpSelfTestStatus();
+
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+typedef PowerUpSelfTestStatus (CRYPTOPP_API * PGetPowerUpSelfTestStatus)();
+#endif
+
+/// \brief Class object that calculates the MAC on the module
+/// \return the MAC for the module
+CRYPTOPP_DLL MessageAuthenticationCode * CRYPTOPP_API NewIntegrityCheckingMAC();
+
+/// \brief Verifies the MAC on the module
+/// \param moduleFilename the fully qualified name of the module
+/// \param expectedModuleMac the expected MAC of the components protected by the integrity check
+/// \param pActualMac the actual MAC of the components calculated by the integrity check
+/// \param pMacFileLocation the offset of the MAC in the PE/PE+ module
+/// \return true if the MAC is valid, false otherwise
+CRYPTOPP_DLL bool CRYPTOPP_API IntegrityCheckModule(const char *moduleFilename, const byte *expectedModuleMac, SecByteBlock *pActualMac = NULLPTR, unsigned long *pMacFileLocation = NULLPTR);
+
+#ifndef CRYPTOPP_DOXYGEN_PROCESSING
+// this is used by Algorithm constructor to allow Algorithm objects to be constructed for the self test
+bool PowerUpSelfTestInProgressOnThisThread();
+
+void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress);
+
+void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier);
+void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor);
+
+void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier);
+void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor);
+#endif
+
+/// \brief The placeholder used prior to embedding the actual MAC in the module.
+/// \details After the DLL is built but before it is MAC'd, the string CRYPTOPP_DUMMY_DLL_MAC
+///   is used as a placeholder for the actual MAC. A post-build step is performed which calculates
+///   the MAC of the DLL and embeds it in the module. The actual MAC is written by the
+///   <tt>cryptest.exe</tt> program using the <tt>mac_dll</tt> subcommand.
+#define CRYPTOPP_DUMMY_DLL_MAC "MAC_51f34b8db820ae8"
+
+NAMESPACE_END
+
+#endif

+ 69 - 0
cryptopp/fltrimpl.h

@@ -0,0 +1,69 @@
+#ifndef CRYPTOPP_FLTRIMPL_H
+#define CRYPTOPP_FLTRIMPL_H
+
+#define FILTER_BEGIN	\
+	switch (m_continueAt)	\
+	{	\
+	case 0:	\
+		m_inputPosition = 0;
+
+#define FILTER_END_NO_MESSAGE_END_NO_RETURN	\
+		break;	\
+	default:	\
+		CRYPTOPP_ASSERT(false);	\
+	}
+
+#define FILTER_END_NO_MESSAGE_END	\
+	FILTER_END_NO_MESSAGE_END_NO_RETURN	\
+	return 0;
+
+/*
+#define FILTER_END	\
+	case -1:	\
+		if (messageEnd && Output(-1, NULLPTR, 0, messageEnd, blocking))	\
+			return 1;	\
+	FILTER_END_NO_MESSAGE_END
+*/
+
+#define FILTER_OUTPUT3(site, statement, output, length, messageEnd, channel)	\
+	{\
+	case site:	\
+	(void) statement;	\
+	if (Output(site, output, length, messageEnd, blocking, channel))	\
+		return STDMAX(size_t(1), length-m_inputPosition);\
+	}
+
+#define FILTER_OUTPUT2(site, statement, output, length, messageEnd)	\
+	FILTER_OUTPUT3(site, statement, output, length, messageEnd, DEFAULT_CHANNEL)
+
+#define FILTER_OUTPUT(site, output, length, messageEnd)	\
+	FILTER_OUTPUT2(site, 0, output, length, messageEnd)
+
+#define FILTER_OUTPUT_BYTE(site, output)	\
+	FILTER_OUTPUT(site, &(const byte &)(byte)output, 1, 0)
+
+#define FILTER_OUTPUT2_MODIFIABLE(site, statement, output, length, messageEnd)	\
+	{\
+	/* fall through */ \
+	case site:	\
+	(void) statement;	\
+	if (OutputModifiable(site, output, length, messageEnd, blocking))	\
+		return STDMAX(size_t(1), length-m_inputPosition);\
+	}
+
+#define FILTER_OUTPUT_MODIFIABLE(site, output, length, messageEnd)	\
+	FILTER_OUTPUT2_MODIFIABLE(site, 0, output, length, messageEnd)
+
+#define FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, statement, output, length, messageEnd, modifiable)	\
+	{\
+	/* fall through */ \
+	case site:	\
+	(void) statement;	\
+	if (modifiable ? OutputModifiable(site, output, length, messageEnd, blocking) : Output(site, output, length, messageEnd, blocking))	\
+		return STDMAX(size_t(1), length-m_inputPosition);\
+	}
+
+#define FILTER_OUTPUT_MAYBE_MODIFIABLE(site, output, length, messageEnd, modifiable)	\
+	FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, 0, output, length, messageEnd, modifiable)
+
+#endif

+ 139 - 0
cryptopp/gcm.h

@@ -0,0 +1,139 @@
+// gcm.h - originally written and placed in the public domain by Wei Dai
+
+/// \file gcm.h
+/// \brief GCM block cipher mode of operation
+/// \since Crypto++ 5.6.0
+
+#ifndef CRYPTOPP_GCM_H
+#define CRYPTOPP_GCM_H
+
+#include "authenc.h"
+#include "modes.h"
+
+// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler
+// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232
+#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM)
+# define CRYPTOPP_DISABLE_GCM_ASM 1
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \enum GCM_TablesOption
+/// \brief GCM table size options
+enum GCM_TablesOption {
+	/// \brief Use a table with 2K entries
+	GCM_2K_Tables,
+	/// \brief Use a table with 64K entries
+	GCM_64K_Tables};
+
+/// \brief GCM block cipher base implementation
+/// \details Base implementation of the AuthenticatedSymmetricCipher interface
+/// \since Crypto++ 5.6.0
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GCM_Base : public AuthenticatedSymmetricCipherBase
+{
+public:
+	// AuthenticatedSymmetricCipher
+	std::string AlgorithmName() const
+		{return GetBlockCipher().AlgorithmName() + std::string("/GCM");}
+	std::string AlgorithmProvider() const
+		{return GetBlockCipher().AlgorithmProvider();}
+	size_t MinKeyLength() const
+		{return GetBlockCipher().MinKeyLength();}
+	size_t MaxKeyLength() const
+		{return GetBlockCipher().MaxKeyLength();}
+	size_t DefaultKeyLength() const
+		{return GetBlockCipher().DefaultKeyLength();}
+	size_t GetValidKeyLength(size_t n) const
+		{return GetBlockCipher().GetValidKeyLength(n);}
+	bool IsValidKeyLength(size_t n) const
+		{return GetBlockCipher().IsValidKeyLength(n);}
+	unsigned int OptimalDataAlignment() const;
+	IV_Requirement IVRequirement() const
+		{return UNIQUE_IV;}
+	unsigned int IVSize() const
+		{return 12;}
+	unsigned int MinIVLength() const
+		{return 1;}
+	unsigned int MaxIVLength() const
+		{return UINT_MAX;}		// (W64LIT(1)<<61)-1 in the standard
+	unsigned int DigestSize() const
+		{return 16;}
+	lword MaxHeaderLength() const
+		{return (W64LIT(1)<<61)-1;}
+	lword MaxMessageLength() const
+		{return ((W64LIT(1)<<39)-256)/8;}
+
+protected:
+	// AuthenticatedSymmetricCipherBase
+	bool AuthenticationIsOnPlaintext() const
+		{return false;}
+	unsigned int AuthenticationBlockSize() const
+		{return HASH_BLOCKSIZE;}
+	void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params);
+	void Resync(const byte *iv, size_t len);
+	size_t AuthenticateBlocks(const byte *data, size_t len);
+	void AuthenticateLastHeaderBlock();
+	void AuthenticateLastConfidentialBlock();
+	void AuthenticateLastFooterBlock(byte *mac, size_t macSize);
+	SymmetricCipher & AccessSymmetricCipher() {return m_ctr;}
+
+	virtual BlockCipher & AccessBlockCipher() =0;
+	virtual GCM_TablesOption GetTablesOption() const =0;
+
+	const BlockCipher & GetBlockCipher() const {return const_cast<GCM_Base *>(this)->AccessBlockCipher();}
+	byte *HashBuffer() {return m_buffer+REQUIRED_BLOCKSIZE;}
+	byte *HashKey() {return m_buffer+2*REQUIRED_BLOCKSIZE;}
+	byte *MulTable() {return m_buffer+3*REQUIRED_BLOCKSIZE;}
+	inline void ReverseHashBufferIfNeeded();
+
+	class CRYPTOPP_DLL GCTR : public CTR_Mode_ExternalCipher::Encryption
+	{
+	protected:
+		void IncrementCounterBy256();
+	};
+
+	GCTR m_ctr;
+	static word16 s_reductionTable[256];
+	static volatile bool s_reductionTableInitialized;
+	enum {REQUIRED_BLOCKSIZE = 16, HASH_BLOCKSIZE = 16};
+};
+
+/// \brief GCM block cipher final implementation
+/// \tparam T_BlockCipher block cipher
+/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables
+/// \tparam T_IsEncryption direction in which to operate the cipher
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher, GCM_TablesOption T_TablesOption, bool T_IsEncryption>
+class GCM_Final : public GCM_Base
+{
+public:
+	static std::string StaticAlgorithmName()
+		{return T_BlockCipher::StaticAlgorithmName() + std::string("/GCM");}
+	bool IsForwardTransformation() const
+		{return T_IsEncryption;}
+
+private:
+	GCM_TablesOption GetTablesOption() const {return T_TablesOption;}
+	BlockCipher & AccessBlockCipher() {return m_cipher;}
+	typename T_BlockCipher::Encryption m_cipher;
+};
+
+/// \brief GCM block cipher mode of operation
+/// \tparam T_BlockCipher block cipher
+/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables
+/// \details \p GCM provides the \p Encryption and \p Decryption typedef. See GCM_Base
+///   and GCM_Final for the AuthenticatedSymmetricCipher implementation.
+/// \sa <a href="http://www.cryptopp.com/wiki/GCM_Mode">GCM Mode</a> and
+///   <A HREF="http://www.cryptopp.com/wiki/Modes_of_Operation">Modes of Operation</A>
+///   on the Crypto++ wiki.
+/// \since Crypto++ 5.6.0
+template <class T_BlockCipher, GCM_TablesOption T_TablesOption=GCM_2K_Tables>
+struct GCM : public AuthenticatedSymmetricCipherDocumentation
+{
+	typedef GCM_Final<T_BlockCipher, T_TablesOption, true> Encryption;
+	typedef GCM_Final<T_BlockCipher, T_TablesOption, false> Decryption;
+};
+
+NAMESPACE_END
+
+#endif

+ 72 - 0
cryptopp/gf256.h

@@ -0,0 +1,72 @@
+// gf256.h - originally written and placed in the public domain by Wei Dai
+
+/// \file gf256.h
+/// \brief Classes and functions for schemes over GF(256)
+
+#ifndef CRYPTOPP_GF256_H
+#define CRYPTOPP_GF256_H
+
+#include "cryptlib.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief GF(256) with polynomial basis
+class GF256
+{
+public:
+	typedef byte Element;
+	typedef int RandomizationParameter;
+
+	GF256(byte modulus) : m_modulus(modulus) {}
+
+	Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const
+		{CRYPTOPP_UNUSED(ignored); return rng.GenerateByte();}
+
+	bool Equal(Element a, Element b) const
+		{return a==b;}
+
+	Element Zero() const
+		{return 0;}
+
+	Element Add(Element a, Element b) const
+		{return a^b;}
+
+	Element& Accumulate(Element &a, Element b) const
+		{return a^=b;}
+
+	Element Inverse(Element a) const
+		{return a;}
+
+	Element Subtract(Element a, Element b) const
+		{return a^b;}
+
+	Element& Reduce(Element &a, Element b) const
+		{return a^=b;}
+
+	Element Double(Element a) const
+		{CRYPTOPP_UNUSED(a); return 0;}
+
+	Element One() const
+		{return 1;}
+
+	Element Multiply(Element a, Element b) const;
+
+	Element Square(Element a) const
+		{return Multiply(a, a);}
+
+	bool IsUnit(Element a) const
+		{return a != 0;}
+
+	Element MultiplicativeInverse(Element a) const;
+
+	Element Divide(Element a, Element b) const
+		{return Multiply(a, MultiplicativeInverse(b));}
+
+private:
+	word m_modulus;
+};
+
+NAMESPACE_END
+
+#endif

+ 73 - 0
cryptopp/gf2_32.h

@@ -0,0 +1,73 @@
+// gf2_32.h - originally written and placed in the public domain by Wei Dai
+
+/// \file gf2_32.h
+/// \brief Classes and functions for schemes over GF(2^32)
+
+#ifndef CRYPTOPP_GF2_32_H
+#define CRYPTOPP_GF2_32_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief GF(2^32) with polynomial basis
+class GF2_32
+{
+public:
+	typedef word32 Element;
+	typedef int RandomizationParameter;
+
+	GF2_32(word32 modulus=0x0000008D) : m_modulus(modulus) {}
+
+	Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const
+		{CRYPTOPP_UNUSED(ignored); return rng.GenerateWord32();}
+
+	bool Equal(Element a, Element b) const
+		{return a==b;}
+
+	Element Identity() const
+		{return 0;}
+
+	Element Add(Element a, Element b) const
+		{return a^b;}
+
+	Element& Accumulate(Element &a, Element b) const
+		{return a^=b;}
+
+	Element Inverse(Element a) const
+		{return a;}
+
+	Element Subtract(Element a, Element b) const
+		{return a^b;}
+
+	Element& Reduce(Element &a, Element b) const
+		{return a^=b;}
+
+	Element Double(Element a) const
+		{CRYPTOPP_UNUSED(a); return 0;}
+
+	Element MultiplicativeIdentity() const
+		{return 1;}
+
+	Element Multiply(Element a, Element b) const;
+
+	Element Square(Element a) const
+		{return Multiply(a, a);}
+
+	bool IsUnit(Element a) const
+		{return a != 0;}
+
+	Element MultiplicativeInverse(Element a) const;
+
+	Element Divide(Element a, Element b) const
+		{return Multiply(a, MultiplicativeInverse(b));}
+
+private:
+	word32 m_modulus;
+};
+
+NAMESPACE_END
+
+#endif

+ 406 - 0
cryptopp/gf2n.h

@@ -0,0 +1,406 @@
+// gf2n.h - originally written and placed in the public domain by Wei Dai
+
+/// \file gf2n.h
+/// \brief Classes and functions for schemes over GF(2^n)
+
+#ifndef CRYPTOPP_GF2N_H
+#define CRYPTOPP_GF2N_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+#include "algebra.h"
+#include "misc.h"
+#include "asn.h"
+
+#include <iosfwd>
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4231 4275)
+#endif
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Polynomial with Coefficients in GF(2)
+/*!	\nosubgrouping */
+class CRYPTOPP_DLL PolynomialMod2
+{
+public:
+	/// \name ENUMS, EXCEPTIONS, and TYPEDEFS
+	//@{
+		/// \brief Exception thrown when divide by zero is encountered
+		class DivideByZero : public Exception
+		{
+		public:
+			DivideByZero() : Exception(OTHER_ERROR, "PolynomialMod2: division by zero") {}
+		};
+
+		typedef unsigned int RandomizationParameter;
+	//@}
+
+	/// \name CREATORS
+	//@{
+		/// \brief Construct the zero polynomial
+		PolynomialMod2();
+		/// Copy construct a PolynomialMod2
+		PolynomialMod2(const PolynomialMod2& t);
+
+		/// \brief Construct a PolynomialMod2 from a word
+		/// \details value should be encoded with the least significant bit as coefficient to x^0
+		///   and most significant bit as coefficient to x^(WORD_BITS-1)
+		///   bitLength denotes how much memory to allocate initially
+		PolynomialMod2(word value, size_t bitLength=WORD_BITS);
+
+		/// \brief Construct a PolynomialMod2 from big-endian byte array
+		PolynomialMod2(const byte *encodedPoly, size_t byteCount)
+			{Decode(encodedPoly, byteCount);}
+
+		/// \brief Construct a PolynomialMod2 from big-endian form stored in a BufferedTransformation
+		PolynomialMod2(BufferedTransformation &encodedPoly, size_t byteCount)
+			{Decode(encodedPoly, byteCount);}
+
+		/// \brief Create a uniformly distributed random polynomial
+		/// \details Create a random polynomial uniformly distributed over all polynomials with degree less than bitcount
+		PolynomialMod2(RandomNumberGenerator &rng, size_t bitcount)
+			{Randomize(rng, bitcount);}
+
+		/// \brief Provides x^i
+		/// \return x^i
+		static PolynomialMod2 CRYPTOPP_API Monomial(size_t i);
+		/// \brief Provides x^t0 + x^t1 + x^t2
+		/// \return x^t0 + x^t1 + x^t2
+		/// \pre The coefficients should be provided in descending order. That is, <pre>t0 > t1 > t2<pre>.
+		static PolynomialMod2 CRYPTOPP_API Trinomial(size_t t0, size_t t1, size_t t2);
+		/// \brief Provides x^t0 + x^t1 + x^t2 + x^t3 + x^t4
+		/// \return x^t0 + x^t1 + x^t2 + x^t3 + x^t4
+		/// \pre The coefficients should be provided in descending order. That is, <pre>t0 > t1 > t2 > t3 > t4<pre>.
+		static PolynomialMod2 CRYPTOPP_API Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4);
+		/// \brief Provides x^(n-1) + ... + x + 1
+		/// \return x^(n-1) + ... + x + 1
+		static PolynomialMod2 CRYPTOPP_API AllOnes(size_t n);
+
+		/// \brief The Zero polinomial
+		/// \return the zero polynomial
+		static const PolynomialMod2 & CRYPTOPP_API Zero();
+		/// \brief The One polinomial
+		/// \return the one polynomial
+		static const PolynomialMod2 & CRYPTOPP_API One();
+	//@}
+
+	/// \name ENCODE/DECODE
+	//@{
+		/// minimum number of bytes to encode this polynomial
+		/*! MinEncodedSize of 0 is 1 */
+		unsigned int MinEncodedSize() const {return STDMAX(1U, ByteCount());}
+
+		/// encode in big-endian format
+		/// \details if outputLen < MinEncodedSize, the most significant bytes will be dropped
+		///   if outputLen > MinEncodedSize, the most significant bytes will be padded
+		void Encode(byte *output, size_t outputLen) const;
+		///
+		void Encode(BufferedTransformation &bt, size_t outputLen) const;
+
+		///
+		void Decode(const byte *input, size_t inputLen);
+		///
+		//* Precondition: bt.MaxRetrievable() >= inputLen
+		void Decode(BufferedTransformation &bt, size_t inputLen);
+
+		/// encode value as big-endian octet string
+		void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const;
+		/// decode value as big-endian octet string
+		void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length);
+	//@}
+
+	/// \name ACCESSORS
+	//@{
+		/// number of significant bits = Degree() + 1
+		unsigned int BitCount() const;
+		/// number of significant bytes = ceiling(BitCount()/8)
+		unsigned int ByteCount() const;
+		/// number of significant words = ceiling(ByteCount()/sizeof(word))
+		unsigned int WordCount() const;
+
+		/// return the n-th bit, n=0 being the least significant bit
+		bool GetBit(size_t n) const {return GetCoefficient(n)!=0;}
+		/// return the n-th byte
+		byte GetByte(size_t n) const;
+
+		/// the zero polynomial will return a degree of -1
+		signed int Degree() const {return (signed int)(BitCount()-1U);}
+		/// degree + 1
+		unsigned int CoefficientCount() const {return BitCount();}
+		/// return coefficient for x^i
+		int GetCoefficient(size_t i) const
+			{return (i/WORD_BITS < reg.size()) ? int(reg[i/WORD_BITS] >> (i % WORD_BITS)) & 1 : 0;}
+		/// return coefficient for x^i
+		int operator[](unsigned int i) const {return GetCoefficient(i);}
+
+		///
+		bool IsZero() const {return !*this;}
+		///
+		bool Equals(const PolynomialMod2 &rhs) const;
+	//@}
+
+	/// \name MANIPULATORS
+	//@{
+		///
+		PolynomialMod2&  operator=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator&=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator^=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator+=(const PolynomialMod2& t) {return *this ^= t;}
+		///
+		PolynomialMod2&  operator-=(const PolynomialMod2& t) {return *this ^= t;}
+		///
+		PolynomialMod2&  operator*=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator/=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator%=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator<<=(unsigned int);
+		///
+		PolynomialMod2&  operator>>=(unsigned int);
+
+		///
+		void Randomize(RandomNumberGenerator &rng, size_t bitcount);
+
+		///
+		void SetBit(size_t i, int value = 1);
+		/// set the n-th byte to value
+		void SetByte(size_t n, byte value);
+
+		///
+		void SetCoefficient(size_t i, int value) {SetBit(i, value);}
+
+		///
+		void swap(PolynomialMod2 &a) {reg.swap(a.reg);}
+	//@}
+
+	/// \name UNARY OPERATORS
+	//@{
+		///
+		bool			operator!() const;
+		///
+		PolynomialMod2	operator+() const {return *this;}
+		///
+		PolynomialMod2	operator-() const {return *this;}
+	//@}
+
+	/// \name BINARY OPERATORS
+	//@{
+		///
+		PolynomialMod2 And(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Xor(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Plus(const PolynomialMod2 &b) const {return Xor(b);}
+		///
+		PolynomialMod2 Minus(const PolynomialMod2 &b) const {return Xor(b);}
+		///
+		PolynomialMod2 Times(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 DividedBy(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Modulo(const PolynomialMod2 &b) const;
+
+		///
+		PolynomialMod2 operator>>(unsigned int n) const;
+		///
+		PolynomialMod2 operator<<(unsigned int n) const;
+	//@}
+
+	/// \name OTHER ARITHMETIC FUNCTIONS
+	//@{
+		/// sum modulo 2 of all coefficients
+		unsigned int Parity() const;
+
+		/// check for irreducibility
+		bool IsIrreducible() const;
+
+		/// is always zero since we're working modulo 2
+		PolynomialMod2 Doubled() const {return Zero();}
+		///
+		PolynomialMod2 Squared() const;
+
+		/// only 1 is a unit
+		bool IsUnit() const {return Equals(One());}
+		/// return inverse if *this is a unit, otherwise return 0
+		PolynomialMod2 MultiplicativeInverse() const {return IsUnit() ? One() : Zero();}
+
+		/// greatest common divisor
+		static PolynomialMod2 CRYPTOPP_API Gcd(const PolynomialMod2 &a, const PolynomialMod2 &n);
+		/// calculate multiplicative inverse of *this mod n
+		PolynomialMod2 InverseMod(const PolynomialMod2 &) const;
+
+		/// calculate r and q such that (a == d*q + r) && (deg(r) < deg(d))
+		static void CRYPTOPP_API Divide(PolynomialMod2 &r, PolynomialMod2 &q, const PolynomialMod2 &a, const PolynomialMod2 &d);
+	//@}
+
+	/// \name INPUT/OUTPUT
+	//@{
+		///
+		friend std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a);
+	//@}
+
+private:
+	friend class GF2NT;
+	friend class GF2NT233;
+
+	SecWordBlock reg;
+};
+
+///
+inline bool operator==(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Equals(b);}
+///
+inline bool operator!=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return !(a==b);}
+/// compares degree
+inline bool operator> (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() > b.Degree();}
+/// compares degree
+inline bool operator>=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() >= b.Degree();}
+/// compares degree
+inline bool operator< (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() < b.Degree();}
+/// compares degree
+inline bool operator<=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() <= b.Degree();}
+///
+inline CryptoPP::PolynomialMod2 operator&(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.And(b);}
+///
+inline CryptoPP::PolynomialMod2 operator^(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Xor(b);}
+///
+inline CryptoPP::PolynomialMod2 operator+(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Plus(b);}
+///
+inline CryptoPP::PolynomialMod2 operator-(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Minus(b);}
+///
+inline CryptoPP::PolynomialMod2 operator*(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Times(b);}
+///
+inline CryptoPP::PolynomialMod2 operator/(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.DividedBy(b);}
+///
+inline CryptoPP::PolynomialMod2 operator%(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Modulo(b);}
+
+// CodeWarrior 8 workaround: put these template instantiations after overloaded operator declarations,
+// but before the use of QuotientRing<EuclideanDomainOf<PolynomialMod2> > for VC .NET 2003
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup<PolynomialMod2>;
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing<PolynomialMod2>;
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain<PolynomialMod2>;
+CRYPTOPP_DLL_TEMPLATE_CLASS EuclideanDomainOf<PolynomialMod2>;
+CRYPTOPP_DLL_TEMPLATE_CLASS QuotientRing<EuclideanDomainOf<PolynomialMod2> >;
+
+/// \brief GF(2^n) with Polynomial Basis
+class CRYPTOPP_DLL GF2NP : public QuotientRing<EuclideanDomainOf<PolynomialMod2> >
+{
+public:
+	GF2NP(const PolynomialMod2 &modulus);
+
+	virtual GF2NP * Clone() const {return new GF2NP(*this);}
+	virtual void DEREncode(BufferedTransformation &bt) const
+		{CRYPTOPP_UNUSED(bt); CRYPTOPP_ASSERT(false);}	// no ASN.1 syntax yet for general polynomial basis
+
+	void DEREncodeElement(BufferedTransformation &out, const Element &a) const;
+	void BERDecodeElement(BufferedTransformation &in, Element &a) const;
+
+	bool Equal(const Element &a, const Element &b) const
+		{CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree() && b.Degree() < m_modulus.Degree()); return a.Equals(b);}
+
+	bool IsUnit(const Element &a) const
+		{CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree()); return !!a;}
+
+	unsigned int MaxElementBitLength() const
+		{return m;}
+
+	unsigned int MaxElementByteLength() const
+		{return (unsigned int)BitsToBytes(MaxElementBitLength());}
+
+	Element SquareRoot(const Element &a) const;
+
+	Element HalfTrace(const Element &a) const;
+
+	// returns z such that z^2 + z == a
+	Element SolveQuadraticEquation(const Element &a) const;
+
+protected:
+	unsigned int m;
+};
+
+/// \brief GF(2^n) with Trinomial Basis
+class CRYPTOPP_DLL GF2NT : public GF2NP
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2
+	GF2NT(unsigned int t0, unsigned int t1, unsigned int t2);
+
+	GF2NP * Clone() const {return new GF2NT(*this);}
+	void DEREncode(BufferedTransformation &bt) const;
+
+	const Element& Multiply(const Element &a, const Element &b) const;
+
+	const Element& Square(const Element &a) const
+		{return Reduced(a.Squared());}
+
+	const Element& MultiplicativeInverse(const Element &a) const;
+
+protected:
+	const Element& Reduced(const Element &a) const;
+
+	unsigned int t0, t1;
+	mutable PolynomialMod2 result;
+};
+
+/// \brief GF(2^n) for b233 and k233
+/// \details GF2NT233 is a specialization of GF2NT that provides Multiply()
+///   and Square() operations when carryless multiplies is available.
+class CRYPTOPP_DLL GF2NT233 : public GF2NT
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2
+	GF2NT233(unsigned int t0, unsigned int t1, unsigned int t2);
+
+	GF2NP * Clone() const {return new GF2NT233(*this);}
+
+	const Element& Multiply(const Element &a, const Element &b) const;
+
+	const Element& Square(const Element &a) const;
+};
+
+/// \brief GF(2^n) with Pentanomial Basis
+class CRYPTOPP_DLL GF2NPP : public GF2NP
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2 + x^t3 + x^t4, t0 > t1 > t2 > t3 > t4
+	GF2NPP(unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4)
+		: GF2NP(PolynomialMod2::Pentanomial(t0, t1, t2, t3, t4)), t1(t1), t2(t2), t3(t3) {}
+
+	GF2NP * Clone() const {return new GF2NPP(*this);}
+	void DEREncode(BufferedTransformation &bt) const;
+
+private:
+	unsigned int t1, t2, t3;
+};
+
+// construct new GF2NP from the ASN.1 sequence Characteristic-two
+CRYPTOPP_DLL GF2NP * CRYPTOPP_API BERDecodeGF2NP(BufferedTransformation &bt);
+
+NAMESPACE_END
+
+#ifndef __BORLANDC__
+NAMESPACE_BEGIN(std)
+template<> inline void swap(CryptoPP::PolynomialMod2 &a, CryptoPP::PolynomialMod2 &b)
+{
+	a.swap(b);
+}
+NAMESPACE_END
+#endif
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

+ 1036 - 0
cryptopp/gfpcrypt.h

@@ -0,0 +1,1036 @@
+// gfpcrypt.h - originally written and placed in the public domain by Wei Dai
+//              RFC6979 deterministic signatures added by Douglas Roark
+//              ECGDSA added by Jeffrey Walton
+
+/// \file gfpcrypt.h
+/// \brief Classes and functions for schemes based on Discrete Logs (DL) over GF(p)
+
+#ifndef CRYPTOPP_GFPCRYPT_H
+#define CRYPTOPP_GFPCRYPT_H
+
+#include "config.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4189 4231 4275)
+#endif
+
+#include "cryptlib.h"
+#include "pubkey.h"
+#include "integer.h"
+#include "modexppc.h"
+#include "algparam.h"
+#include "smartptr.h"
+#include "sha.h"
+#include "asn.h"
+#include "hmac.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters<Integer>;
+
+/// \brief Integer-based GroupParameters specialization
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBased : public ASN1CryptoMaterial<DL_GroupParameters<Integer> >
+{
+    typedef DL_GroupParameters_IntegerBased ThisClass;
+
+public:
+    virtual ~DL_GroupParameters_IntegerBased() {}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param params the group parameters
+    void Initialize(const DL_GroupParameters_IntegerBased &params)
+        {Initialize(params.GetModulus(), params.GetSubgroupOrder(), params.GetSubgroupGenerator());}
+
+    /// \brief Create a group parameters over integers
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param pbits the size of p, in bits
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, unsigned int pbits)
+        {GenerateRandom(rng, MakeParameters("ModulusSize", (int)pbits));}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param p the modulus
+    /// \param g the generator
+    void Initialize(const Integer &p, const Integer &g)
+        {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(ComputeGroupOrder(p)/2);}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    void Initialize(const Integer &p, const Integer &q, const Integer &g)
+        {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(q);}
+
+    // ASN1Object interface
+    void BERDecode(BufferedTransformation &bt);
+    void DEREncode(BufferedTransformation &bt) const;
+
+    /// \brief Generate a random key
+    /// \param rng a RandomNumberGenerator to produce keying material
+    /// \param alg additional initialization parameters
+    /// \details Recognised NameValuePairs are ModulusSize and
+    ///  SubgroupOrderSize (optional)
+    /// \throw KeyingErr if a key can't be generated or algorithm parameters
+    ///  are invalid
+    void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
+
+    /// \brief Get a named value
+    /// \param name the name of the object or value to retrieve
+    /// \param valueType reference to a variable that receives the value
+    /// \param pValue void pointer to a variable that receives the value
+    /// \return true if the value was retrieved, false otherwise
+    /// \details GetVoidValue() retrieves the value of name if it exists.
+    /// \note GetVoidValue() is an internal function and should be implemented
+    ///  by derived classes. Users should use one of the other functions instead.
+    /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+    ///  GetRequiredParameter() and GetRequiredIntParameter()
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+
+    /// \brief Initialize or reinitialize this key
+    /// \param source NameValuePairs to assign
+    void AssignFrom(const NameValuePairs &source);
+
+    // DL_GroupParameters
+    const Integer & GetSubgroupOrder() const {return m_q;}
+    Integer GetGroupOrder() const {return GetFieldType() == 1 ? GetModulus()-Integer::One() : GetModulus()+Integer::One();}
+    bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const;
+    bool ValidateElement(unsigned int level, const Integer &element, const DL_FixedBasePrecomputation<Integer> *precomp) const;
+
+    /// \brief Determine if subgroup membership check is fast
+    /// \return true or false
+    bool FastSubgroupCheckAvailable() const {return GetCofactor() == 2;}
+
+    /// \brief Encodes the element
+    /// \param reversible flag indicating the encoding format
+    /// \param element reference to the element to encode
+    /// \param encoded destination byte array for the encoded element
+    /// \details EncodeElement() must be implemented in a derived class.
+    /// \pre <tt>COUNTOF(encoded) == GetEncodedElementSize()</tt>
+    /// \sa GetEncodedElementSize(), DecodeElement(), <A
+    ///  HREF="http://github.com/weidai11/cryptopp/issues/40">Cygwin
+    ///  i386 crash at -O3</A>
+    void EncodeElement(bool reversible, const Element &element, byte *encoded) const;
+
+    /// \brief Retrieve the encoded element's size
+    /// \param reversible flag indicating the encoding format
+    /// \return encoded element's size, in bytes
+    /// \details The format of the encoded element varies by the underlying
+    ///  type of the element and the reversible flag.
+    /// \sa EncodeElement(), DecodeElement()
+    unsigned int GetEncodedElementSize(bool reversible) const;
+
+    /// \brief Decodes the element
+    /// \param encoded byte array with the encoded element
+    /// \param checkForGroupMembership flag indicating if the element should be validated
+    /// \return Element after decoding
+    /// \details DecodeElement() must be implemented in a derived class.
+    /// \pre <tt>COUNTOF(encoded) == GetEncodedElementSize()</tt>
+    /// \sa GetEncodedElementSize(), EncodeElement()
+    Integer DecodeElement(const byte *encoded, bool checkForGroupMembership) const;
+
+    /// \brief Converts an element to an Integer
+    /// \param element the element to convert to an Integer
+    /// \return Element after converting to an Integer
+    /// \details ConvertElementToInteger() must be implemented in a derived class.
+    Integer ConvertElementToInteger(const Element &element) const
+        {return element;}
+
+    /// \brief Retrieve the maximum exponent for the group
+    /// \return the maximum exponent for the group
+    Integer GetMaxExponent() const;
+
+    /// \brief Retrieve the OID of the algorithm
+    /// \return OID of the algorithm
+    OID GetAlgorithmID() const;
+
+    /// \brief Retrieve the modulus for the group
+    /// \return the modulus for the group
+    virtual const Integer & GetModulus() const =0;
+
+    /// \brief Set group parameters
+    /// \param p the prime modulus
+    /// \param g the group generator
+    virtual void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) =0;
+
+    /// \brief Set subgroup order
+    /// \param q the subgroup order
+    void SetSubgroupOrder(const Integer &q)
+        {m_q = q; ParametersChanged();}
+
+    static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "";}
+
+protected:
+    Integer ComputeGroupOrder(const Integer &modulus) const
+        {return modulus-(GetFieldType() == 1 ? 1 : -1);}
+
+    // GF(p) = 1, GF(p^2) = 2
+    virtual int GetFieldType() const =0;
+    virtual unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const;
+
+private:
+    Integer m_q;
+};
+
+/// \brief Integer-based GroupParameters default implementation
+/// \tparam GROUP_PRECOMP group parameters precomputation specialization
+/// \tparam BASE_PRECOMP base class precomputation specialization
+template <class GROUP_PRECOMP, class BASE_PRECOMP = DL_FixedBasePrecomputationImpl<typename GROUP_PRECOMP::Element> >
+class CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBasedImpl : public DL_GroupParametersImpl<GROUP_PRECOMP, BASE_PRECOMP, DL_GroupParameters_IntegerBased>
+{
+    typedef DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> ThisClass;
+
+public:
+    typedef typename GROUP_PRECOMP::Element Element;
+
+    virtual ~DL_GroupParameters_IntegerBasedImpl() {}
+
+    // GeneratibleCryptoMaterial interface
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+        {return GetValueHelper<DL_GroupParameters_IntegerBased>(this, name, valueType, pValue).Assignable();}
+
+    void AssignFrom(const NameValuePairs &source)
+        {AssignFromHelper<DL_GroupParameters_IntegerBased>(this, source);}
+
+    // DL_GroupParameters
+    const DL_FixedBasePrecomputation<Element> & GetBasePrecomputation() const {return this->m_gpc;}
+    DL_FixedBasePrecomputation<Element> & AccessBasePrecomputation() {return this->m_gpc;}
+
+    // IntegerGroupParameters
+    /// \brief Retrieve the modulus for the group
+    /// \return the modulus for the group
+    const Integer & GetModulus() const {return this->m_groupPrecomputation.GetModulus();}
+
+    /// \brief Retrieves a reference to the group generator
+    /// \return const reference to the group generator
+    const Integer & GetGenerator() const {return this->m_gpc.GetBase(this->GetGroupPrecomputation());}
+
+    void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g)        // these have to be set together
+        {this->m_groupPrecomputation.SetModulus(p); this->m_gpc.SetBase(this->GetGroupPrecomputation(), g); this->ParametersChanged();}
+
+    // non-inherited
+    bool operator==(const DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> &rhs) const
+        {return GetModulus() == rhs.GetModulus() && GetGenerator() == rhs.GetGenerator() && this->GetSubgroupOrder() == rhs.GetSubgroupOrder();}
+    bool operator!=(const DL_GroupParameters_IntegerBasedImpl<GROUP_PRECOMP, BASE_PRECOMP> &rhs) const
+        {return !operator==(rhs);}
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_IntegerBasedImpl<ModExpPrecomputation>;
+
+/// \brief GF(p) group parameters
+class CRYPTOPP_DLL DL_GroupParameters_GFP : public DL_GroupParameters_IntegerBasedImpl<ModExpPrecomputation>
+{
+public:
+    virtual ~DL_GroupParameters_GFP() {}
+
+    /// \brief Determines if an element is an identity
+    /// \param element element to check
+    /// \return true if the element is an identity, false otherwise
+    /// \details The identity element or or neutral element is a special element
+    ///  in a group that leaves other elements unchanged when combined with it.
+    /// \details IsIdentity() must be implemented in a derived class.
+    bool IsIdentity(const Integer &element) const {return element == Integer::One();}
+
+    /// \brief Exponentiates a base to multiple exponents
+    /// \param results an array of Elements
+    /// \param base the base to raise to the exponents
+    /// \param exponents an array of exponents
+    /// \param exponentsCount the number of exponents in the array
+    /// \details SimultaneousExponentiate() raises the base to each exponent in
+    ///  the exponents array and stores the result at the respective position in
+    ///  the results array.
+    /// \details SimultaneousExponentiate() must be implemented in a derived class.
+    /// \pre <tt>COUNTOF(results) == exponentsCount</tt>
+    /// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
+    void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
+
+    /// \brief Get a named value
+    /// \param name the name of the object or value to retrieve
+    /// \param valueType reference to a variable that receives the value
+    /// \param pValue void pointer to a variable that receives the value
+    /// \return true if the value was retrieved, false otherwise
+    /// \details GetVoidValue() retrieves the value of name if it exists.
+    /// \note GetVoidValue() is an internal function and should be implemented
+    ///  by derived classes. Users should use one of the other functions instead.
+    /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+    ///  GetRequiredParameter() and GetRequiredIntParameter()
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+    {
+        return GetValueHelper<DL_GroupParameters_IntegerBased>(this, name, valueType, pValue).Assignable();
+    }
+
+    // used by MQV
+    Element MultiplyElements(const Element &a, const Element &b) const;
+    Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const;
+
+protected:
+    int GetFieldType() const {return 1;}
+};
+
+/// \brief GF(p) group parameters that default to safe primes
+class CRYPTOPP_DLL DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupParameters_GFP
+{
+public:
+    typedef NoCofactorMultiplication DefaultCofactorOption;
+
+    virtual ~DL_GroupParameters_GFP_DefaultSafePrime() {}
+
+protected:
+    unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;}
+};
+
+/// ElGamal encryption for safe interop
+/// \sa <A HREF="https://eprint.iacr.org/2021/923.pdf">On the
+///  (in)security of ElGamal in OpenPGP</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/1059">Issue 1059</A>,
+///  <A HREF="https://nvd.nist.gov/vuln/detail/CVE-2021-40530">CVE-2021-40530</A>
+/// \since Crypto++ 8.6
+class CRYPTOPP_DLL DL_GroupParameters_ElGamal : public DL_GroupParameters_GFP_DefaultSafePrime
+{
+public:
+    typedef NoCofactorMultiplication DefaultCofactorOption;
+
+    virtual ~DL_GroupParameters_ElGamal() {}
+
+	Integer GetMaxExponent() const
+	{
+		return GetSubgroupOrder()-1;
+	}
+};
+
+/// \brief GDSA algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement <tt>T</tt> can be Integer, ECP or EC2N.
+template <class T>
+class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T>
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-1363";}
+
+    virtual ~DL_Algorithm_GDSA() {}
+
+    void Sign(const DL_GroupParameters<T> &params, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        r %= q;
+        Integer kInv = k.InverseMod(q);
+        s = (kInv * (x*r + e)) % q;
+        CRYPTOPP_ASSERT(!!r && !!s);
+    }
+
+    bool Verify(const DL_GroupParameters<T> &params, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q || s<1)
+            return false;
+
+        Integer w = s.InverseMod(q);
+        Integer u1 = (e * w) % q;
+        Integer u2 = (r * w) % q;
+        // verify r == (g^u1 * y^u2 mod p) mod q
+        return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q;
+    }
+};
+
+/// \brief DSA signature algorithm based on RFC 6979
+/// \tparam T FieldElement type or class
+/// \tparam H HashTransformation derived class
+/// \details FieldElement <tt>T</tt> can be Integer, ECP or EC2N.
+/// \sa <a href="http://tools.ietf.org/rfc/rfc6979.txt">RFC 6979, Deterministic Usage of the
+///  Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)</a>
+/// \since Crypto++ 6.0
+template <class T, class H>
+class DL_Algorithm_DSA_RFC6979 : public DL_Algorithm_GDSA<T>, public DeterministicSignatureAlgorithm
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-RFC6979";}
+
+    virtual ~DL_Algorithm_DSA_RFC6979() {}
+
+    bool IsProbabilistic() const
+        {return false;}
+    bool IsDeterministic() const
+        {return true;}
+
+    // Deterministic K
+    Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const
+    {
+        static const byte zero = 0, one = 1;
+        const size_t qlen = q.BitCount();
+        const size_t rlen = BitsToBytes(qlen);
+
+        // Step (a) - formatted E(m)
+        SecByteBlock BH(e.MinEncodedSize());
+        e.Encode(BH, BH.size());
+        BH = bits2octets(BH, q);
+
+        // Step (a) - private key to byte array
+        SecByteBlock BX(STDMAX(rlen, x.MinEncodedSize()));
+        x.Encode(BX, BX.size());
+
+        // Step (b)
+        SecByteBlock V(H::DIGESTSIZE);
+        std::fill(V.begin(), V.begin()+H::DIGESTSIZE, one);
+
+        // Step (c)
+        SecByteBlock K(H::DIGESTSIZE);
+        std::fill(K.begin(), K.begin()+H::DIGESTSIZE, zero);
+
+        // Step (d)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.Update(&zero, 1);
+        m_hmac.Update(BX, BX.size());
+        m_hmac.Update(BH, BH.size());
+        m_hmac.TruncatedFinal(K, K.size());
+
+        // Step (e)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.TruncatedFinal(V, V.size());
+
+        // Step (f)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.Update(&one, 1);
+        m_hmac.Update(BX, BX.size());
+        m_hmac.Update(BH, BH.size());
+        m_hmac.TruncatedFinal(K, K.size());
+
+        // Step (g)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.TruncatedFinal(V, V.size());
+
+        Integer k;
+        SecByteBlock temp(rlen);
+        for (;;)
+        {
+            // We want qlen bits, but we support only hash functions with an output length
+            //   multiple of 8; hence, we will gather rlen bits, i.e., rolen octets.
+            size_t toff = 0;
+            while (toff < rlen)
+            {
+                m_hmac.Update(V, V.size());
+                m_hmac.TruncatedFinal(V, V.size());
+
+                size_t cc = STDMIN(V.size(), temp.size() - toff);
+                memcpy_s(temp+toff, temp.size() - toff, V, cc);
+                toff += cc;
+            }
+
+            k = bits2int(temp, qlen);
+            if (k > 0 && k < q)
+                break;
+
+            // k is not in the proper range; update K and V, and loop.
+            m_hmac.Update(V, V.size());
+            m_hmac.Update(&zero, 1);
+            m_hmac.TruncatedFinal(K, K.size());
+
+            m_hmac.SetKey(K, K.size());
+            m_hmac.Update(V, V.size());
+            m_hmac.TruncatedFinal(V, V.size());
+        }
+
+        return k;
+    }
+
+protected:
+
+    Integer bits2int(const SecByteBlock& bits, size_t qlen) const
+    {
+        Integer ret(bits, bits.size());
+        size_t blen = bits.size()*8;
+
+        if (blen > qlen)
+            ret >>= blen - qlen;
+
+        return ret;
+    }
+
+    // RFC 6979 support function. Takes an integer and converts it into bytes that
+    // are the same length as an elliptic curve's order.
+    SecByteBlock int2octets(const Integer& val, size_t rlen) const
+    {
+        SecByteBlock block(val.MinEncodedSize());
+        val.Encode(block, val.MinEncodedSize());
+
+        if (block.size() == rlen)
+            return block;
+
+        // The least significant bytes are the ones we need to preserve.
+        SecByteBlock t(rlen);
+        if (block.size() > rlen)
+        {
+            size_t offset = block.size() - rlen;
+            std::memcpy(t, block + offset, rlen);
+        }
+        else // block.size() < rlen
+        {
+            size_t offset = rlen - block.size();
+            std::memset(t, '\x00', offset);
+            std::memcpy(t + offset, block, rlen - offset);
+        }
+
+        return t;
+    }
+
+    // Turn a stream of bits into a set of bytes with the same length as an elliptic
+    // curve's order.
+    SecByteBlock bits2octets(const SecByteBlock& in, const Integer& q) const
+    {
+        Integer b2 = bits2int(in, q.BitCount());
+        Integer b1 = b2 - q;
+        return int2octets(b1.IsNegative() ? b2 : b1, q.ByteCount());
+    }
+
+private:
+    mutable H m_hash;
+    mutable HMAC<H> m_hmac;
+};
+
+/// \brief German Digital Signature Algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement <tt>T</tt> can be Integer, ECP or EC2N.
+/// \details The Digital Signature Scheme ECGDSA does not define the algorithm over integers. Rather, the
+///  signature algorithm is only defined over elliptic curves. However, the library design is such that the
+///  generic algorithm reside in <tt>gfpcrypt.h</tt>.
+/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf <A HREF="http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf">
+///  The Digital Signature Scheme ECGDSA (October 24, 2006)</A>
+template <class T>
+class DL_Algorithm_GDSA_ISO15946 : public DL_ElgamalLikeSignatureAlgorithm<T>
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "GDSA-ISO15946";}
+
+    virtual ~DL_Algorithm_GDSA_ISO15946() {}
+
+    void Sign(const DL_GroupParameters<T> &params, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        // r = x(k * G) mod q
+        r = params.ConvertElementToInteger(params.ExponentiateBase(k)) % q;
+        // s = (k * r - h(m)) * d_A mod q
+        s = (k * r - e) * x % q;
+        CRYPTOPP_ASSERT(!!r && !!s);
+    }
+
+    bool Verify(const DL_GroupParameters<T> &params, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q || s<1)
+            return false;
+
+        const Integer& rInv = r.InverseMod(q);
+        const Integer u1 = (rInv * e) % q;
+        const Integer u2 = (rInv * s) % q;
+        // verify x(G^u1 + P_A^u2) mod q
+        return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q;
+    }
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<Integer>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979<Integer, SHA1>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979<Integer, SHA224>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979<Integer, SHA256>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979<Integer, SHA384>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979<Integer, SHA512>;
+
+/// \brief NR algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement <tt>T</tt> can be Integer, ECP or EC2N.
+template <class T>
+class DL_Algorithm_NR : public DL_ElgamalLikeSignatureAlgorithm<T>
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "NR";}
+
+    virtual ~DL_Algorithm_NR() {}
+
+    void Sign(const DL_GroupParameters<T> &params, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        r = (r + e) % q;
+        s = (k - x*r) % q;
+        CRYPTOPP_ASSERT(!!r);
+    }
+
+    bool Verify(const DL_GroupParameters<T> &params, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q)
+            return false;
+
+        // check r == (m_g^s * m_y^r + m) mod m_q
+        return r == (params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(s, r)) + e) % q;
+    }
+};
+
+/// \brief Discrete Log (DL) public key in GF(p) groups
+/// \tparam GP GroupParameters derived class
+/// \details DSA public key format is defined in 7.3.3 of RFC 2459. The    private key format is defined in 12.9 of PKCS #11 v2.10.
+template <class GP>
+class DL_PublicKey_GFP : public DL_PublicKeyImpl<GP>
+{
+public:
+    virtual ~DL_PublicKey_GFP() {}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param params the group parameters
+    /// \param y the public element
+    void Initialize(const DL_GroupParameters_IntegerBased &params, const Integer &y)
+        {this->AccessGroupParameters().Initialize(params); this->SetPublicElement(y);}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param p the modulus
+    /// \param g the generator
+    /// \param y the public element
+    void Initialize(const Integer &p, const Integer &g, const Integer &y)
+        {this->AccessGroupParameters().Initialize(p, g); this->SetPublicElement(y);}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \param y the public element
+    void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &y)
+        {this->AccessGroupParameters().Initialize(p, q, g); this->SetPublicElement(y);}
+
+    // X509PublicKey
+    void BERDecodePublicKey(BufferedTransformation &bt, bool, size_t)
+        {this->SetPublicElement(Integer(bt));}
+    void DEREncodePublicKey(BufferedTransformation &bt) const
+        {this->GetPublicElement().DEREncode(bt);}
+};
+
+/// \brief Discrete Log (DL) private key in GF(p) groups
+/// \tparam GP GroupParameters derived class
+template <class GP>
+class DL_PrivateKey_GFP : public DL_PrivateKeyImpl<GP>
+{
+public:
+    virtual ~DL_PrivateKey_GFP();
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param modulusBits the size of the modulus, in bits
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits)
+        {this->GenerateRandomWithKeySize(rng, modulusBits);}
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param p the modulus
+    /// \param g the generator
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &g)
+        {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupGenerator", g));}
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &q, const Integer &g)
+        {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupOrder", q)("SubgroupGenerator", g));}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param params the group parameters
+    /// \param x the private exponent
+    void Initialize(const DL_GroupParameters_IntegerBased &params, const Integer &x)
+        {this->AccessGroupParameters().Initialize(params); this->SetPrivateExponent(x);}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param p the modulus
+    /// \param g the generator
+    /// \param x the private exponent
+    void Initialize(const Integer &p, const Integer &g, const Integer &x)
+        {this->AccessGroupParameters().Initialize(p, g); this->SetPrivateExponent(x);}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \param x the private exponent
+    void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &x)
+        {this->AccessGroupParameters().Initialize(p, q, g); this->SetPrivateExponent(x);}
+};
+
+// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499
+template <class GP>
+DL_PrivateKey_GFP<GP>::~DL_PrivateKey_GFP() {}
+
+/// \brief Discrete Log (DL) signing/verification keys in GF(p) groups
+struct DL_SignatureKeys_GFP
+{
+    typedef DL_GroupParameters_GFP GroupParameters;
+    typedef DL_PublicKey_GFP<GroupParameters> PublicKey;
+    typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey;
+};
+
+/// \brief Discrete Log (DL) encryption/decryption keys in GF(p) groups
+struct DL_CryptoKeys_GFP
+{
+    typedef DL_GroupParameters_GFP_DefaultSafePrime GroupParameters;
+    typedef DL_PublicKey_GFP<GroupParameters> PublicKey;
+    typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey;
+};
+
+/// ElGamal encryption keys for safe interop
+/// \sa <A HREF="https://eprint.iacr.org/2021/923.pdf">On the
+///  (in)security of ElGamal in OpenPGP</A>,
+///  <A HREF="https://github.com/weidai11/cryptopp/issues/1059">Issue 1059</A>,
+///  <A HREF="https://nvd.nist.gov/vuln/detail/CVE-2021-40530">CVE-2021-40530</A>
+/// \since Crypto++ 8.6
+struct DL_CryptoKeys_ElGamal
+{
+    typedef DL_GroupParameters_ElGamal GroupParameters;
+    typedef DL_PublicKey_GFP<GroupParameters> PublicKey;
+    typedef DL_PrivateKey_GFP<GroupParameters> PrivateKey;
+};
+
+/// \brief DSA signature scheme
+/// \tparam H HashTransformation derived class
+/// \sa <a href="http://www.weidai.com/scan-mirror/sig.html#DSA-1363">DSA-1363</a>
+/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2
+template <class H>
+struct GDSA : public DL_SS<
+    DL_SignatureKeys_GFP,
+    DL_Algorithm_GDSA<Integer>,
+    DL_SignatureMessageEncodingMethod_DSA,
+    H>
+{
+};
+
+/// \brief NR signature scheme
+/// \tparam H HashTransformation derived class
+/// \sa <a href="http://www.weidai.com/scan-mirror/sig.html#NR">NR</a>
+template <class H>
+struct NR : public DL_SS<
+    DL_SignatureKeys_GFP,
+    DL_Algorithm_NR<Integer>,
+    DL_SignatureMessageEncodingMethod_NR,
+    H>
+{
+};
+
+/// \brief DSA group parameters
+/// \details These are GF(p) group parameters that are allowed by the DSA standard
+/// \sa DL_Keys_DSA
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL DL_GroupParameters_DSA : public DL_GroupParameters_GFP
+{
+public:
+    virtual ~DL_GroupParameters_DSA() {}
+
+    /// \brief Check the group for errors
+    /// \param rng RandomNumberGenerator for objects which use randomized testing
+    /// \param level level of thoroughness
+    /// \return true if the tests succeed, false otherwise
+    /// \details ValidateGroup() also checks that the lengths of p and q are allowed
+    ///  by the DSA standard.
+    /// \details There are four levels of thoroughness:
+    ///  <ul>
+    ///  <li>0 - using this object won't cause a crash or exception
+    ///  <li>1 - this object will probably function, and encrypt, sign, other operations correctly
+    ///  <li>2 - ensure this object will function correctly, and perform reasonable security checks
+    ///  <li>3 - perform reasonable security checks, and do checks that may take a long time
+    ///  </ul>
+    /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0.
+    ///  Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended.
+    bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const;
+
+    /// \brief Generate a random key or crypto parameters
+    /// \param rng a RandomNumberGenerator to produce keying material
+    /// \param alg additional initialization parameters
+    /// \details NameValuePairs can be ModulusSize alone; or Modulus, SubgroupOrder, and
+    ///  SubgroupGenerator. ModulusSize must be between <tt>DSA::MIN_PRIME_LENGTH</tt> and
+    ///  <tt>DSA::MAX_PRIME_LENGTH</tt>, and divisible by <tt>DSA::PRIME_LENGTH_MULTIPLE</tt>.
+    /// \details An example of changing the modulus size using NameValuePairs is shown below.
+    /// <pre>
+    ///  AlgorithmParameters params = MakeParameters
+    ///    (Name::ModulusSize(), 2048);
+    ///
+    ///  DL_GroupParameters_DSA groupParams;
+    ///  groupParams.GenerateRandom(prng, params);
+    /// </pre>
+    /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid.
+    void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
+
+    /// \brief Check the prime length for errors
+    /// \param pbits number of bits in the prime number
+    /// \return true if the tests succeed, false otherwise
+    static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits)
+        {return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;}
+
+    /// \brief DSA prime length
+    enum {
+        /// \brief Minimum prime length
+        MIN_PRIME_LENGTH = 1024,
+        /// \brief Maximum prime length
+        MAX_PRIME_LENGTH = 3072,
+        /// \brief Prime length multiple
+        PRIME_LENGTH_MULTIPLE = 1024
+    };
+};
+
+template <class H>
+class DSA2;
+
+/// \brief DSA keys
+/// \sa DL_GroupParameters_DSA
+/// \since Crypto++ 1.0
+struct DL_Keys_DSA
+{
+    typedef DL_PublicKey_GFP<DL_GroupParameters_DSA> PublicKey;
+    typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA2<SHA1> > PrivateKey;
+};
+
+/// \brief DSA signature scheme
+/// \tparam H HashTransformation derived class
+/// \details The class is named DSA2 instead of DSA for backwards compatibility because
+///  DSA was a non-template class.
+/// \details DSA default method GenerateRandom uses a 2048-bit modulus and a 224-bit subgoup by default.
+///  The modulus can be changed using the following code:
+/// <pre>
+///  DSA::PrivateKey privateKey;
+///  privateKey.GenerateRandomWithKeySize(prng, 2048);
+/// </pre>
+/// \details The subgroup order can be changed using the following code:
+/// <pre>
+///  AlgorithmParameters params = MakeParameters
+///    (Name::ModulusSize(), 2048)
+///    (Name::SubgroupOrderSize(), 256);
+///
+///  DSA::PrivateKey privateKey;
+///  privateKey.GenerateRandom(prng, params);
+/// </pre>
+/// \sa <a href="http://en.wikipedia.org/wiki/Digital_Signature_Algorithm">DSA</a>, as specified in FIPS 186-3,
+///  <a href="https://www.cryptopp.com/wiki/Digital_Signature_Algorithm">Digital Signature Algorithm</a> on the wiki, and
+///  <a href="https://www.cryptopp.com/wiki/NameValuePairs">NameValuePairs</a> on the wiki.
+/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2, Crypto++ 6.1 for 2048-bit modulus.
+template <class H>
+class DSA2 : public DL_SS<
+    DL_Keys_DSA,
+    DL_Algorithm_GDSA<Integer>,
+    DL_SignatureMessageEncodingMethod_DSA,
+    H,
+    DSA2<H> >
+{
+public:
+    static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();}
+};
+
+/// \brief DSA deterministic signature scheme
+/// \tparam H HashTransformation derived class
+/// \sa <a href="http://www.weidai.com/scan-mirror/sig.html#DSA-1363">DSA-1363</a>
+/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2
+template <class H>
+struct DSA_RFC6979 : public DL_SS<
+    DL_SignatureKeys_GFP,
+    DL_Algorithm_DSA_RFC6979<Integer, H>,
+    DL_SignatureMessageEncodingMethod_DSA,
+    H,
+    DSA_RFC6979<H> >
+{
+    static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("DSA-RFC6979/") + H::StaticAlgorithmName();}
+};
+
+/// DSA with SHA-1, typedef'd for backwards compatibility
+typedef DSA2<SHA1> DSA;
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_GFP<DL_GroupParameters_DSA>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_GFP<DL_GroupParameters_DSA>;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA2<SHA1> >;
+
+/// \brief P1363 based XOR Encryption Method
+/// \tparam MAC MessageAuthenticationCode derived class used for MAC computation
+/// \tparam DHAES_MODE flag indicating DHAES mode
+/// \tparam LABEL_OCTETS flag indicating the label is octet count
+/// \details DL_EncryptionAlgorithm_Xor is based on an early P1363 draft, which itself appears to be based on an
+///  early Certicom SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used it in its Integrated
+///  Ecryption Schemes with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=false</tt> and <tt>LABEL_OCTETS=true</tt>.
+/// \details If you need this method for Crypto++ 4.2 compatibility, then use the ECIES template class with
+///  <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=false</tt> and <tt>LABEL_OCTETS=true</tt>.
+/// \details If you need this method for Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES template class with
+///  <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=true</tt> and <tt>LABEL_OCTETS=false</tt>.
+/// \details Bouncy Castle 1.54 and Botan 1.11 compatibility are the default template parameters.
+/// \since Crypto++ 4.0
+template <class MAC, bool DHAES_MODE, bool LABEL_OCTETS=false>
+class DL_EncryptionAlgorithm_Xor : public DL_SymmetricEncryptionAlgorithm
+{
+public:
+    virtual ~DL_EncryptionAlgorithm_Xor() {}
+
+    bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;}
+    size_t GetSymmetricKeyLength(size_t plaintextLength) const
+        {return plaintextLength + static_cast<size_t>(MAC::DEFAULT_KEYLENGTH);}
+    size_t GetSymmetricCiphertextLength(size_t plaintextLength) const
+        {return plaintextLength + static_cast<size_t>(MAC::DIGESTSIZE);}
+    size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const
+        {return SaturatingSubtract(ciphertextLength, static_cast<size_t>(MAC::DIGESTSIZE));}
+    void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs &parameters) const
+    {
+        CRYPTOPP_UNUSED(rng);
+        const byte *cipherKey = NULLPTR, *macKey = NULLPTR;
+        if (DHAES_MODE)
+        {
+            macKey = key;
+            cipherKey = key + MAC::DEFAULT_KEYLENGTH;
+        }
+        else
+        {
+            cipherKey = key;
+            macKey = key + plaintextLength;
+        }
+
+        ConstByteArrayParameter encodingParameters;
+        parameters.GetValue(Name::EncodingParameters(), encodingParameters);
+
+        if (plaintextLength)    // Coverity finding
+            xorbuf(ciphertext, plaintext, cipherKey, plaintextLength);
+
+        MAC mac(macKey);
+        mac.Update(ciphertext, plaintextLength);
+        mac.Update(encodingParameters.begin(), encodingParameters.size());
+        if (DHAES_MODE)
+        {
+            byte L[8];
+            PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size())));
+            mac.Update(L, 8);
+        }
+        mac.Final(ciphertext + plaintextLength);
+    }
+    DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs &parameters) const
+    {
+        size_t plaintextLength = GetMaxSymmetricPlaintextLength(ciphertextLength);
+        const byte *cipherKey, *macKey;
+        if (DHAES_MODE)
+        {
+            macKey = key;
+            cipherKey = key + MAC::DEFAULT_KEYLENGTH;
+        }
+        else
+        {
+            cipherKey = key;
+            macKey = key + plaintextLength;
+        }
+
+        ConstByteArrayParameter encodingParameters;
+        parameters.GetValue(Name::EncodingParameters(), encodingParameters);
+
+        MAC mac(macKey);
+        mac.Update(ciphertext, plaintextLength);
+        mac.Update(encodingParameters.begin(), encodingParameters.size());
+        if (DHAES_MODE)
+        {
+            byte L[8];
+            PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size())));
+            mac.Update(L, 8);
+        }
+        if (!mac.Verify(ciphertext + plaintextLength))
+            return DecodingResult();
+
+        if (plaintextLength)    // Coverity finding
+            xorbuf(plaintext, ciphertext, cipherKey, plaintextLength);
+
+        return DecodingResult(plaintextLength);
+    }
+};
+
+/// \brief P1363 based Key Derivation Method
+/// \tparam T FieldElement type or class
+/// \tparam DHAES_MODE flag indicating DHAES mode
+/// \tparam KDF key derivation function
+/// \details FieldElement <tt>T</tt> can be Integer, ECP or EC2N.
+template <class T, bool DHAES_MODE, class KDF>
+class DL_KeyDerivationAlgorithm_P1363 : public DL_KeyDerivationAlgorithm<T>
+{
+public:
+    virtual ~DL_KeyDerivationAlgorithm_P1363() {}
+
+    bool ParameterSupported(const char *name) const {return strcmp(name, Name::KeyDerivationParameters()) == 0;}
+    void Derive(const DL_GroupParameters<T> &params, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs &parameters) const
+    {
+        SecByteBlock agreedSecret;
+        if (DHAES_MODE)
+        {
+            agreedSecret.New(params.GetEncodedElementSize(true) + params.GetEncodedElementSize(false));
+            params.EncodeElement(true, ephemeralPublicKey, agreedSecret);
+            params.EncodeElement(false, agreedElement, agreedSecret + params.GetEncodedElementSize(true));
+        }
+        else
+        {
+            agreedSecret.New(params.GetEncodedElementSize(false));
+            params.EncodeElement(false, agreedElement, agreedSecret);
+        }
+
+        ConstByteArrayParameter derivationParameters;
+        parameters.GetValue(Name::KeyDerivationParameters(), derivationParameters);
+        KDF::DeriveKey(derivedKey, derivedLength, agreedSecret, agreedSecret.size(), derivationParameters.begin(), derivationParameters.size());
+    }
+};
+
+/// \brief Discrete Log Integrated Encryption Scheme
+/// \tparam COFACTOR_OPTION cofactor multiplication option
+/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation
+/// \tparam DHAES_MODE flag indicating if the MAC includes addition context parameters such as the label
+/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits
+/// \details DLIES is an Integer based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation Method (KEM)
+///  with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is
+///  <A HREF="http://en.wikipedia.org/wiki/ciphertext_indistinguishability">IND-CCA2</A>, which is a strong notion of security.
+///  You should prefer an Integrated Encryption Scheme over homegrown schemes.
+/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom
+///  SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption
+///  Schemes with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=false</tt> and <tt>LABEL_OCTETS=true</tt>.
+/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the DLIES template class with
+///  <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=false</tt> and <tt>LABEL_OCTETS=true</tt>.
+/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the DLIES
+///  template class with <tt>NoCofactorMultiplication</tt>, <tt>DHAES_MODE=true</tt> and <tt>LABEL_OCTETS=false</tt>.
+/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of
+///  <tt>IncompatibleCofactorMultiplication</tt> and <tt>DHAES_MODE=true</tt> is recommended for best efficiency and security.
+///  SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the
+///  security provided by the MAC. The hash is also used in the key derivation function as a PRF.
+/// \details Below is an example of constructing a Crypto++ 4.2 compatible DLIES encryptor and decryptor.
+/// <pre>
+///    AutoSeededRandomPool prng;
+///    DL_PrivateKey_GFP<DL_GroupParameters_GFP> key;
+///    key.Initialize(prng, 2048);
+///
+///    DLIES<SHA1,NoCofactorMultiplication,true,true>::Decryptor decryptor(key);
+///    DLIES<SHA1,NoCofactorMultiplication,true,true>::Encryptor encryptor(decryptor);
+/// </pre>
+/// \sa ECIES, <a href="http://www.weidai.com/scan-mirror/ca.html#DLIES">Discrete Log Integrated Encryption Scheme (DLIES)</a>,
+///  Martínez, Encinas, and Ávila's <A HREF="http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf">A Survey of the Elliptic
+///  Curve Integrated Encryption Schemes</A>
+/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility
+template <class HASH = SHA1, class COFACTOR_OPTION = NoCofactorMultiplication, bool DHAES_MODE = true, bool LABEL_OCTETS=false>
+struct DLIES
+    : public DL_ES<
+        DL_CryptoKeys_GFP,
+        DL_KeyAgreementAlgorithm_DH<Integer, COFACTOR_OPTION>,
+        DL_KeyDerivationAlgorithm_P1363<Integer, DHAES_MODE, P1363_KDF2<HASH> >,
+        DL_EncryptionAlgorithm_Xor<HMAC<HASH>, DHAES_MODE, LABEL_OCTETS>,
+        DLIES<> >
+{
+    static std::string CRYPTOPP_API StaticAlgorithmName() {return "DLIES";}    // TODO: fix this after name is standardized
+};
+
+NAMESPACE_END
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff