2929// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3030// ==================================================================================
3131
32- #define PROFILE
33-
3432#include " cryptocontext.h"
3533#include " schemerns/rns-leveledshe.h"
3634
3937
4038namespace lbcrypto {
4139
40+ namespace {
41+ inline ScalingTechnique GetScalingTechnique (const CiphertextImpl<DCRTPoly>& ct) {
42+ return static_cast <const CryptoParametersRNS&>(*ct.GetCryptoParameters ()).GetScalingTechnique ();
43+ }
44+
45+ // AdjustForAddOrSubInPlace() is a no-op when the operands share level, noise-scale degree and tower
46+ // count (the plaintext overload additionally requires the plaintext element in EVALUATION format).
47+ inline bool AdjustForAddOrSubIsNoOp (const CiphertextImpl<DCRTPoly>& a, const CiphertextImpl<DCRTPoly>& b) {
48+ return a.GetLevel () == b.GetLevel () && a.GetNoiseScaleDeg () == b.GetNoiseScaleDeg () &&
49+ a.GetElements ()[0 ].GetNumOfElements () == b.GetElements ()[0 ].GetNumOfElements ();
50+ }
51+ inline bool AdjustForAddOrSubIsNoOp (const CiphertextImpl<DCRTPoly>& ct, const PlaintextImpl& pt) {
52+ const auto & pe = pt.GetElement <DCRTPoly>();
53+ return pt.GetLevel () == ct.GetLevel () && pt.GetNoiseScaleDeg () == ct.GetNoiseScaleDeg () &&
54+ pe.GetFormat () == Format::EVALUATION && pe.GetNumOfElements () == ct.GetElements ()[0 ].GetNumOfElements ();
55+ }
56+
57+ // AdjustForMultInPlace() is a no-op when the operands share level and tower count and either the
58+ // scaling technique is FIXEDMANUAL (no rescale on mult) or both operands are already at depth 1.
59+ inline bool AdjustForMultIsNoOp (const CiphertextImpl<DCRTPoly>& a, const CiphertextImpl<DCRTPoly>& b,
60+ ScalingTechnique st) {
61+ return a.GetLevel () == b.GetLevel () &&
62+ a.GetElements ()[0 ].GetNumOfElements () == b.GetElements ()[0 ].GetNumOfElements () &&
63+ (st == FIXEDMANUAL || (a.GetNoiseScaleDeg () == 1 && b.GetNoiseScaleDeg () == 1 ));
64+ }
65+ inline bool AdjustForMultIsNoOp (const CiphertextImpl<DCRTPoly>& ct, const PlaintextImpl& pt, ScalingTechnique st) {
66+ const auto & pe = pt.GetElement <DCRTPoly>();
67+ return ct.GetLevel () == pt.GetLevel () && pe.GetFormat () == Format::EVALUATION &&
68+ pe.GetNumOfElements () == ct.GetElements ()[0 ].GetNumOfElements () &&
69+ (st == FIXEDMANUAL || (ct.GetNoiseScaleDeg () == 1 && pt.GetNoiseScaleDeg () == 1 ));
70+ }
71+ } // namespace
72+
4273// ///////////////////////////////////////
4374// SHE ADDITION
4475// ///////////////////////////////////////
@@ -51,8 +82,8 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalAdd(ConstCiphertext<DCRTPoly>& ciphertex
5182}
5283
5384void LeveledSHERNS::EvalAddInPlace (Ciphertext<DCRTPoly>& ciphertext1, ConstCiphertext<DCRTPoly>& ciphertext2) const {
54- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext1-> GetCryptoParameters ())-> GetScalingTechnique ();
55- if (st == NORESCALE ) {
85+ auto st = GetScalingTechnique (*ciphertext1 );
86+ if (st == NORESCALE || AdjustForAddOrSubIsNoOp (*ciphertext1, *ciphertext2) ) {
5687 EvalAddCoreInPlace (ciphertext1, ciphertext2);
5788 }
5889 else {
@@ -84,8 +115,8 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalAdd(ConstCiphertext<DCRTPoly>& ciphertex
84115}
85116
86117void LeveledSHERNS::EvalAddInPlace (Ciphertext<DCRTPoly>& ciphertext, ConstPlaintext& plaintext) const {
87- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
88- if (st == NORESCALE ) {
118+ auto st = GetScalingTechnique (*ciphertext );
119+ if (st == NORESCALE || AdjustForAddOrSubIsNoOp (*ciphertext, *plaintext) ) {
89120 EvalAddCoreInPlace (ciphertext, plaintext->GetElement <DCRTPoly>());
90121 }
91122 else {
@@ -119,8 +150,8 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalSub(ConstCiphertext<DCRTPoly>& ciphertex
119150}
120151
121152void LeveledSHERNS::EvalSubInPlace (Ciphertext<DCRTPoly>& ciphertext1, ConstCiphertext<DCRTPoly>& ciphertext2) const {
122- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext1-> GetCryptoParameters ())-> GetScalingTechnique ();
123- if (st == NORESCALE ) {
153+ auto st = GetScalingTechnique (*ciphertext1 );
154+ if (st == NORESCALE || AdjustForAddOrSubIsNoOp (*ciphertext1, *ciphertext2) ) {
124155 EvalSubCoreInPlace (ciphertext1, ciphertext2);
125156 }
126157 else {
@@ -152,9 +183,9 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalSub(ConstCiphertext<DCRTPoly>& ciphertex
152183}
153184
154185void LeveledSHERNS::EvalSubInPlace (Ciphertext<DCRTPoly>& ciphertext, ConstPlaintext& plaintext) const {
155- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
156- if (st == NORESCALE ) {
157- EvalAddCoreInPlace (ciphertext, plaintext->GetElement <DCRTPoly>());
186+ auto st = GetScalingTechnique (*ciphertext );
187+ if (st == NORESCALE || AdjustForAddOrSubIsNoOp (*ciphertext, *plaintext) ) {
188+ EvalSubCoreInPlace (ciphertext, plaintext->GetElement <DCRTPoly>());
158189 }
159190 else {
160191 auto ctmorphed = MorphPlaintext (plaintext, ciphertext);
@@ -181,8 +212,8 @@ void LeveledSHERNS::EvalSubMutableInPlace(Ciphertext<DCRTPoly>& ciphertext, Plai
181212
182213Ciphertext<DCRTPoly> LeveledSHERNS::EvalMult (ConstCiphertext<DCRTPoly>& ciphertext1,
183214 ConstCiphertext<DCRTPoly>& ciphertext2) const {
184- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext1-> GetCryptoParameters ())-> GetScalingTechnique ();
185- if (st == NORESCALE )
215+ auto st = GetScalingTechnique (*ciphertext1 );
216+ if (st == NORESCALE || AdjustForMultIsNoOp (*ciphertext1, *ciphertext2, st) )
186217 return EvalMultCore (ciphertext1, ciphertext2);
187218
188219 auto c1 = ciphertext1->Clone ();
@@ -230,15 +261,21 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalMult(ConstCiphertext<DCRTPoly>& cipherte
230261}
231262
232263void LeveledSHERNS::EvalMultInPlace (Ciphertext<DCRTPoly>& ciphertext, ConstPlaintext& plaintext) const {
233- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
264+ auto st = GetScalingTechnique (*ciphertext );
234265 if (st == NORESCALE ) {
235266 EvalMultCoreInPlace (ciphertext, plaintext->GetElement <DCRTPoly>());
236267 }
237268 else {
238- auto ctmorphed = MorphPlaintext (plaintext, ciphertext);
239- AdjustForMultInPlace (ciphertext, ctmorphed);
240- EvalMultCoreInPlace (ciphertext, ctmorphed->GetElements ()[0 ]);
241- ciphertext->SetNoiseScaleDeg (ciphertext->GetNoiseScaleDeg () + ctmorphed->GetNoiseScaleDeg ());
269+ if (AdjustForMultIsNoOp (*ciphertext, *plaintext, st)) {
270+ EvalMultCoreInPlace (ciphertext, plaintext->GetElement <DCRTPoly>());
271+ ciphertext->SetNoiseScaleDeg (ciphertext->GetNoiseScaleDeg () + plaintext->GetNoiseScaleDeg ());
272+ }
273+ else {
274+ auto ctmorphed = MorphPlaintext (plaintext, ciphertext);
275+ AdjustForMultInPlace (ciphertext, ctmorphed);
276+ EvalMultCoreInPlace (ciphertext, ctmorphed->GetElements ()[0 ]);
277+ ciphertext->SetNoiseScaleDeg (ciphertext->GetNoiseScaleDeg () + ctmorphed->GetNoiseScaleDeg ());
278+ }
242279 }
243280}
244281
@@ -251,7 +288,7 @@ Ciphertext<DCRTPoly> LeveledSHERNS::EvalMultMutable(Ciphertext<DCRTPoly>& cipher
251288 // TODO (Andrey) : This part is only used in CKKS scheme
252289 result->SetScalingFactor (ciphertext->GetScalingFactor () * ctmorphed->GetScalingFactor ());
253290 // TODO (Andrey) : This part is only used in BGV scheme
254- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
291+ auto st = GetScalingTechnique (*ciphertext );
255292 if (st == FLEXIBLEAUTO || st == FLEXIBLEAUTOEXT )
256293 result->SetScalingFactorInt (ciphertext->GetScalingFactorInt ().ModMul (
257294 ctmorphed->GetScalingFactorInt (), ciphertext->GetCryptoParameters ()->GetPlaintextModulus ()));
@@ -268,7 +305,7 @@ void LeveledSHERNS::EvalMultMutableInPlace(Ciphertext<DCRTPoly>& ciphertext, Pla
268305 // TODO (Andrey) : This part is only used in CKKS scheme
269306 ciphertext->SetScalingFactor (ciphertext->GetScalingFactor () * ctmorphed->GetScalingFactor ());
270307 // TODO (Andrey) : This part is only used in BGV scheme
271- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
308+ auto st = GetScalingTechnique (*ciphertext );
272309 if (st == FLEXIBLEAUTO || st == FLEXIBLEAUTOEXT )
273310 ciphertext->SetScalingFactorInt (ciphertext->GetScalingFactorInt ().ModMul (
274311 ctmorphed->GetScalingFactorInt (), ciphertext->GetCryptoParameters ()->GetPlaintextModulus ()));
@@ -315,7 +352,7 @@ Ciphertext<DCRTPoly> LeveledSHERNS::ModReduce(ConstCiphertext<DCRTPoly>& ciphert
315352}
316353
317354void LeveledSHERNS::ModReduceInPlace (Ciphertext<DCRTPoly>& ciphertext, size_t levels) const {
318- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
355+ auto st = GetScalingTechnique (*ciphertext );
319356 if (st == FIXEDMANUAL )
320357 ModReduceInternalInPlace (ciphertext, levels);
321358}
@@ -335,7 +372,7 @@ Ciphertext<DCRTPoly> LeveledSHERNS::LevelReduce(ConstCiphertext<DCRTPoly>& ciphe
335372// TODO (Andrey) : remove evalKey as unused
336373void LeveledSHERNS::LevelReduceInPlace (Ciphertext<DCRTPoly>& ciphertext, const EvalKey<DCRTPoly> evalKey,
337374 size_t levels) const {
338- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext-> GetCryptoParameters ())-> GetScalingTechnique ();
375+ auto st = GetScalingTechnique (*ciphertext );
339376 if (st == NORESCALE )
340377 OPENFHE_THROW (" Not implemented for NORESCALE rescaling technique" );
341378 if (st == FIXEDMANUAL && levels > 0 )
@@ -477,7 +514,7 @@ void LeveledSHERNS::AdjustForAddOrSubInPlace(Ciphertext<DCRTPoly>& ciphertext1,
477514}
478515
479516void LeveledSHERNS::AdjustForMultInPlace (Ciphertext<DCRTPoly>& ciphertext1, Ciphertext<DCRTPoly>& ciphertext2) const {
480- auto st = std::dynamic_pointer_cast<CryptoParametersRNS>(ciphertext1-> GetCryptoParameters ())-> GetScalingTechnique ();
517+ auto st = GetScalingTechnique (*ciphertext1 );
481518 if (st == FIXEDMANUAL )
482519 AdjustLevelsInPlace (ciphertext1, ciphertext2);
483520 else if (st != NORESCALE )
0 commit comments