Program Listing for File binfhecontext.cpp

↰ Return to documentation for file (binfhe/lib/binfhecontext.cpp)

//==================================================================================
// BSD 2-Clause License
//
// Copyright (c) 2014-2026, NJIT, Duality Technologies Inc. and other contributors
//
// All rights reserved.
//
// Author TPOC: contact@openfhe.org
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//==================================================================================

/*
  Implementation file for Boolean Circuit FHE context class
 */

#include "binfhecontext.h"

#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

static constexpr double STD_DEV = 3.19;

namespace lbcrypto {

// RingGSWCryptoParams never sees the LWE dimension, so the map and n meet only here
static void VerifyGadgetBaseMapCoverage(const std::map<uint32_t, uint32_t>& baseGMap, uint32_t n) {
    uint32_t count{0};
    for (const auto& item : baseGMap)
        count += item.second;
    if (count != n)
        OPENFHE_THROW("Gadget base map should cover the LWE dimension.");
}

void BinFHEContext::GenerateBinFHEContext(uint32_t n, uint32_t N, NativeInteger q, NativeInteger Q, double std,
                                          uint32_t baseKS, uint32_t baseG, uint32_t baseR, SecretKeyDist keyDist,
                                          BINFHE_METHOD method, uint32_t numAutoKeys) {
    auto lweparams = std::make_shared<LWECryptoParams>(n, N, q, Q, Q, std, baseKS, keyDist);
    auto rgswparams =
            std::make_shared<RingGSWCryptoParams>(N, Q, q, baseG, baseR, method, std, keyDist, true, numAutoKeys);
    m_params = std::make_shared<BinFHECryptoParams>(lweparams, rgswparams);
    m_binfhescheme = std::make_shared<BinFHEScheme>(method);
}

void BinFHEContext::GenerateBinFHEContext(BINFHE_PARAMSET s, bool arbFunc, uint32_t logQ, uint32_t N,
                                          BINFHE_METHOD method, bool timeOptimization) {
    if (method != GINX)
        OPENFHE_THROW("CGGI is the only supported method");
    if (s != STD128 && s != TOY)
        OPENFHE_THROW("STD128 and TOY are the only supported sets");
    if (logQ > 29)
        OPENFHE_THROW("logQ > 29 is not supported");
    if (logQ < 11)
        OPENFHE_THROW("logQ < 11 is not supported");

    isMethodCompatible(method, s);

    auto logQprime = 54;
    uint32_t baseG = 0;
    if (logQ > 25) {
        baseG = 1 << 14;
    } else if (logQ > 16) {
        baseG = 1 << 18;
    } else if (logQ > 11) {
        baseG = 1 << 27;
    } else {  // if (logQ == 11)
        baseG = 1 << 5;
        logQprime = 27;
    }

    // choose minimum ringD satisfying sl and Q
    // if specified some larger N, security is also satisfied
    auto minRingDim = StdLatticeParm::FindRingDim(HEStd_ternary, HEStd_128_classic, logQprime);
    uint32_t ringDim = N > minRingDim ? N : minRingDim;

    // find prime Q for NTT
    NativeInteger Q = LastPrime<NativeInteger>(logQprime, 2 * ringDim);

    // q = 2*ringDim by default for maximum plaintext space, if needed for arbitrary function evaluation, q = ringDim
    uint32_t q = arbFunc ? ringDim : 2 * ringDim;

    uint64_t qKS = uint64_t(1) << 35;

    uint32_t n = (s == TOY) ? 32 : 1305;
    auto lweparams = std::make_shared<LWECryptoParams>(n, ringDim, q, Q, qKS, STD_DEV, 32);
    auto rgswparams = std::make_shared<RingGSWCryptoParams>(ringDim, Q, q, baseG, 23, method, STD_DEV, UNIFORM_TERNARY,
                                                            ((logQ != 11) && timeOptimization));

    m_params = std::make_shared<BinFHECryptoParams>(lweparams, rgswparams);
    m_binfhescheme = std::make_shared<BinFHEScheme>(method);
    m_timeOptimization = timeOptimization;
}

void BinFHEContext::GenerateBinFHEContext(BINFHE_PARAMSET s, BINFHE_METHOD method) {
    enum { PRIME = 0 };  // value for modKS if you want to use the intermediate prime for modulus for key switching

    isMethodCompatible(method, s);

    // clang-format off
    static const std::unordered_map<BINFHE_PARAMSET, BinFHEContextParams> paramsMap{
    //  { BINFHE_PARAMSET         { bits, cycOrder, latParam, modq,   modKS, Bks,        Bg, Brk, autoKeys,         keyDist, stdDev, gadgetBaseMap } },
        { TOY,                    {   27,     1024,       64,  512,   PRIME,  25,       512,  23,        9, UNIFORM_TERNARY,   3.19, {{512, 64}} } },
        { TOY_MULTI_BASE,         {   27,     1024,       64,  512,   PRIME,  25,       512,  23,        9, UNIFORM_TERNARY,   3.19, {{128, 32}, {512, 32}} } },
        { MEDIUM,                 {   28,     2048,      422, 1024,   16384, 128,      1024,  32,       10, UNIFORM_TERNARY,   3.19, {{1024, 422}} } },
        { STD128,                 {   27,     2048,      554, 2048,   32768, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 303}, {512, 251}} } },
        { STD128_3,               {   27,     2048,      592, 2048,   65536, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 575}, {512, 17}} } },
        { STD128_4,               {   27,     2048,      630, 2048,  131072, 512,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 134}, {32, 496}} } },
        { STD128Q,                {   25,     2048,      598, 2048,   32768, 256,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 377}, {128, 221}} } },
        { STD128Q_3,              {   25,     2048,      639, 2048,   65536, 256,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 287}, {32, 352}} } },
        { STD128Q_4,              {   28,     4096,      680, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 273}, {128, 407}} } },
        { STD192,                 {   28,     4096,      820, 4096,   32768, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 658}, {1024, 162}} } },
        { STD192_3,               {   28,     4096,      874, 4096,   65536, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 857}, {1024, 17}} } },
        { STD192_4,               {   28,     4096,      928, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 718}, {128, 210}} } },
        { STD192Q,                {   28,     4096,      889, 4096,   32768, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 732}, {1024, 157}} } },
        { STD192Q_3,              {   28,     4096,      947, 4096,   65536, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 935}, {1024, 12}} } },
        { STD192Q_4,              {   28,     4096,     1004, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 855}, {128, 149}} } },
        { STD256,                 {   28,     4096,     1077, 4096,   32768, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 931}, {1024, 146}} } },
        { STD256_3,               {   28,     4096,     1214, 4096,  131072,  64,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 1190}, {1024, 24}} } },
        { STD256_4,               {   28,     4096,     1283, 4096,  262144, 128,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 1137}, {128, 146}} } },
        { STD256Q,                {   26,     4096,     1169, 4096,   32768, 256,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 173}, {64, 996}} } },
        { STD256Q_3,              {   26,     4096,     1317, 4096,  131072,  64,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 41}, {32, 1276}} } },
        { STD256Q_4,              {   26,     4096,     1391, 4096,  262144,  64,         8,  64,       10, UNIFORM_TERNARY,   3.19, {{8, 289}, {16, 1102}} } },
        { LPF_STD128,             {   27,     2048,      554, 2048,   32768, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 523}, {512, 31}} } },
        { LPF_STD128_3,           {   27,     2048,      630, 2048,  131072, 512,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 165}, {64, 465}} } },
        { LPF_STD128_4,           {   28,     4096,      668, 4096,  262144,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 621}, {128, 47}} } },
        { LPF_STD128Q,            {   25,     2048,      598, 2048,   32768, 256,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 106}, {32, 492}} } },
        { LPF_STD128Q_3,          {   25,     2048,      680, 2048,  131072, 512,         4,  64,       10, UNIFORM_TERNARY,   3.19, {{4, 43}, {8, 637}} } },
        { LPF_STD128Q_4,          {   28,     4096,      720, 4096,  262144,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 715}, {128, 5}} } },
        { LPF_STD192,             {   28,     4096,      874, 4096,   65536, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 782}, {1024, 92}} } },
        { LPF_STD192_3,           {   28,     4096,      928, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 493}, {128, 435}} } },
        { LPF_STD192_4,           {   28,     4096,      982, 4096,  262144,  64,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 893}, {64, 89}} } },
        { LPF_STD192Q,            {   28,     4096,      947, 4096,   65536, 256,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 859}, {1024, 88}} } },
        { LPF_STD192Q_3,          {   28,     4096,     1004, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 629}, {128, 375}} } },
        { LPF_STD192Q_4,          {   28,     4096,     1062, 4096,  262144,  64,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 359}, {32, 703}} } },
        { LPF_STD256,             {   28,     4096,     1146, 4096,   65536,  64,       128,  64,       10, UNIFORM_TERNARY,   3.19, {{128, 1091}, {1024, 55}} } },
        { LPF_STD256_3,           {   28,     4096,     1214, 4096,  131072,  64,        64,  64,       10, UNIFORM_TERNARY,   3.19, {{64, 1006}, {128, 208}} } },
        { LPF_STD256_4,           {   28,     4096,     1352, 4096,  524288, 128,         8,  64,       10, UNIFORM_TERNARY,   3.19, {{8, 110}, {16, 1242}} } },
        { LPF_STD256Q,            {   26,     4096,     1243, 4096,   65536,  64,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 997}, {64, 246}} } },
        { LPF_STD256Q_3,          {   26,     4096,     1391, 4096,  262144,  64,        16,  64,       10, UNIFORM_TERNARY,   3.19, {{16, 1294}, {32, 97}} } },
        { LPF_STD256Q_4,          {   28,     8192,     1465, 8192,  524288,  32,        32,  64,       10, UNIFORM_TERNARY,   3.19, {{32, 1201}, {64, 264}} } },
        { STD128_LMKCDEY,         {   27,     2048,      554, 2048,   32768, 256,       512,  64,       40, UNIFORM_TERNARY,   3.19, {{512, 552}, {16384, 2}} } },
        { STD128_3_LMKCDEY,       {   27,     2048,      592, 2048,   65536, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 440}, {512, 152}} } },
        { STD128_4_LMKCDEY,       {   27,     2048,      668, 2048,  262144, 512,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 586}, {128, 82}} } },
        { STD128Q_LMKCDEY,        {   25,     2048,      598, 2048,   32768, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 565}, {512, 33}} } },
        { STD128Q_3_LMKCDEY,      {   25,     2048,      639, 2048,   65536, 256,        32,  64,       40, UNIFORM_TERNARY,   3.19, {{32, 532}, {128, 107}} } },
        { STD128Q_4_LMKCDEY,      {   28,     4096,      680, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 642}, {1024, 38}} } },
        { STD192_LMKCDEY,         {   28,     4096,      716, 4096,   32768, 256,       128,  64,       40,        GAUSSIAN,   3.19, {{128, 633}, {1024, 83}} } },
        { STD192_3_LMKCDEY,       {   28,     4096,      874, 4096,   65536, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 731}, {1024, 143}} } },
        { STD192_4_LMKCDEY,       {   28,     4096,      928, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 914}, {1024, 14}} } },
        { STD192Q_LMKCDEY,        {   28,     4096,      778, 4096,   32768, 256,       128,  64,       40,        GAUSSIAN,   3.19, {{128, 745}, {1024, 33}} } },
        { STD192Q_3_LMKCDEY,      {   28,     4096,      947, 4096,   65536, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 811}, {1024, 136}} } },
        { STD192Q_4_LMKCDEY,      {   28,     4096,     1004, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 997}, {1024, 7}} } },
        { STD256_LMKCDEY,         {   28,     4096,     1009, 4096,   65536,  64,       128,  64,       40,        GAUSSIAN,   3.19, {{128, 779}, {1024, 230}} } },
        { STD256_3_LMKCDEY,       {   28,     4096,     1146, 4096,   65536,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 1095}, {1024, 51}} } },
        { STD256_4_LMKCDEY,       {   28,     4096,     1283, 4096,  262144,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 1263}, {1024, 20}} } },
        { STD256Q_LMKCDEY,        {   28,     4096,     1120, 4096,   65536,  64,       128,  64,       40,        GAUSSIAN,   3.19, {{128, 980}, {1024, 140}} } },
        { STD256Q_3_LMKCDEY,      {   26,     4096,     1317, 4096,  131072,  64,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 1288}, {128, 29}} } },
        { STD256Q_4_LMKCDEY,      {   26,     4096,     1317, 4096,  131072,  64,        16,  64,       40, UNIFORM_TERNARY,   3.19, {{16, 1014}, {32, 303}} } },
        { LPF_STD128_LMKCDEY,     {   27,     2048,      554, 2048,   32768, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 364}, {512, 190}} } },
        { LPF_STD128_3_LMKCDEY,   {   27,     2048,      630, 2048,  131072, 512,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 120}, {128, 510}} } },
        { LPF_STD128_4_LMKCDEY,   {   28,     4096,      706, 4096,  524288, 128,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 701}, {1024, 5}} } },
        { LPF_STD128Q_LMKCDEY,    {   25,     2048,      598, 2048,   32768, 256,        32,  64,       40, UNIFORM_TERNARY,   3.19, {{32, 448}, {128, 150}} } },
        { LPF_STD128Q_3_LMKCDEY,  {   25,     2048,      680, 2048,  131072, 512,        16,  64,       40, UNIFORM_TERNARY,   3.19, {{16, 658}, {32, 22}} } },
        { LPF_STD128Q_4_LMKCDEY,  {   28,     4096,      760, 4096,  524288, 128,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 760}} } },
        { LPF_STD192_LMKCDEY,     {   28,     4096,      874, 4096,   65536, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 492}, {1024, 382}} } },
        { LPF_STD192_3_LMKCDEY,   {   28,     4096,      928, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 889}, {1024, 39}} } },
        { LPF_STD192_4_LMKCDEY,   {   28,     4096,      982, 4096,  262144,  64,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 899}, {128, 83}} } },
        { LPF_STD192Q_LMKCDEY,    {   28,     4096,      947, 4096,   65536, 256,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 572}, {1024, 375}} } },
        { LPF_STD192Q_3_LMKCDEY,  {   28,     4096,     1004, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 972}, {1024, 32}} } },
        { LPF_STD192Q_4_LMKCDEY,  {   28,     4096,     1120, 4096,  524288, 128,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 990}, {128, 130}} } },
        { LPF_STD256_LMKCDEY,     {   28,     4096,     1146, 4096,   65536,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 854}, {1024, 292}} } },
        { LPF_STD256_3_LMKCDEY,   {   28,     4096,     1214, 4096,  131072,  64,       128,  64,       40, UNIFORM_TERNARY,   3.19, {{128, 1202}, {1024, 12}} } },
        { LPF_STD256_4_LMKCDEY,   {   28,     4096,     1352, 4096,  524288, 128,        32,  64,       40, UNIFORM_TERNARY,   3.19, {{32, 1276}, {64, 76}} } },
        { LPF_STD256Q_LMKCDEY,    {   26,     4096,     1243, 4096,   65536,  64,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 900}, {128, 343}} } },
        { LPF_STD256Q_3_LMKCDEY,  {   26,     4096,     1391, 4096,  262144,  64,        32,  64,       40, UNIFORM_TERNARY,   3.19, {{32, 1279}, {64, 112}} } },
        { LPF_STD256Q_4_LMKCDEY,  {   28,     8192,     1465, 8192,  524288,  32,        64,  64,       40, UNIFORM_TERNARY,   3.19, {{64, 1243}, {128, 222}} } },
        { STD128_AP,              {   27,     2048,      554, 2048,   32768, 256,       128, 128,       10, UNIFORM_TERNARY,   3.19, {{128, 10}, {512, 544}} } },
        { STD128_3_AP,            {   27,     2048,      592, 2048,   65536, 256,       128, 128,       10, UNIFORM_TERNARY,   3.19, {{128, 512}, {512, 80}} } },
        { STD128_4_AP,            {   27,     2048,      668, 2048,  262144,  64,        32, 128,       10, UNIFORM_TERNARY,   3.19, {{32, 304}, {64, 364}} } },
        { STD128Q_AP,             {   25,     2048,      598, 2048,   32768, 256,        32, 128,       10, UNIFORM_TERNARY,   3.19, {{32, 72}, {128, 526}} } },
        { STD128Q_3_AP,           {   25,     2048,      639, 2048,   65536, 256,        32, 128,       10, UNIFORM_TERNARY,   3.19, {{32, 605}, {128, 34}} } },
        { STD128Q_4_AP,           {   28,     4096,      680, 4096,  131072,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 680}} } },
        { STD192_AP,              {   28,     4096,      874, 1024,   65536, 256,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 653}, {1024, 221}} } },
        { STD192_3_AP,            {   28,     4096,      928, 2048,  131072,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 904}, {1024, 24}} } },
        { STD192_4_AP,            {   28,     4096,      928, 4096,  131072,  64,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 488}, {128, 440}} } },
        { STD192Q_AP,             {   28,     4096,      947, 1024,   65536,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 808}, {1024, 139}} } },
        { STD192Q_3_AP,           {   28,     4096,     1004, 2048,  131072,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 991}, {1024, 13}} } },
        { STD192Q_4_AP,           {   28,     4096,     1062, 4096,  262144,  32,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 282}, {128, 780}} } },
        { STD256_AP,              {   28,     4096,     1146, 1024,   65536,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 1117}, {1024, 29}} } },
        { STD256_3_AP,            {   28,     4096,     1214, 4096,  131072,  32,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 1160}, {1024, 54}} } },
        { STD256_4_AP,            {   28,     4096,     1214, 4096,  131072,  64,        64,   8,       10, UNIFORM_TERNARY,   3.19, {{64, 1192}, {128, 22}} } },
        { STD256Q_AP,             {   28,     4096,     1120, 4096,   65536,  64,       128,  32,       10,        GAUSSIAN,   3.19, {{128, 1085}, {1024, 35}} } },
        { STD256Q_3_AP,           {   26,     4096,     1317, 4096,  131072,  64,        32,   8,       10, UNIFORM_TERNARY,   3.19, {{32, 1265}, {64, 52}} } },
        { STD256Q_4_AP,           {   26,     4096,     1391, 4096,  262144,  32,         8,   8,       10, UNIFORM_TERNARY,   3.19, {{8, 200}, {16, 1191}} } },
        { LPF_STD128_AP,          {   27,     2048,      554, 2048,   32768, 256,       128, 128,       10, UNIFORM_TERNARY,   3.19, {{128, 449}, {512, 105}} } },
        { LPF_STD128_3_AP,        {   27,     2048,      630, 2048,  131072, 512,        64, 128,       10, UNIFORM_TERNARY,   3.19, {{64, 424}, {128, 206}} } },
        { LPF_STD128_4_AP,        {   28,     4096,      668, 4096,  262144,  64,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 501}, {128, 167}} } },
        { LPF_STD128Q_AP,         {   25,     2048,      598, 2048,   32768, 256,        32, 128,       10, UNIFORM_TERNARY,   3.19, {{32, 534}, {128, 64}} } },
        { LPF_STD128Q_3_AP,       {   25,     2048,      680, 2048,  131072, 512,         8,  32,       10, UNIFORM_TERNARY,   3.19, {{8, 487}, {16, 193}} } },
        { LPF_STD128Q_4_AP,       {   28,     4096,      720, 4096,  262144,  64,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 605}, {128, 115}} } },
        { LPF_STD192_AP,          {   28,     4096,      874, 2048,   65536,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 801}, {1024, 73}} } },
        { LPF_STD192_3_AP,        {   28,     4096,      928, 4096,  131072,  64,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 164}, {128, 764}} } },
        { LPF_STD192_4_AP,        {   28,     4096,      982, 4096,  262144,  64,        32,   8,       10, UNIFORM_TERNARY,   3.19, {{32, 834}, {64, 148}} } },
        { LPF_STD192Q_AP,         {   28,     4096,      947, 2048,   65536,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 884}, {1024, 63}} } },
        { LPF_STD192Q_3_AP,       {   28,     4096,     1004, 4096,  131072,  64,        64,  32,       10, UNIFORM_TERNARY,   3.19, {{64, 315}, {128, 689}} } },
        { LPF_STD192Q_4_AP,       {   28,     4096,     1062, 4096,  262144,  64,        16,   8,       10, UNIFORM_TERNARY,   3.19, {{16, 222}, {32, 840}} } },
        { LPF_STD256_AP,          {   28,     4096,     1146, 2048,   65536,  64,       128,  32,       10, UNIFORM_TERNARY,   3.19, {{128, 1112}, {1024, 34}} } },
        { LPF_STD256_3_AP,        {   28,     4096,     1214, 4096,  131072,  64,        64,   8,       10, UNIFORM_TERNARY,   3.19, {{64, 942}, {128, 272}} } },
        { LPF_STD256_4_AP,        {   28,     4096,     1352, 4096,  524288,  32,         8,   8,       10, UNIFORM_TERNARY,   3.19, {{8, 288}, {16, 1064}} } },
        { LPF_STD256Q_AP,         {   26,     4096,     1243, 4096,   65536,  64,        32,   8,       10, UNIFORM_TERNARY,   3.19, {{32, 908}, {64, 335}} } },
        { LPF_STD256Q_3_AP,       {   26,     4096,     1391, 4096,  262144,  32,        16,   8,       10, UNIFORM_TERNARY,   3.19, {{16, 1248}, {32, 143}} } },
        { LPF_STD256Q_4_AP,       {   51,     8192,     1391, 8192,  262144,  32,  67108864,   8,       10, UNIFORM_TERNARY,   3.19, {{67108864, 1391}} } },
        { SIGNED_MOD_TEST,        {   28,     2048,      512, 1024,   PRIME,  25,       128,  23,       10, UNIFORM_TERNARY,   3.19, {{128, 512}} } },
    };
    // clang-format on

    auto search = paramsMap.find(s);
    if (paramsMap.end() == search)
        OPENFHE_THROW("unknown parameter set");

    auto& params = search->second;

    auto Q = LastPrime<NativeInteger>(params.numberBits, params.cyclOrder);
    auto ringDim = params.cyclOrder >> 1;
    auto lweparams = std::make_shared<LWECryptoParams>(params.latticeParam, ringDim, params.mod, Q,
                                                       (params.modKS == PRIME ? Q : params.modKS), params.stdDev,
                                                       params.baseKS, params.keyDist);
    VerifyGadgetBaseMapCoverage(params.gadgetBaseMap, params.latticeParam);

    auto rgswparams = std::make_shared<RingGSWCryptoParams>(ringDim, Q, params.mod, params.gadgetBase,
                                                            params.gadgetBaseMap, params.baseRK, method, params.stdDev,
                                                            params.keyDist, false, params.numAutoKeys);
    m_params = std::make_shared<BinFHECryptoParams>(lweparams, rgswparams);

    m_binfhescheme = std::make_shared<BinFHEScheme>(method);
}

void BinFHEContext::GenerateBinFHEContext(const BinFHEContextParams& params, BINFHE_METHOD method) {
    enum { PRIME = 0 };  // value for modKS if you want to use the intermediate prime for modulus for key switching

    auto Q = LastPrime<NativeInteger>(params.numberBits, params.cyclOrder);
    auto ringDim = params.cyclOrder >> 1;
    auto lweparams = std::make_shared<LWECryptoParams>(params.latticeParam, ringDim, params.mod, Q,
                                                       (params.modKS == PRIME ? Q : params.modKS), params.stdDev,
                                                       params.baseKS, params.keyDist);
    std::shared_ptr<RingGSWCryptoParams> rgswparams;
    if (params.gadgetBaseMap.empty()) {
        rgswparams =
                std::make_shared<RingGSWCryptoParams>(ringDim, Q, params.mod, params.gadgetBase, params.baseRK, method,
                                                      params.stdDev, params.keyDist, false, params.numAutoKeys);
    } else {
        VerifyGadgetBaseMapCoverage(params.gadgetBaseMap, params.latticeParam);

        rgswparams = std::make_shared<RingGSWCryptoParams>(ringDim, Q, params.mod, params.gadgetBase,
                                                           params.gadgetBaseMap, params.baseRK, method, params.stdDev,
                                                           params.keyDist, false, params.numAutoKeys);
    }
    m_params = std::make_shared<BinFHECryptoParams>(lweparams, rgswparams);
    m_binfhescheme = std::make_shared<BinFHEScheme>(method);
}

LWEPrivateKey BinFHEContext::KeyGen() const {
    auto&& LWEParams = m_params->GetLWEParams();
    if (LWEParams->GetKeyDist() == GAUSSIAN)
        return m_LWEscheme->KeyGenGaussian(LWEParams->Getn(), LWEParams->GetqKS());
    return m_LWEscheme->KeyGen(LWEParams->Getn(), LWEParams->GetqKS());
}

LWEPrivateKey BinFHEContext::KeyGenN() const {
    auto&& LWEParams = m_params->GetLWEParams();
    if (LWEParams->GetKeyDist() == GAUSSIAN)
        return m_LWEscheme->KeyGenGaussian(LWEParams->GetN(), LWEParams->GetQ());
    return m_LWEscheme->KeyGen(LWEParams->GetN(), LWEParams->GetQ());
}

LWEKeyPair BinFHEContext::KeyGenPair() const {
    return m_LWEscheme->KeyGenPair(m_params->GetLWEParams());
}

LWEPublicKey BinFHEContext::PubKeyGen(ConstLWEPrivateKey& sk) const {
    if (sk == nullptr)
        OPENFHE_THROW("PrivateKey is empty");
    return m_LWEscheme->PubKeyGen(m_params->GetLWEParams(), sk);
}

LWECiphertext BinFHEContext::Encrypt(ConstLWEPrivateKey& sk, LWEPlaintext m, BINFHE_OUTPUT output,
                                     LWEPlaintextModulus p, NativeInteger mod) const {
    if (sk == nullptr)
        OPENFHE_THROW("PrivateKey is empty");
    auto&& LWEParams = m_params->GetLWEParams();
    auto ct = m_LWEscheme->Encrypt(LWEParams, sk, m, p, (mod == 0 ? LWEParams->Getq() : mod));

    // BINFHE_OUTPUT is kept as it is for backward compatibility but
    // this logic is obsolete now and commented out
    // if ((output != FRESH) && (p == 4)) {
    //    ct = m_binfhescheme->Bootstrap(m_params, m_BTKey, ct);
    //}
    return ct;
}

LWECiphertext BinFHEContext::Encrypt(ConstLWEPublicKey& pk, LWEPlaintext m, BINFHE_OUTPUT output, LWEPlaintextModulus p,
                                     NativeInteger mod) const {
    if (pk == nullptr)
        OPENFHE_THROW("PublicKey is empty");
    auto&& LWEParams = m_params->GetLWEParams();
    auto ct = m_LWEscheme->EncryptN(LWEParams, pk, m, p, (mod == 0 ? LWEParams->GetQ() : mod));

    // Switch from ct of modulus Q and dimension N to smaller q and n
    // This is done by default while calling Encrypt but the output could
    // be set to LARGE_DIM to skip this switching
    if (output == SMALL_DIM) {
#if NATIVEINT != 32
        if (m_BTKey.KSkey32 != nullptr)
            ct = m_LWEscheme->SwitchCTtoqn(LWEParams, m_BTKey.KSkey32, ct);
        else
#endif
            ct = SwitchCTtoqn(m_BTKey.KSkey, ct);
        ct->SetptModulus(p);
    }
    return ct;
}

LWECiphertext BinFHEContext::SwitchCTtoqn(ConstLWESwitchingKey& ksk, ConstLWECiphertext& ct) const {
    if (ksk == nullptr)
        OPENFHE_THROW("SwitchingKey is empty");
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    auto&& LWEParams = m_params->GetLWEParams();
    if (ct->GetLength() != LWEParams->GetN() || ct->GetModulus() != LWEParams->GetQ())
        OPENFHE_THROW("ciphertext must have large dimension N and modulus Q");
    return m_LWEscheme->SwitchCTtoqn(LWEParams, ksk, ct);
}

void BinFHEContext::Decrypt(ConstLWEPrivateKey& sk, ConstLWECiphertext& ct, LWEPlaintext* result,
                            LWEPlaintextModulus p) const {
    if (sk == nullptr)
        OPENFHE_THROW("PrivateKey is empty");
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    m_LWEscheme->Decrypt(m_params->GetLWEParams(), sk, ct, result, p);
}

LWESwitchingKey BinFHEContext::KeySwitchGen(ConstLWEPrivateKey& sk, ConstLWEPrivateKey& skN) const {
    if (sk == nullptr)
        OPENFHE_THROW("New PrivateKey is empty");
    if (skN == nullptr)
        OPENFHE_THROW("Old PrivateKey is empty");

    return m_LWEscheme->KeySwitchGen(m_params->GetLWEParams(), sk, skN);
}

void BinFHEContext::BTKeyGen(ConstLWEPrivateKey& sk, KEYGEN_MODE keygenMode, bool internal32) {
    if (sk == nullptr)
        OPENFHE_THROW("PrivateKey is empty");
    auto&& RGSWParams = m_params->GetRingGSWParams();
    auto temp = RGSWParams->GetBaseG();

    // the map is keyed by gadget base alone, but what it caches is only valid for the secret
    // key it was generated from; take a cached entry only when this call just regenerated it
    if (m_timeOptimization) {
        for (auto&& [k, v] : RGSWParams->GetGPowerMap()) {
            RGSWParams->Change_BaseG(k);
            m_BTKey_map[k] = m_binfhescheme->KeyGen(m_params, sk, keygenMode, internal32);
        }
        RGSWParams->Change_BaseG(temp);
        m_BTKey = m_BTKey_map[temp];
    } else {
        m_BTKey = m_binfhescheme->KeyGen(m_params, sk, keygenMode, internal32);
        m_BTKey_map[temp] = m_BTKey;
    }

#if NATIVEINT != 32
    ReleaseMonomialsIfAll32();
#endif
}

LWECiphertext BinFHEContext::EvalBinGate(const BINGATE gate, ConstLWECiphertext& ct1, ConstLWECiphertext& ct2,
                                         bool extended) const {
    if (ct1 == nullptr)
        OPENFHE_THROW("Ciphertext1 is empty");
    if (ct2 == nullptr)
        OPENFHE_THROW("Ciphertext2 is empty");
    return m_binfhescheme->EvalBinGate(m_params, gate, m_BTKey, ct1, ct2, extended);
}

LWECiphertext BinFHEContext::EvalBinGate(const BINGATE gate, const std::vector<LWECiphertext>& ctvector,
                                         bool extended) const {
    return m_binfhescheme->EvalBinGate(m_params, gate, m_BTKey, ctvector, extended);
}

LWECiphertext BinFHEContext::Bootstrap(ConstLWECiphertext& ct, bool extended) const {
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->Bootstrap(m_params, m_BTKey, ct, extended);
}

LWECiphertext BinFHEContext::EvalNOT(ConstLWECiphertext& ct) const {
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->EvalNOT(m_params, ct);
}

LWECiphertext BinFHEContext::EvalConstant(bool value) const {
    return m_LWEscheme->NoiselessEmbedding(m_params->GetLWEParams(), value);
}

LWECiphertext BinFHEContext::EvalFunc(ConstLWECiphertext& ct, const std::vector<NativeInteger>& LUT) const {
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->EvalFunc(m_params, m_BTKey, ct, LUT, GetBeta());
}

LWECiphertext BinFHEContext::EvalFloor(ConstLWECiphertext& ct, uint32_t roundbits) const {
    //    auto q = m_params->GetLWEParams()->Getq().ConvertToInt();
    //    if (roundbits != 0) {
    //        NativeInteger newp = this->GetMaxPlaintextSpace();
    //        SetQ(q / newp * (1 << roundbits));
    //    }
    //    SetQ(q);
    //    return res;
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->EvalFloor(m_params, m_BTKey, ct, GetBeta(), roundbits);
}

LWECiphertext BinFHEContext::EvalSign(ConstLWECiphertext& ct, bool schemeSwitch) {
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->EvalSign(std::make_shared<BinFHECryptoParams>(*m_params), m_BTKey_map, ct, GetBeta(),
                                    schemeSwitch);
}

std::vector<LWECiphertext> BinFHEContext::EvalDecomp(ConstLWECiphertext& ct) {
    if (ct == nullptr)
        OPENFHE_THROW("Ciphertext is empty");
    return m_binfhescheme->EvalDecomp(m_params, m_BTKey_map, ct, GetBeta());
}

std::vector<NativeInteger> BinFHEContext::GenerateLUTviaFunction(NativeInteger (*f)(NativeInteger m, NativeInteger p),
                                                                 NativeInteger p) {
    if (!IsPowerOfTwo(p.ConvertToInt<BasicInteger>()))
        OPENFHE_THROW("plaintext p not power of two");

    NativeInteger q{GetParams()->GetLWEParams()->Getq()};
    NativeInteger x{0};

    std::vector<NativeInteger> vec(q.ConvertToInt(), q / p);
    for (size_t i = 0; i < vec.size(); ++i, x += p) {
        vec[i] *= f(x / q, p);  // x/q = (i*p)/q = i/(q/p)
        if (vec[i] >= q)        // (f(x/q, p) >= p) --> (f(x/q, p)*(q/p) >= q)
            OPENFHE_THROW("input function should output in Z_{p_output}");
    }
    return vec;
}

}  // namespace lbcrypto