diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a3d5e4d3..ed846d80a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,24 @@ option(WITH_COVTEST "Turn on to enable coverage testing (can be used with g++ on option(WITH_NOISE_DEBUG "Use only when running lattice estimator; not for production" OFF ) option(WITH_REDUCED_NOISE "Enable reduced noise within HKS and BFV HPSPOVERQ modes" OFF ) option(USE_MACPORTS "Use MacPorts installed packages" OFF ) +option(OPENFHE_DEFAULT_LOG_SINK "Compile the built-in diagnostic sink (std::cerr/std::cout); turn OFF to supply your own" ON ) + +# Diagnostic log sink: when ON (default), compile openfhe_log_default.cpp so +# OpenFHEErrStream()/OpenFHEOutStream() target std::cerr/std::cout, preserving +# the historical behavior. When OFF, that translation unit is empty and the +# embedding application must define those accessors itself, letting an embedder +# keep std::cerr/std::cout out of the compiled OpenFHE archive (e.g. an R package +# subject to CRAN's no-output-from-compiled-code rule). +# +# OFF is intended for static builds (BUILD_STATIC), where the accessors are +# resolved when the embedding application links. Combining OFF with a shared +# build leaves those symbols undefined in the library itself: valid on ELF +# platforms, which resolve them at load time, but rejected at link time by +# platforms that require every symbol to resolve when the library is created +# (macOS, Windows). +if(OPENFHE_DEFAULT_LOG_SINK) + add_definitions(-DOPENFHE_DEFAULT_LOG_SINK) +endif() # Set required number of bits for native integer in build by setting NATIVE_SIZE to 64 or 128 if(NOT NATIVE_SIZE) diff --git a/src/binfhe/lib/lwe-pke.cpp b/src/binfhe/lib/lwe-pke.cpp index 5e8b01b70..45b5d05c6 100644 --- a/src/binfhe/lib/lwe-pke.cpp +++ b/src/binfhe/lib/lwe-pke.cpp @@ -34,6 +34,7 @@ #include "math/discreteuniformgenerator.h" #include "math/ternaryuniformgenerator.h" #include "utils/parallel.h" +#include "utils/openfhe_log.h" namespace lbcrypto { @@ -206,7 +207,7 @@ void LWEEncryptionScheme::Decrypt(const std::shared_ptr& params double error = (static_cast(p) * (r.ConvertToDouble() - q.ConvertToDouble() / (p * 2))) / q.ConvertToDouble() - static_cast(*result); - std::cerr << error * q.ConvertToDouble() / static_cast(p) << std::endl; + OPENFHE_LOG_ERR << error * q.ConvertToDouble() / static_cast(p) << std::endl; #endif } diff --git a/src/core/include/utils/openfhe_log.h b/src/core/include/utils/openfhe_log.h new file mode 100644 index 000000000..2bc60b0b3 --- /dev/null +++ b/src/core/include/utils/openfhe_log.h @@ -0,0 +1,88 @@ +//================================================================================== +// BSD 2-Clause License +// +// Copyright (c) 2014-2022, 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. +//================================================================================== + +/* + Pluggable diagnostic output channel for OpenFHE. + + Library code that needs to emit a diagnostic message writes to + OPENFHE_LOG_ERR / OPENFHE_LOG_OUT instead of std::cerr / std::cout + directly. Each macro expands to a std::ostream&, so every built-in + operator<< overload and manipulator (std::endl, std::hex, ...) works + transparently and existing call sites need no other change. + + Routing the streams through an indirection lets an embedding + application redirect OpenFHE's diagnostics without editing every call + site. Two mechanisms are provided, and they compose: + + * Runtime: call SetOpenFHEErrStream() / SetOpenFHEOutStream() to + point the channel at any std::ostream (a file, a string stream, a + GUI log widget) whose lifetime outlives subsequent diagnostics. + + * Build time: the default sink (which targets std::cerr / std::cout) + lives in a single translation unit, openfhe_log_default.cpp, that + is compiled only when the OPENFHE_DEFAULT_LOG_SINK CMake option is + ON (the default). An embedder that must keep std::cerr / std::cout + out of the compiled OpenFHE archive entirely — for example an R + package, where CRAN forbids compiled code that writes to + stdout/stderr — builds with -DOPENFHE_DEFAULT_LOG_SINK=OFF and + links its own definitions of the accessors below. + + With OPENFHE_DEFAULT_LOG_SINK=ON (the default) the behavior is + byte-for-byte identical to writing to std::cerr / std::cout directly. +*/ + +#ifndef _LBCRYPTO_UTILS_OPENFHE_LOG_H_ +#define _LBCRYPTO_UTILS_OPENFHE_LOG_H_ + +#include + +namespace lbcrypto { + +// Diagnostic error / output channels. All library diagnostics route +// here via OPENFHE_LOG_ERR / OPENFHE_LOG_OUT. The default sink +// (openfhe_log_default.cpp, compiled iff OPENFHE_DEFAULT_LOG_SINK) +// targets std::cerr / std::cout; an embedder may supply its own. +std::ostream& OpenFHEErrStream(); +std::ostream& OpenFHEOutStream(); + +// Redirect the channels at runtime. The referenced stream must outlive +// any subsequent OpenFHE diagnostic. Intended to be called once during +// initialization; concurrent use with library diagnostics is the +// caller's responsibility. +void SetOpenFHEErrStream(std::ostream& os); +void SetOpenFHEOutStream(std::ostream& os); + +} // namespace lbcrypto + +#define OPENFHE_LOG_ERR (::lbcrypto::OpenFHEErrStream()) +#define OPENFHE_LOG_OUT (::lbcrypto::OpenFHEOutStream()) + +#endif // _LBCRYPTO_UTILS_OPENFHE_LOG_H_ diff --git a/src/core/lib/math/dftransform.cpp b/src/core/lib/math/dftransform.cpp index 42243a910..bdd0d51bf 100644 --- a/src/core/lib/math/dftransform.cpp +++ b/src/core/lib/math/dftransform.cpp @@ -41,6 +41,7 @@ #include #include +#include "utils/openfhe_log.h" namespace lbcrypto { @@ -114,7 +115,7 @@ std::vector> DiscreteFourierTransform::FFTForwardTransform( // cosTable.resize(l); // maxMCached = m; // } - // std::cout<<"miss m "< +#include "utils/openfhe_log.h" #if (defined(__linux__) || defined(__unix__)) && !defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) #include #endif @@ -61,7 +62,7 @@ void PseudoRandomNumberGenerator::InitPRNGEngine(const std::string& libPath) { genPRNGEngine = default_prng::createEngineInstance; if (!genPRNGEngine) OPENFHE_THROW("Cannot find symbol: default_prng::createEngineInstance"); - // std::cerr << "InitPRNGEngine: using local PRNG" << std::endl; + // OPENFHE_LOG_ERR << "InitPRNGEngine: using local PRNG" << std::endl; } else { #if (defined(__linux__) || defined(__unix__)) && !defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) @@ -83,7 +84,7 @@ void PseudoRandomNumberGenerator::InitPRNGEngine(const std::string& libPath) { dlclose(libraryHandle); OPENFHE_THROW(errMsg); } - std::cerr << __FUNCTION__ << ": using external PRNG" << std::endl; + OPENFHE_LOG_ERR << __FUNCTION__ << ": using external PRNG" << std::endl; #else OPENFHE_THROW("OpenFHE may use an external PRNG library linked with g++ on Linux only"); #endif diff --git a/src/core/lib/math/hal/bigintntl/mubintvecntl.cpp b/src/core/lib/math/hal/bigintntl/mubintvecntl.cpp index 1a46fbed6..e6a2cd81b 100644 --- a/src/core/lib/math/hal/bigintntl/mubintvecntl.cpp +++ b/src/core/lib/math/hal/bigintntl/mubintvecntl.cpp @@ -38,6 +38,7 @@ //================================================================================== #include "config_core.h" +#include "utils/openfhe_log.h" #ifdef WITH_NTL #define FASTNLOOSE @@ -63,7 +64,7 @@ myVecP::myVecP(const myVecP& a) : Vec(INIT_SIZE, a.length()) { int rv = this->CopyModulus(a); if (rv == -1) { #ifdef WARN_BAD_MODULUS - std::cerr << "in myVecP(myVecP) Bad CopyModulus" << std::endl; + OPENFHE_LOG_ERR << "in myVecP(myVecP) Bad CopyModulus" << std::endl; #endif } *this = a; @@ -75,7 +76,7 @@ myVecP::myVecP(myVecP&& a) : Vec(INIT_SIZE, a.length()) { int rv = this->CopyModulus(a); if (rv == -1) { #ifdef WARN_BAD_MODULUS - std::cerr << "in myVecP(myVecP &&) Bad CopyModulus" << std::endl; + OPENFHE_LOG_ERR << "in myVecP(myVecP &&) Bad CopyModulus" << std::endl; #endif } this->move(a); @@ -240,7 +241,7 @@ myVecP& myVecP::operator=(std::initializer_list rhs) { if (i < len) { int tmp = *(rhs.begin() + i); if (tmp < 0) { - std::cout << "warning trying to assign negative integer value" << std::endl; + OPENFHE_LOG_OUT << "warning trying to assign negative integer value" << std::endl; } #ifdef FORCE_NORMALIZATION if (isModulusSet()) @@ -306,7 +307,7 @@ myVecP& myVecP::operator=(const myVecP& rhs) { int rv = this->CopyModulus(rhs); if (rv == -1) { #ifdef WARN_BAD_MODULUS - std::cerr << "in operator=(myVecP) Bad CopyModulus" << std::endl; + OPENFHE_LOG_ERR << "in operator=(myVecP) Bad CopyModulus" << std::endl; #endif } for (size_t i = 0; i < rhs.GetLength(); i++) { @@ -323,7 +324,7 @@ myVecP& myVecP::operator=(myVecP&& rhs) { int rv = this->CopyModulus(rhs); if (rv == -1) { #ifdef WARN_BAD_MODULUS - std::cerr << "in operator=(myVecP) Bad CopyModulus" << std::endl; + OPENFHE_LOG_ERR << "in operator=(myVecP) Bad CopyModulus" << std::endl; #endif } this->move(rhs); diff --git a/src/core/lib/utils/blockAllocator/xallocator.cpp b/src/core/lib/utils/blockAllocator/xallocator.cpp index d95798368..3572a6e06 100644 --- a/src/core/lib/utils/blockAllocator/xallocator.cpp +++ b/src/core/lib/utils/blockAllocator/xallocator.cpp @@ -43,6 +43,7 @@ #include "utils/blockAllocator/blockAllocator.h" #include "utils/blockAllocator/xallocator.h" #include "utils/exception.h" +#include "utils/openfhe_log.h" static std::mutex xalloc_mutex; static bool _xallocInitialized = false; @@ -372,30 +373,30 @@ void xalloc_stats() { lock_get(); std::unique_lock lock(xalloc_mutex); { - std::cout << "\n***********************"; + OPENFHE_LOG_OUT << "\n***********************"; if (!_allocators.empty()) { auto mode = _allocators.begin()->second->GetMode(); if (mode == Allocator::HEAP_BLOCKS) - std::cout << " HEAP_BLOCKS\n"; + OPENFHE_LOG_OUT << " HEAP_BLOCKS\n"; if (mode == Allocator::HEAP_POOL) - std::cout << " HEAP_POOL\n"; + OPENFHE_LOG_OUT << " HEAP_POOL\n"; if (mode == Allocator::STATIC_POOL) - std::cout << " STATIC_POOL\n"; + OPENFHE_LOG_OUT << " STATIC_POOL\n"; } for (auto& [k, a] : _allocators) { if (a->GetBlockCount() == 0) continue; if (a->GetName()) - std::cout << a->GetName(); - std::cout << " Block Size: " << a->GetBlockSize(); - std::cout << " Block Count: " << a->GetBlockCount(); - std::cout << " Block Allocs: " << a->GetAllocations(); - std::cout << " Block Deallocs: " << a->GetDeallocations(); - std::cout << " Blocks In Use: " << a->GetBlocksInUse(); - std::cout << std::endl; + OPENFHE_LOG_OUT << a->GetName(); + OPENFHE_LOG_OUT << " Block Size: " << a->GetBlockSize(); + OPENFHE_LOG_OUT << " Block Count: " << a->GetBlockCount(); + OPENFHE_LOG_OUT << " Block Allocs: " << a->GetAllocations(); + OPENFHE_LOG_OUT << " Block Deallocs: " << a->GetDeallocations(); + OPENFHE_LOG_OUT << " Blocks In Use: " << a->GetBlocksInUse(); + OPENFHE_LOG_OUT << std::endl; } - std::cout << "***********************\n"; + OPENFHE_LOG_OUT << "***********************\n"; } lock_release(); } diff --git a/src/core/lib/utils/openfhe_log_default.cpp b/src/core/lib/utils/openfhe_log_default.cpp new file mode 100644 index 000000000..e43d563c9 --- /dev/null +++ b/src/core/lib/utils/openfhe_log_default.cpp @@ -0,0 +1,77 @@ +//================================================================================== +// BSD 2-Clause License +// +// Copyright (c) 2014-2022, 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. +//================================================================================== + +/* + Default diagnostic sink for OpenFHE: routes OpenFHEErrStream() / + OpenFHEOutStream() to std::cerr / std::cout. + + This translation unit is the ONLY place in the library that names + std::cerr / std::cout. It is compiled only when OPENFHE_DEFAULT_LOG_SINK + is defined (controlled by the CMake option of the same name, ON by + default). When the option is OFF this file compiles to nothing, and the + embedding application must provide its own definitions of + lbcrypto::OpenFHEErrStream() / OpenFHEOutStream() (and, if it uses them, + the Set* setters). That lets an embedder keep std::cerr / std::cout out + of the compiled OpenFHE archive entirely — e.g. an R package, where + CRAN's "compiled code should not write to stdout/stderr" rule forbids + those symbols — while still receiving the library's diagnostics. +*/ + +#include "utils/openfhe_log.h" + +#ifdef OPENFHE_DEFAULT_LOG_SINK + + #include + +namespace lbcrypto { + +namespace { +std::ostream* g_errStream = &std::cerr; +std::ostream* g_outStream = &std::cout; +} // namespace + +std::ostream& OpenFHEErrStream() { + return *g_errStream; +} +std::ostream& OpenFHEOutStream() { + return *g_outStream; +} + +void SetOpenFHEErrStream(std::ostream& os) { + g_errStream = &os; +} +void SetOpenFHEOutStream(std::ostream& os) { + g_outStream = &os; +} + +} // namespace lbcrypto + +#endif // OPENFHE_DEFAULT_LOG_SINK diff --git a/src/core/lib/utils/prng/blake2engine.cpp b/src/core/lib/utils/prng/blake2engine.cpp index 9a0739445..bb7a95959 100644 --- a/src/core/lib/utils/prng/blake2engine.cpp +++ b/src/core/lib/utils/prng/blake2engine.cpp @@ -36,6 +36,7 @@ #include #include #include +#include "utils/openfhe_log.h" namespace default_prng { @@ -67,9 +68,9 @@ extern "C" { static void Blake2SeedGenerator(Blake2Engine::blake2_seed_array_t& seed) { #if defined(FIXED_SEED) // Only used for debugging in the single-threaded mode. - std::cerr << "**FOR DEBUGGING ONLY!!!! Using fixed initializer for PRNG. " - "Use a single thread only, e.g., OMP_NUM_THREADS=1!" - << std::endl; + OPENFHE_LOG_ERR << "**FOR DEBUGGING ONLY!!!! Using fixed initializer for PRNG. " + "Use a single thread only, e.g., OMP_NUM_THREADS=1!" + << std::endl; seed[0] = 1; #else diff --git a/src/pke/lib/scheme/ckksrns/ckksrns-fhe.cpp b/src/pke/lib/scheme/ckksrns/ckksrns-fhe.cpp index e2223e8a7..69cb4f581 100644 --- a/src/pke/lib/scheme/ckksrns/ckksrns-fhe.cpp +++ b/src/pke/lib/scheme/ckksrns/ckksrns-fhe.cpp @@ -54,6 +54,7 @@ #include #include #include +#include "utils/openfhe_log.h" #ifdef BOOTSTRAPTIMING #include @@ -180,20 +181,22 @@ void FHECKKSRNS::EvalBootstrapSetup(const CryptoContextImpl& cc, std:: // Perform some checks on the level budget and compute parameters uint32_t newBudget0 = levelBudget[0]; if (newBudget0 > logSlots) { - std::cerr << "\nWarning, the level budget for encoding is too large. Setting it to " << logSlots << std::endl; + OPENFHE_LOG_ERR << "\nWarning, the level budget for encoding is too large. Setting it to " << logSlots + << std::endl; newBudget0 = logSlots; } if (newBudget0 < 1) { - std::cerr << "\nWarning, the level budget for encoding can not be zero. Setting it to 1" << std::endl; + OPENFHE_LOG_ERR << "\nWarning, the level budget for encoding can not be zero. Setting it to 1" << std::endl; newBudget0 = 1; } uint32_t newBudget1 = levelBudget[1]; if (newBudget1 > logSlots) { - std::cerr << "\nWarning, the level budget for decoding is too large. Setting it to " << logSlots << std::endl; + OPENFHE_LOG_ERR << "\nWarning, the level budget for decoding is too large. Setting it to " << logSlots + << std::endl; newBudget1 = logSlots; } if (newBudget1 < 1) { - std::cerr << "\nWarning, the level budget for decoding can not be zero. Setting it to 1" << std::endl; + OPENFHE_LOG_ERR << "\nWarning, the level budget for decoding can not be zero. Setting it to 1" << std::endl; newBudget1 = 1; } @@ -677,8 +680,8 @@ Ciphertext FHECKKSRNS::EvalBootstrap(ConstCiphertext& cipher } #ifdef BOOTSTRAPTIMING - std::cerr << "\nNumber of levels at the beginning of bootstrapping: " - << raised->GetElements()[0].GetNumOfElements() - 1 << std::endl; + OPENFHE_LOG_ERR << "\nNumber of levels at the beginning of bootstrapping: " + << raised->GetElements()[0].GetNumOfElements() - 1 << std::endl; #endif //------------------------------------------------------------------------------ @@ -789,7 +792,7 @@ Ciphertext FHECKKSRNS::EvalBootstrap(ConstCiphertext& cipher #ifdef BOOTSTRAPTIMING timeModReduce = TOC(t); - std::cerr << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; + OPENFHE_LOG_ERR << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; // Running SlotToCoeff TIC(t); #endif @@ -848,7 +851,7 @@ Ciphertext FHECKKSRNS::EvalBootstrap(ConstCiphertext& cipher #ifdef BOOTSTRAPTIMING timeEncode = TOC(t); - std::cerr << "\nEncoding time: " << timeEncode / 1000.0 << " s" << std::endl; + OPENFHE_LOG_ERR << "\nEncoding time: " << timeEncode / 1000.0 << " s" << std::endl; // Running Approximate Mod Reduction TIC(t); #endif @@ -874,7 +877,7 @@ Ciphertext FHECKKSRNS::EvalBootstrap(ConstCiphertext& cipher #ifdef BOOTSTRAPTIMING timeModReduce = TOC(t); - std::cerr << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; + OPENFHE_LOG_ERR << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; // Running SlotToCoeff TIC(t); #endif @@ -902,7 +905,7 @@ Ciphertext FHECKKSRNS::EvalBootstrap(ConstCiphertext& cipher #ifdef BOOTSTRAPTIMING timeDecode = TOC(t); - std::cout << "Decoding time: " << timeDecode / 1000.0 << " s" << std::endl; + OPENFHE_LOG_OUT << "Decoding time: " << timeDecode / 1000.0 << " s" << std::endl; #endif // If we start with more towers, than we obtain from bootstrapping, return the original ciphertext. @@ -1125,7 +1128,7 @@ Ciphertext FHECKKSRNS::EvalBootstrapStCFirst(ConstCiphertext #ifdef BOOTSTRAPTIMING timeDecode = TOC(t); - std::cout << "Decoding time: " << timeDecode / 1000.0 << " s" << std::endl; + OPENFHE_LOG_OUT << "Decoding time: " << timeDecode / 1000.0 << " s" << std::endl; #endif //------------------------------------------------------------------------------ @@ -1183,7 +1186,8 @@ Ciphertext FHECKKSRNS::EvalBootstrapStCFirst(ConstCiphertext } #ifdef BOOTSTRAPTIMING - std::cerr << "\nNumber of levels after mod raise: " << raised->GetElements()[0].GetNumOfElements() - 1 << std::endl; + OPENFHE_LOG_ERR << "\nNumber of levels after mod raise: " << raised->GetElements()[0].GetNumOfElements() - 1 + << std::endl; #endif double normalization = pre * (1.0 / (k * N)); // Scaling adjustment before Coefficient to Slots @@ -1241,7 +1245,7 @@ Ciphertext FHECKKSRNS::EvalBootstrapStCFirst(ConstCiphertext #ifdef BOOTSTRAPTIMING timeEncode = TOC(t); - std::cerr << "\nEncoding time: " << timeEncode / 1000.0 << " s" << std::endl; + OPENFHE_LOG_ERR << "\nEncoding time: " << timeEncode / 1000.0 << " s" << std::endl; // Running Approximate Mod Reduction TIC(t); #endif @@ -1282,7 +1286,7 @@ Ciphertext FHECKKSRNS::EvalBootstrapStCFirst(ConstCiphertext #ifdef BOOTSTRAPTIMING timeModReduce = TOC(t); - std::cerr << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; + OPENFHE_LOG_ERR << "Approximate modular reduction time: " << timeModReduce / 1000.0 << " s" << std::endl; // Running SlotToCoeff TIC(t); #endif @@ -3078,8 +3082,8 @@ std::shared_ptr> FHECKKSRNS::EvalMVBPrecomputeInternal( } #ifdef BOOTSTRAPTIMING - std::cerr << "\nNumber of levels at the beginning of bootstrapping: " - << raised->GetElements()[0].GetNumOfElements() - 1 << std::endl; + OPENFHE_LOG_ERR << "\nNumber of levels at the beginning of bootstrapping: " + << raised->GetElements()[0].GetNumOfElements() - 1 << std::endl; #endif //------------------------------------------------------------------------------