Program Listing for File binfhecontext.h

↰ Return to documentation for file (binfhe/include/binfhecontext.h)

//==================================================================================
// 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.
//==================================================================================

/*
  Header file for BinFHEContext class, which is used for Boolean circuit FHE schemes
 */

#ifndef SRC_BINFHE_INCLUDE_BINFHECONTEXT_H_
#define SRC_BINFHE_INCLUDE_BINFHECONTEXT_H_

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

#include "binfhe-base-scheme.h"
#include "lattice/stdlatticeparms.h"
#include "utils/memory.h"
#include "utils/serializable.h"

namespace lbcrypto {

struct BinFHEContextParams {
    uint32_t numberBits;
    uint32_t cyclOrder;
    uint32_t latticeParam;
    uint32_t mod;
    uint32_t modKS;
    uint32_t baseKS;
    uint32_t gadgetBase;
    uint32_t baseRK;
    uint32_t numAutoKeys;
    SecretKeyDist keyDist;
    double stdDev;
    std::map<uint32_t, uint32_t> gadgetBaseMap;
};

class BinFHEContext : public Serializable {
  public:
    BinFHEContext() = default;

    void GenerateBinFHEContext(uint32_t n, uint32_t N, NativeInteger q, NativeInteger Q, double std, uint32_t baseKS,
                               uint32_t baseG, uint32_t baseR, SecretKeyDist keyDist = UNIFORM_TERNARY,
                               BINFHE_METHOD method = GINX, uint32_t numAutoKeys = 10);

    void GenerateBinFHEContext(BINFHE_PARAMSET set, bool arbFunc, uint32_t logQ = 11, uint32_t N = 0,
                               BINFHE_METHOD method = GINX, bool timeOptimization = false);

    void GenerateBinFHEContext(BINFHE_PARAMSET set, BINFHE_METHOD method = GINX);

    void GenerateBinFHEContext(const BinFHEContextParams& params, BINFHE_METHOD method = GINX);

    const RingGSWACCKey& GetRefreshKey() const {
        return m_BTKey.BSkey;
    }

    const LWESwitchingKey& GetSwitchKey() const {
        return m_BTKey.KSkey;
    }

    const RingGSWBTKey& GetBTKey() const {
        return m_BTKey;
    }

    const LWEPublicKey& GetPublicKey() const {
        return m_BTKey.Pkey;
    }

    bool HasInternal32RefreshKey() const {
#if NATIVEINT != 32
        return m_BTKey.BSkey32 != nullptr;
#else
        return false;
#endif
    }

    bool HasInternal32SwitchKey() const {
#if NATIVEINT != 32
        return m_BTKey.KSkey32 != nullptr;
#else
        return false;
#endif
    }

    const std::shared_ptr<std::map<uint32_t, RingGSWBTKey>> GetBTKeyMap() const {
        return std::make_shared<std::map<uint32_t, RingGSWBTKey>>(m_BTKey_map);
    }

    LWEPrivateKey KeyGen() const;

    LWEKeyPair KeyGenPair() const;

    LWEPublicKey PubKeyGen(ConstLWEPrivateKey& sk) const;

    LWEPrivateKey KeyGenN() const;

    LWECiphertext Encrypt(ConstLWEPrivateKey& sk, LWEPlaintext m, BINFHE_OUTPUT output = SMALL_DIM,
                          LWEPlaintextModulus p = 4, NativeInteger mod = 0) const;

    LWECiphertext Encrypt(ConstLWEPublicKey& pk, LWEPlaintext m, BINFHE_OUTPUT output = SMALL_DIM,
                          LWEPlaintextModulus p = 4, NativeInteger mod = 0) const;

    LWECiphertext SwitchCTtoqn(ConstLWESwitchingKey& ksk, ConstLWECiphertext& ct) const;

    void Decrypt(ConstLWEPrivateKey& sk, ConstLWECiphertext& ct, LWEPlaintext* result, LWEPlaintextModulus p = 4) const;

    LWESwitchingKey KeySwitchGen(ConstLWEPrivateKey& sk, ConstLWEPrivateKey& skN) const;

    void BTKeyGen(ConstLWEPrivateKey& sk, KEYGEN_MODE keygenMode = SYM_ENCRYPT, bool internal32 = true);

    void BTKeyLoad(const RingGSWBTKey& key, bool internal32 = true) {
        m_BTKey = key;
#if NATIVEINT != 32
        if (internal32) {
            if (m_BTKey.BSkey != nullptr)
                m_params->GetRingGSWParams()->EnsureMonomials();
            if (CompressBTKeys()) {
                ReleaseMonomialsIfAll32();
                AllocTrim();
            }
            return;
        }
        // the caller asked for the native width, so widen whatever arrived narrow
        if (m_BTKey.BSkey == nullptr && m_BTKey.BSkey32 != nullptr)
            m_BTKey.BSkey = m_BTKey.BSkey32->Widen(m_params->GetRingGSWParams());
        if (m_BTKey.KSkey == nullptr && m_BTKey.KSkey32 != nullptr)
            m_BTKey.KSkey = m_BTKey.KSkey32->Widen(*m_params->GetLWEParams());
        m_BTKey.BSkey32 = nullptr;
        m_BTKey.KSkey32 = nullptr;
#else
        (void)internal32;
#endif
        if (m_BTKey.BSkey != nullptr)
            m_params->GetRingGSWParams()->EnsureMonomials();
    }

    void BTKeyMapLoadSingleElement(uint32_t baseG, const RingGSWBTKey& key) {
        if (key.BSkey != nullptr)
            m_params->GetRingGSWParams()->EnsureMonomials();
        m_BTKey_map[baseG] = key;
    }

    void ClearBTKeys() {
        m_BTKey.BSkey.reset();
        m_BTKey.KSkey.reset();
        m_BTKey.Pkey.reset();
#if NATIVEINT != 32
        m_BTKey.BSkey32.reset();
        m_BTKey.KSkey32.reset();
#endif
        m_BTKey_map.clear();
    }

    LWECiphertext EvalBinGate(BINGATE gate, ConstLWECiphertext& ct1, ConstLWECiphertext& ct2,
                              bool extended = false) const;

    LWECiphertext EvalBinGate(BINGATE gate, const std::vector<LWECiphertext>& ctvector, bool extended = false) const;

    LWECiphertext Bootstrap(ConstLWECiphertext& ct, bool extended = false) const;

    LWECiphertext EvalFunc(ConstLWECiphertext& ct, const std::vector<NativeInteger>& LUT) const;

    std::vector<NativeInteger> GenerateLUTviaFunction(NativeInteger (*f)(NativeInteger m, NativeInteger p),
                                                      NativeInteger p);

    LWECiphertext EvalFloor(ConstLWECiphertext& ct, uint32_t roundbits = 0) const;

    LWECiphertext EvalSign(ConstLWECiphertext& ct, bool schemeSwitch = false);

    std::vector<LWECiphertext> EvalDecomp(ConstLWECiphertext& ct);

    LWECiphertext EvalNOT(ConstLWECiphertext& ct) const;

    LWECiphertext EvalConstant(bool value) const;

    const std::shared_ptr<BinFHECryptoParams>& GetParams() {
        return m_params;
    }

    const std::shared_ptr<LWEEncryptionScheme>& GetLWEScheme() {
        return m_LWEscheme;
    }

    const std::shared_ptr<BinFHEScheme>& GetBinFHEScheme() {
        return m_binfhescheme;
    }

    template <class Archive>
    void save(Archive& ar, std::uint32_t const version) const {
        ar(::cereal::make_nvp("params", m_params));
    }

    template <class Archive>
    void load(Archive& ar, std::uint32_t const version) {
        if (version > SerializedVersion()) {
            OPENFHE_THROW("serialized object version " + std::to_string(version) +
                          " is from a later version of the library");
        }
        ar(::cereal::make_nvp("params", m_params));
        m_binfhescheme = std::make_shared<BinFHEScheme>(m_params->GetRingGSWParams()->GetMethod());
    }

    std::string SerializedObjectName() const override {
        return "BinFHEContext";
    }

    static uint32_t SerializedVersion() {
        return 1;
    }

    NativeInteger GetMaxPlaintextSpace() const {
        // Under our parameter choices, beta = 128 is enough, and therefore plaintext = q/2beta
        return m_params->GetLWEParams()->Getq() / (this->GetBeta() << 1);
    }

    constexpr NativeInteger GetBeta() const {
        return NativeInteger(128);
    }

  private:
#if NATIVEINT != 32
    bool CompressBTKeys() {
        bool converted = false;
        if (m_BTKey.BSkey != nullptr) {
            const auto& rgswParams = m_params->GetRingGSWParams();
            if (m_BTKey.BSkey32 == nullptr && RingGSWACCKey32Impl::Fits(*rgswParams))
                m_BTKey.BSkey32 = std::make_shared<RingGSWACCKey32Impl>(rgswParams, *m_BTKey.BSkey);
            if (m_BTKey.BSkey32 != nullptr) {
                // the map entry for the active baseG aliases m_BTKey; release its copy too or
                // the 64-bit key stays resident through it
                for (auto& [baseG, key] : m_BTKey_map) {
                    if (key.BSkey == m_BTKey.BSkey) {
                        key.BSkey32 = m_BTKey.BSkey32;
                        key.BSkey.reset();
                    }
                }
                m_BTKey.BSkey.reset();
                converted = true;
            }
        }
        if (m_BTKey.KSkey != nullptr) {
            const auto& lweParams = m_params->GetLWEParams();
            if (m_BTKey.KSkey32 == nullptr && LWESwitchingKey32Impl::Fits(*lweParams))
                m_BTKey.KSkey32 = std::make_shared<LWESwitchingKey32Impl>(*lweParams, *m_BTKey.KSkey);
            if (m_BTKey.KSkey32 != nullptr) {
                for (auto& [baseG, key] : m_BTKey_map) {
                    if (key.KSkey == m_BTKey.KSkey) {
                        key.KSkey32 = m_BTKey.KSkey32;
                        key.KSkey.reset();
                    }
                }
                m_BTKey.KSkey.reset();
                converted = true;
            }
        }
        return converted;
    }
#endif

#if NATIVEINT != 32
    // release the 64-bit monomial table when every held key runs on the 32-bit internal path
    // (which keeps its own); rebuilt on demand if a 64-bit key is generated or loaded later
    void ReleaseMonomialsIfAll32() {
        if (m_BTKey.BSkey != nullptr || m_BTKey.BSkey32 == nullptr)
            return;
        for (const auto& [baseG, key] : m_BTKey_map)
            if (key.BSkey != nullptr)
                return;
        m_params->GetRingGSWParams()->ClearMonomials();
    }
#endif

    // Shared pointer to Ring GSW + LWE parameters
    std::shared_ptr<BinFHECryptoParams> m_params{nullptr};

    // Shared pointer to the underlying additive LWE scheme
    std::shared_ptr<LWEEncryptionScheme> m_LWEscheme{std::make_shared<LWEEncryptionScheme>()};

    // Shared pointer to the underlying RingGSW/RLWE scheme
    std::shared_ptr<BinFHEScheme> m_binfhescheme{nullptr};

    // Struct containing the bootstrapping keys
    RingGSWBTKey m_BTKey = {0};

    std::map<uint32_t, RingGSWBTKey> m_BTKey_map;

    // Whether to optimize time for sign eval
    bool m_timeOptimization{false};
};

}  // namespace lbcrypto

#endif  // SRC_BINFHE_INCLUDE_BINFHECONTEXT_H_