Program Listing for File rgsw-acckey32.cpp

↰ Return to documentation for file (binfhe/lib/rgsw-acckey32.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.
//==================================================================================

#include "rgsw-acckey32.h"

#include <cstdint>
#include <memory>
#include <utility>
#include <vector>

#include "utils/exception.h"

namespace lbcrypto {

#if NATIVEINT != 32

bool RingGSWACCKey32Impl::Fits(const RingGSWCryptoParams& params) {
    auto method = params.GetMethod();
    if (method != BINFHE_METHOD::GINX && method != BINFHE_METHOD::AP && method != BINFHE_METHOD::LMKCDEY)
        return false;
    if (params.GetQ().GetMSB() > MAX_MODULUS_SIZE32)
        return false;
    uint64_t Q{params.GetQ().ConvertToInt<uint64_t>()};
    auto ok = [Q](const RingGSWCryptoParams::BaseGParams& bp) {
        // excess-H headroom: the biased value must stay inside a 32-bit word
        if (bp.digitsG * bp.gBits + 1 > 32)
            return false;
        // uint64 headroom for the lazy inner product: digitsG2 * (Q-1)^2 < 2^64
        uint64_t d2{static_cast<uint64_t>((bp.digitsG - 1) << 1)};
        return d2 <= static_cast<uint64_t>(-1) / ((Q - 1) * (Q - 1));
    };
    const auto& byIndex = params.GetBaseGByIndex();
    if (byIndex.empty())
        return ok(params.GetDefaultBaseGParams());
    for (const auto& bp : byIndex)
        if (!ok(bp))
            return false;
    // the LMKCDEY automorphism key switch uses the default base regardless of the per-index map
    if (method == BINFHE_METHOD::LMKCDEY && !ok(params.GetDefaultBaseGParams()))
        return false;
    return true;
}

RingGSWACCKey32Impl::RingGSWACCKey32Impl(const std::shared_ptr<RingGSWCryptoParams>& params,
                                         const RingGSWACCKeyImpl& ek) {
    const auto& src = ek.GetElements();
    if (src.empty() || src[0].empty() || src[0][0].empty())
        OPENFHE_THROW("RingGSWACCKey32Impl: empty accumulator key");
    Init(params);
    m_key.assign(src.size(),
                 std::vector<std::vector<EvalKey32>>(src[0].size(), std::vector<EvalKey32>(src[0][0].size())));
    for (size_t i = 0; i < src.size(); ++i)
        for (size_t j = 0; j < src[i].size(); ++j)
            for (size_t k = 0; k < src[i][j].size(); ++k)
                if (src[i][j][k] != nullptr)
                    SetEvalKey(i, j, k, *src[i][j][k]);
}

RingGSWACCKey32Impl::RingGSWACCKey32Impl(const std::shared_ptr<RingGSWCryptoParams>& params, uint32_t d1, uint32_t d2,
                                         uint32_t d3) {
    Init(params);
    m_key.assign(d1, std::vector<std::vector<EvalKey32>>(d2, std::vector<EvalKey32>(d3)));
}

// shared setup for both constructors
void RingGSWACCKey32Impl::Init(const std::shared_ptr<RingGSWCryptoParams>& params) {
    if (!Fits(*params))
        OPENFHE_THROW("parameters do not qualify for the 32-bit internal path");

    m_N = params->GetN();
    m_polyParams = params->GetPolyParams32();
    // force the lazy monomial build now: construction is single-threaded, gates may not be
    if (params->GetMethod() == BINFHE_METHOD::GINX)
        params->GetMonomialsPrecon32();
}

void RingGSWACCKey32Impl::SetEvalKey(uint32_t i, uint32_t j, uint32_t k, const RingGSWEvalKeyImpl& ek) {
    const auto& el = ek.GetElements();
    auto& dst = m_key[i][j][k];
    dst.resize(el.size());
    for (size_t d = 0; d < el.size(); ++d) {
        dst[d].clear();
        dst[d].reserve(el[d].size());
        for (size_t col = 0; col < el[d].size(); ++col)
            dst[d].push_back(NarrowPoly32(el[d][col], m_polyParams));
    }
}

RingGSWACCKey RingGSWACCKey32Impl::Widen(const std::shared_ptr<RingGSWCryptoParams>& params) const {
    const auto& polyParams = params->GetPolyParams();
    auto ek = std::make_shared<RingGSWACCKeyImpl>(m_key.size(), m_key[0].size(), m_key[0][0].size());
    for (size_t i = 0; i < m_key.size(); ++i) {
        for (size_t j = 0; j < m_key[i].size(); ++j) {
            for (size_t k = 0; k < m_key[i][j].size(); ++k) {
                const auto& src = m_key[i][j][k];
                if (src.empty())
                    continue;
                auto dst = std::make_shared<RingGSWEvalKeyImpl>(static_cast<uint32_t>(src.size()), 2);
                for (size_t d = 0; d < src.size(); ++d) {
                    for (size_t col = 0; col < src[d].size(); ++col) {
                        NativePoly p(polyParams, src[d][col].GetFormat(), true);
                        WidenPoly32Into(src[d][col], p);
                        (*dst)[d][col] = std::move(p);
                    }
                }
                (*ek)[i][j][k] = std::move(dst);
            }
        }
    }
    return ek;
}

uint64_t RingGSWACCKey32Impl::KeyBytes() const {
    uint64_t polys = 0;
    for (const auto& i : m_key)
        for (const auto& j : i)
            for (const auto& k : j)
                for (const auto& d : k)
                    polys += d.size();
    return polys * static_cast<uint64_t>(m_N) * sizeof(uint32_t);
}

#endif  // NATIVEINT != 32

}  // namespace lbcrypto