@@ -347,9 +347,16 @@ void LeveledSHEBase<Element>::RelinearizeInPlace(Ciphertext<Element>& ciphertext
347347template <class Element >
348348std::shared_ptr<std::map<uint32_t , EvalKey<Element>>> LeveledSHEBase<Element>::EvalAutomorphismKeyGen(
349349 const PrivateKey<Element> privateKey, const std::vector<uint32_t >& indexList) const {
350+
351+ // Do not generate duplicate keys that have been already generated and added to the static storage (map)
352+ std::set<uint32_t > allIndices (indexList.begin (), indexList.end ());
353+ std::set<uint32_t > indicesToGenerate{
354+ CryptoContextImpl<Element>::GetEvalAutomorphismNoKeyIndices (privateKey->GetKeyTag (), allIndices)};
355+ std::vector<uint32_t > newIndices (indicesToGenerate.begin (), indicesToGenerate.end ());
356+
350357 // we already have checks on higher level?
351- // auto it = std::find(indexList .begin(), indexList .end(), 2 * n - 1);
352- // if (it != indexList .end())
358+ // auto it = std::find(newIndices .begin(), newIndices .end(), 2 * n - 1);
359+ // if (it != newIndices .end())
353360 // OPENFHE_THROW("conjugation is disabled");
354361
355362 const auto cc = privateKey->GetCryptoContext ();
@@ -359,26 +366,26 @@ std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> LeveledSHEBase<Element>::E
359366 const uint32_t M = s.GetCyclotomicOrder ();
360367
361368 // we already have checks on higher level?
362- // if (indexList .size() > N - 1)
369+ // if (newIndices .size() > N - 1)
363370 // OPENFHE_THROW("size exceeds the ring dimension");
364371
365- // create and initialize the key map (key is a value from indexList , EvalKey is nullptr). in this case
372+ // create and initialize the key map (key is a value from newIndices , EvalKey is nullptr). in this case
366373 // we should be able to assign values to the map without using "omp critical" as all evalKeys' elements would
367374 // have already been created
368375 auto evalKeys = std::make_shared<std::map<uint32_t , EvalKey<Element>>>();
369- for (auto indx : indexList )
376+ for (auto indx : newIndices )
370377 (*evalKeys)[indx];
371378
372- const uint32_t sz = indexList .size ();
379+ const uint32_t sz = newIndices .size ();
373380#pragma omp parallel for
374381 for (uint32_t i = 0 ; i < sz; ++i) {
375- auto index = NativeInteger (indexList [i]).ModInverse (M).ConvertToInt <uint32_t >();
382+ auto index = NativeInteger (newIndices [i]).ModInverse (M).ConvertToInt <uint32_t >();
376383 std::vector<uint32_t > vec (N);
377384 PrecomputeAutoMap (N, index, &vec);
378385
379386 auto privateKeyPermuted = std::make_shared<PrivateKeyImpl<Element>>(cc);
380387 privateKeyPermuted->SetPrivateElement (s.AutomorphismTransform (index, vec));
381- (*evalKeys)[indexList [i]] = cc->GetScheme ()->KeySwitchGen (privateKey, privateKeyPermuted);
388+ (*evalKeys)[newIndices [i]] = cc->GetScheme ()->KeySwitchGen (privateKey, privateKeyPermuted);
382389 }
383390
384391 return evalKeys;
0 commit comments