Skip to content

Commit dd8d374

Browse files
authored
fix bug in LeveledSHERNS::EvalSubInPlace(Ciphertext<DCRTPoly>& ciphertext, ConstPlaintext& plaintext) (#1217)
1 parent 652cc2d commit dd8d374

1 file changed

Lines changed: 60 additions & 23 deletions

File tree

src/pke/lib/schemerns/rns-leveledshe.cpp

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
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

@@ -39,6 +37,39 @@
3937

4038
namespace 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

5384
void 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

86117
void 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

121152
void 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

154185
void 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

182213
Ciphertext<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

232263
void 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

317354
void 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
336373
void 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

479516
void 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

Comments
 (0)