SEAL_v2.3.0-4.patch 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801
  1. From e37bf6b79c81cbbeff19378ad425f987c036286b Mon Sep 17 00:00:00 2001
  2. From: Kim Laine <kim.laine@microsoft.com>
  3. Date: Mon, 4 Dec 2017 16:09:56 -0800
  4. Subject: [PATCH 1/3] Explosed generic Galois automorphisms in public API
  5. ---
  6. SEAL/seal/evaluator.cpp | 5 +
  7. SEAL/seal/evaluator.h | 181 ++++++++++++++++++++++++++------
  8. SEAL/seal/keygenerator.cpp | 8 --
  9. SEAL/seal/keygenerator.h | 40 ++++---
  10. SEALNET/sealnet/EvaluatorWrapper.cpp | 146 ++++++++++++++++++++++++++
  11. SEALNET/sealnet/EvaluatorWrapper.h | 157 ++++++++++++++++++++++++---
  12. SEALNET/sealnet/KeyGeneratorWrapper.cpp | 33 ++++++
  13. SEALNET/sealnet/KeyGeneratorWrapper.h | 35 ++++++
  14. SEALNETTest/EvaluatorWrapper.cs | 82 +++++++++++++++
  15. SEALNETTest/KeyGeneratorWrapper.cs | 147 ++++++++++++++++++++++++++
  16. SEALTest/evaluator.cpp | 79 ++++++++++++++
  17. SEALTest/keygenerator.cpp | 146 ++++++++++++++++++++++++++
  18. 12 files changed, 990 insertions(+), 69 deletions(-)
  19. diff --git a/SEAL/seal/evaluator.cpp b/SEAL/seal/evaluator.cpp
  20. index 0a5b99d..8945b5d 100644
  21. --- a/SEAL/seal/evaluator.cpp
  22. +++ b/SEAL/seal/evaluator.cpp
  23. @@ -1791,6 +1791,11 @@ namespace seal
  24. void Evaluator::rotate_rows(Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys, const MemoryPoolHandle &pool)
  25. {
  26. + if (!qualifiers_.enable_batching)
  27. + {
  28. + throw logic_error("encryption parameters do not support batching");
  29. + }
  30. +
  31. // Is there anything to do?
  32. if (steps == 0)
  33. {
  34. diff --git a/SEAL/seal/evaluator.h b/SEAL/seal/evaluator.h
  35. index 5b67455..93cc1d2 100644
  36. --- a/SEAL/seal/evaluator.h
  37. +++ b/SEAL/seal/evaluator.h
  38. @@ -894,13 +894,136 @@ namespace seal
  39. @throws std::invalid_argument if plain_ntt is zero
  40. @throws std::logic_error if destination_ntt is aliased and needs to be reallocated
  41. */
  42. - inline void multiply_plain_ntt(const Ciphertext &encrypted_ntt, const Plaintext &plain_ntt,
  43. - Ciphertext &destination_ntt)
  44. + inline void multiply_plain_ntt(const Ciphertext &encrypted_ntt,
  45. + const Plaintext &plain_ntt, Ciphertext &destination_ntt)
  46. {
  47. destination_ntt = encrypted_ntt;
  48. multiply_plain_ntt(destination_ntt, plain_ntt);
  49. }
  50. + /**
  51. + Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
  52. + an appropriate set of Galois keys must also be provided. Dynamic memory allocations
  53. + in the process are allocated from the memory pool pointed to by the given
  54. + MemoryPoolHandle.
  55. +
  56. + The desired Galois automorphism is given as a Galois element, and must be an odd
  57. + integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
  58. + with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
  59. + to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
  60. + i steps to the right. The Galois element M-1 corresponds to a column rotation (row
  61. + swap). In the polynomial view (not batching), a Galois automorphism by a Galois
  62. + element p changes Enc(plain(x)) to Enc(plain(x^p)).
  63. +
  64. + @param[in] encrypted The ciphertext to apply the Galois automorphism to
  65. + @param[in] galois_elt The Galois element
  66. + @param[in] galois_keys The Galois keys
  67. + @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  68. + @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  69. + encryption parameters
  70. + @throws std::invalid_argument if encrypted has size greater than two
  71. + @throws std::invalid_argument if the Galois element is not valid
  72. + @throws std::invalid_argument if necessary Galois keys are not present
  73. + @throws std::invalid_argument if pool is uninitialized
  74. + */
  75. + void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt,
  76. + const GaloisKeys &galois_keys, const MemoryPoolHandle &pool);
  77. +
  78. + /**
  79. + Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
  80. + an appropriate set of Galois keys must also be provided. Dynamic memory allocations
  81. + in the process are allocated from the memory pool pointed to by the local
  82. + MemoryPoolHandle.
  83. +
  84. + The desired Galois automorphism is given as a Galois element, and must be an odd
  85. + integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
  86. + with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
  87. + to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
  88. + i steps to the right. The Galois element M-1 corresponds to a column rotation (row
  89. + swap). In the polynomial view (not batching), a Galois automorphism by a Galois
  90. + element p changes Enc(plain(x)) to Enc(plain(x^p)).
  91. +
  92. + @param[in] encrypted The ciphertext to apply the Galois automorphism to
  93. + @param[in] galois_elt The Galois element
  94. + @param[in] galois_keys The Galois keys
  95. + @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  96. + encryption parameters
  97. + @throws std::invalid_argument if encrypted has size greater than two
  98. + @throws std::invalid_argument if the Galois element is not valid
  99. + @throws std::invalid_argument if necessary Galois keys are not present
  100. + */
  101. + inline void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt,
  102. + const GaloisKeys &galois_keys)
  103. + {
  104. + apply_galois(encrypted, galois_elt, galois_keys, pool_);
  105. + }
  106. +
  107. + /**
  108. + Applies a Galois automorphism to a ciphertext and writes the result to the
  109. + destination parameter. To evaluate the Galois automorphism, an appropriate set of
  110. + Galois keys must also be provided. Dynamic memory allocations in the process are
  111. + allocated from the memory pool pointed to by the given MemoryPoolHandle.
  112. +
  113. + The desired Galois automorphism is given as a Galois element, and must be an odd
  114. + integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
  115. + with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
  116. + to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
  117. + i steps to the right. The Galois element M-1 corresponds to a column rotation (row
  118. + swap). In the polynomial view (not batching), a Galois automorphism by a Galois
  119. + element p changes Enc(plain(x)) to Enc(plain(x^p)).
  120. +
  121. + @param[in] encrypted The ciphertext to apply the Galois automorphism to
  122. + @param[in] galois_elt The Galois element
  123. + @param[in] galois_keys The Galois keys
  124. + @param[out] destination The ciphertext to overwrite with the result
  125. + @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  126. + @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  127. + encryption parameters
  128. + @throws std::invalid_argument if encrypted has size greater than two
  129. + @throws std::invalid_argument if the Galois element is not valid
  130. + @throws std::invalid_argument if necessary Galois keys are not present
  131. + @throws std::logic_error if destination is aliased and needs to be reallocated
  132. + @throws std::invalid_argument if pool is uninitialized
  133. + */
  134. + inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
  135. + const GaloisKeys &galois_keys, Ciphertext &destination,
  136. + const MemoryPoolHandle &pool)
  137. + {
  138. + destination = encrypted;
  139. + apply_galois(destination, galois_elt, galois_keys, pool);
  140. + }
  141. +
  142. + /**
  143. + Applies a Galois automorphism to a ciphertext and writes the result to the
  144. + destination parameter. To evaluate the Galois automorphism, an appropriate set of
  145. + Galois keys must also be provided. Dynamic memory allocations in the process are
  146. + allocated from the memory pool pointed to by the local MemoryPoolHandle.
  147. +
  148. + The desired Galois automorphism is given as a Galois element, and must be an odd
  149. + integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
  150. + with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
  151. + to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
  152. + i steps to the right. The Galois element M-1 corresponds to a column rotation (row
  153. + swap). In the polynomial view (not batching), a Galois automorphism by a Galois
  154. + element p changes Enc(plain(x)) to Enc(plain(x^p)).
  155. +
  156. + @param[in] encrypted The ciphertext to apply the Galois automorphism to
  157. + @param[in] galois_elt The Galois element
  158. + @param[in] galois_keys The Galois keys
  159. + @param[out] destination The ciphertext to overwrite with the result
  160. + @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  161. + encryption parameters
  162. + @throws std::invalid_argument if encrypted has size greater than two
  163. + @throws std::invalid_argument if the Galois element is not valid
  164. + @throws std::invalid_argument if necessary Galois keys are not present
  165. + @throws std::logic_error if destination is aliased and needs to be reallocated
  166. + */
  167. + inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
  168. + const GaloisKeys &galois_keys, Ciphertext &destination)
  169. + {
  170. + apply_galois(encrypted, galois_elt, galois_keys, destination, pool_);
  171. + }
  172. +
  173. /**
  174. Rotates plaintext matrix rows cyclically. When batching is used, this function rotates
  175. the encrypted plaintext matrix rows cyclically to the left (steps > 0) or to the right
  176. @@ -913,6 +1036,7 @@ namespace seal
  177. @param[in] steps The number of steps to rotate (negative left, positive right)
  178. @param[in] galois_keys The Galois keys
  179. @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  180. + @throws std::logic_error if the encryption parameters do not support batching
  181. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  182. encryption parameters
  183. @throws std::invalid_argument if encrypted has size greater than two
  184. @@ -934,13 +1058,15 @@ namespace seal
  185. @param[in] encrypted The ciphertext to rotate
  186. @param[in] steps The number of steps to rotate (negative left, positive right)
  187. @param[in] galois_keys The Galois keys
  188. + @throws std::logic_error if the encryption parameters do not support batching
  189. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  190. encryption parameters
  191. @throws std::invalid_argument if encrypted has size greater than two
  192. @throws std::invalid_argument if steps has too big absolute value
  193. @throws std::invalid_argument if necessary Galois keys are not present
  194. */
  195. - inline void rotate_rows(Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys)
  196. + inline void rotate_rows(Ciphertext &encrypted, int steps,
  197. + const GaloisKeys &galois_keys)
  198. {
  199. rotate_rows(encrypted, steps, galois_keys, pool_);
  200. }
  201. @@ -959,6 +1085,7 @@ namespace seal
  202. @param[in] galois_keys The Galois keys
  203. @param[out] destination The ciphertext to overwrite with the rotated result
  204. @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  205. + @throws std::logic_error if the encryption parameters do not support batching
  206. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  207. encryption parameters
  208. @throws std::invalid_argument if encrypted has size greater than two
  209. @@ -968,7 +1095,8 @@ namespace seal
  210. @throws std::invalid_argument if pool is uninitialized
  211. */
  212. inline void rotate_rows(const Ciphertext &encrypted, int steps,
  213. - const GaloisKeys &galois_keys, Ciphertext &destination, const MemoryPoolHandle &pool)
  214. + const GaloisKeys &galois_keys, Ciphertext &destination,
  215. + const MemoryPoolHandle &pool)
  216. {
  217. destination = encrypted;
  218. rotate_rows(destination, steps, galois_keys, pool);
  219. @@ -987,6 +1115,7 @@ namespace seal
  220. @param[in] steps The number of steps to rotate (negative left, positive right)
  221. @param[in] galois_keys The Galois keys
  222. @param[out] destination The ciphertext to overwrite with the rotated result
  223. + @throws std::logic_error if the encryption parameters do not support batching
  224. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  225. encryption parameters
  226. @throws std::invalid_argument if encrypted has size greater than two
  227. @@ -1011,6 +1140,7 @@ namespace seal
  228. @param[in] galois_keys The Galois keys
  229. @param[out] destination The ciphertext to overwrite with the rotated result
  230. @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  231. + @throws std::logic_error if the encryption parameters do not support batching
  232. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  233. encryption parameters
  234. @throws std::invalid_argument if encrypted has size greater than two
  235. @@ -1021,6 +1151,10 @@ namespace seal
  236. inline void rotate_columns(Ciphertext &encrypted, const GaloisKeys &galois_keys,
  237. const MemoryPoolHandle &pool)
  238. {
  239. + if (!qualifiers_.enable_batching)
  240. + {
  241. + throw std::logic_error("encryption parameters do not support batching");
  242. + }
  243. std::uint64_t m = (parms_.poly_modulus().coeff_count() - 1) << 1;
  244. apply_galois(encrypted, m - 1, galois_keys, pool);
  245. }
  246. @@ -1035,6 +1169,7 @@ namespace seal
  247. @param[in] encrypted The ciphertext to rotate
  248. @param[in] galois_keys The Galois keys
  249. @param[out] destination The ciphertext to overwrite with the rotated result
  250. + @throws std::logic_error if the encryption parameters do not support batching
  251. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  252. encryption parameters
  253. @throws std::invalid_argument if encrypted has size greater than two
  254. @@ -1058,6 +1193,7 @@ namespace seal
  255. @param[in] galois_keys The Galois keys
  256. @param[out] destination The ciphertext to overwrite with the rotated result
  257. @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
  258. + @throws std::logic_error if the encryption parameters do not support batching
  259. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  260. encryption parameters
  261. @throws std::invalid_argument if encrypted has size greater than two
  262. @@ -1084,6 +1220,7 @@ namespace seal
  263. @param[in] encrypted The ciphertext to rotate
  264. @param[in] galois_keys The Galois keys
  265. @param[out] destination The ciphertext to overwrite with the rotated result
  266. + @throws std::logic_error if the encryption parameters do not support batching
  267. @throws std::invalid_argument if encrypted or galois_keys is not valid for the
  268. encryption parameters
  269. @throws std::invalid_argument if encrypted has size greater than two
  270. @@ -1101,10 +1238,11 @@ namespace seal
  271. Evaluator &operator =(Evaluator &&assign) = delete;
  272. - void relinearize(Ciphertext &encrypted, const EvaluationKeys &evaluation_keys, int destination_size,
  273. - const MemoryPoolHandle &pool);
  274. + void relinearize(Ciphertext &encrypted, const EvaluationKeys &evaluation_keys,
  275. + int destination_size, const MemoryPoolHandle &pool);
  276. - inline void decompose_single_coeff(const std::uint64_t *value, std::uint64_t *destination, const MemoryPoolHandle &pool)
  277. + inline void decompose_single_coeff(const std::uint64_t *value,
  278. + std::uint64_t *destination, const MemoryPoolHandle &pool)
  279. {
  280. #ifdef SEAL_DEBUG
  281. if (value == nullptr)
  282. @@ -1150,7 +1288,8 @@ namespace seal
  283. }
  284. }
  285. - inline void decompose(const std::uint64_t *value, std::uint64_t *destination, const MemoryPoolHandle &pool)
  286. + inline void decompose(const std::uint64_t *value, std::uint64_t *destination,
  287. + const MemoryPoolHandle &pool)
  288. {
  289. #ifdef SEAL_DEBUG
  290. if (value == nullptr)
  291. @@ -1209,32 +1348,6 @@ namespace seal
  292. void populate_Zmstar_to_generator();
  293. - // The apply_galois function applies a Galois automorphism to a ciphertext.
  294. - // It is needed for slot permutations.
  295. - // Input: encryption of M(x) and an integer p such that gcd(p, m) = 1.
  296. - // Output: encryption of M(x^p).
  297. - // The function requires certain GaloisKeys and auxiliary data.
  298. - void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, const GaloisKeys &evaluation_keys,
  299. - const MemoryPoolHandle &pool);
  300. -
  301. - inline void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, const GaloisKeys &evaluation_keys)
  302. - {
  303. - apply_galois(encrypted, galois_elt, evaluation_keys, pool_);
  304. - }
  305. -
  306. - inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
  307. - const GaloisKeys &evaluation_keys, Ciphertext &destination, const MemoryPoolHandle &pool)
  308. - {
  309. - destination = encrypted;
  310. - apply_galois(destination, galois_elt, evaluation_keys, pool);
  311. - }
  312. -
  313. - inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
  314. - const GaloisKeys &evaluation_keys, Ciphertext &destination)
  315. - {
  316. - apply_galois(encrypted, galois_elt, evaluation_keys, destination, pool_);
  317. - }
  318. -
  319. MemoryPoolHandle pool_;
  320. EncryptionParameters parms_;
  321. diff --git a/SEAL/seal/keygenerator.cpp b/SEAL/seal/keygenerator.cpp
  322. index fa7fd46..ee6338f 100644
  323. --- a/SEAL/seal/keygenerator.cpp
  324. +++ b/SEAL/seal/keygenerator.cpp
  325. @@ -293,10 +293,6 @@ namespace seal
  326. {
  327. throw logic_error("cannot generate galois keys for unspecified secret key");
  328. }
  329. - if (!qualifiers_.enable_batching)
  330. - {
  331. - throw logic_error("encryption parameters are not valid for batching");
  332. - }
  333. // Check that decomposition_bit_count is in correct interval
  334. if (decomposition_bit_count < SEAL_DBC_MIN || decomposition_bit_count > SEAL_DBC_MAX)
  335. @@ -426,10 +422,6 @@ namespace seal
  336. {
  337. throw logic_error("cannot generate galois keys for unspecified secret key");
  338. }
  339. - if (!qualifiers_.enable_batching)
  340. - {
  341. - throw logic_error("encryption parameters are not valid for batching");
  342. - }
  343. // Check that decomposition_bit_count is in correct interval
  344. if (decomposition_bit_count < SEAL_DBC_MIN || decomposition_bit_count > SEAL_DBC_MAX)
  345. diff --git a/SEAL/seal/keygenerator.h b/SEAL/seal/keygenerator.h
  346. index a702a3e..393aa61 100644
  347. --- a/SEAL/seal/keygenerator.h
  348. +++ b/SEAL/seal/keygenerator.h
  349. @@ -99,15 +99,38 @@ namespace seal
  350. }
  351. /**
  352. - Generates Galois keys.
  353. + Generates Galois keys. This function creates logarithmically many (in degree of the
  354. + polynomial modulus) Galois keys that is sufficient to apply any Galois automorphism
  355. + (e.g. rotations) on encrypted data. Most users will want to use this overload of
  356. + the function.
  357. @param[in] decomposition_bit_count The decomposition bit count
  358. @param[out] galois_keys The Galois keys instance to overwrite with the generated keys
  359. @throws std::invalid_argument if decomposition_bit_count is not within [1, 60]
  360. - @throws std::logic_error if the encryption parameters do not support batching
  361. - */
  362. + */
  363. void generate_galois_keys(int decomposition_bit_count, GaloisKeys &galois_keys);
  364. + /**
  365. + Generates Galois keys. This function creates specific Galois keys that can be used to
  366. + apply specific Galois automorphisms on encrypted data. The user needs to give as
  367. + input a vector of Galois elements corresponding to the keys that are to be created.
  368. +
  369. + The Galois elements are odd integers in the interval [1, M-1], where M = 2*N, and
  370. + N = degree(poly_modulus). Used with batching, a Galois element 3^i % M corresponds
  371. + to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M
  372. + corresponds to a cyclic row rotation i steps to the right. The Galois element M-1
  373. + corresponds to a column rotation (row swap). In the polynomial view (not batching),
  374. + a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
  375. +
  376. + @param[in] decomposition_bit_count The decomposition bit count
  377. + @param[in] galois_elts The Galois elements for which to generate keys
  378. + @param[out] galois_keys The Galois keys instance to overwrite with the generated keys
  379. + @throws std::invalid_argument if decomposition_bit_count is not within [1, 60]
  380. + @throws std::invalid_argument if the Galois elements are not valid
  381. + */
  382. + void generate_galois_keys(int decomposition_bit_count,
  383. + const std::vector<std::uint64_t> &galois_elts, GaloisKeys &galois_keys);
  384. +
  385. private:
  386. KeyGenerator(const KeyGenerator &copy) = delete;
  387. @@ -141,17 +164,6 @@ namespace seal
  388. return generated_;
  389. }
  390. - void generate_galois_keys(int decomposition_bit_count,
  391. - const std::vector<std::uint64_t> &galois_elts, GaloisKeys &galois_keys);
  392. -
  393. - inline GaloisKeys generate_galois_keys(int decomposition_bit_count,
  394. - const std::vector<std::uint64_t> &galois_elts)
  395. - {
  396. - GaloisKeys keys;
  397. - generate_galois_keys(decomposition_bit_count, galois_elts, keys);
  398. - return keys;
  399. - }
  400. -
  401. MemoryPoolHandle pool_;
  402. EncryptionParameters parms_;
  403. diff --git a/SEALNET/sealnet/EvaluatorWrapper.cpp b/SEALNET/sealnet/EvaluatorWrapper.cpp
  404. index b4868ed..648fbfd 100644
  405. --- a/SEALNET/sealnet/EvaluatorWrapper.cpp
  406. +++ b/SEALNET/sealnet/EvaluatorWrapper.cpp
  407. @@ -1513,6 +1513,152 @@ namespace Microsoft
  408. }
  409. }
  410. + void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys)
  411. + {
  412. + if (evaluator_ == nullptr)
  413. + {
  414. + throw gcnew ObjectDisposedException("Evaluator is disposed");
  415. + }
  416. + if (encrypted == nullptr)
  417. + {
  418. + throw gcnew ArgumentNullException("encrypted cannot be null");
  419. + }
  420. + if (galoisKeys == nullptr)
  421. + {
  422. + throw gcnew ArgumentNullException("galoisKeys cannot be null");
  423. + }
  424. + try
  425. + {
  426. + evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt, galoisKeys->GetKeys());
  427. + GC::KeepAlive(encrypted);
  428. + GC::KeepAlive(galoisKeys);
  429. + }
  430. + catch (const exception &e)
  431. + {
  432. + HandleException(&e);
  433. + }
  434. + catch (...)
  435. + {
  436. + HandleException(nullptr);
  437. + }
  438. + }
  439. +
  440. + void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys,
  441. + MemoryPoolHandle ^pool)
  442. + {
  443. + if (evaluator_ == nullptr)
  444. + {
  445. + throw gcnew ObjectDisposedException("Evaluator is disposed");
  446. + }
  447. + if (encrypted == nullptr)
  448. + {
  449. + throw gcnew ArgumentNullException("encrypted cannot be null");
  450. + }
  451. + if (galoisKeys == nullptr)
  452. + {
  453. + throw gcnew ArgumentNullException("galoisKeys cannot be null");
  454. + }
  455. + if (pool == nullptr)
  456. + {
  457. + throw gcnew ArgumentNullException("pool cannot be null");
  458. + }
  459. + try
  460. + {
  461. + evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt,
  462. + galoisKeys->GetKeys(), pool->GetHandle());
  463. + GC::KeepAlive(encrypted);
  464. + GC::KeepAlive(galoisKeys);
  465. + GC::KeepAlive(pool);
  466. + }
  467. + catch (const exception &e)
  468. + {
  469. + HandleException(&e);
  470. + }
  471. + catch (...)
  472. + {
  473. + HandleException(nullptr);
  474. + }
  475. + }
  476. +
  477. + void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys,
  478. + Ciphertext ^destination)
  479. + {
  480. + if (evaluator_ == nullptr)
  481. + {
  482. + throw gcnew ObjectDisposedException("Evaluator is disposed");
  483. + }
  484. + if (encrypted == nullptr)
  485. + {
  486. + throw gcnew ArgumentNullException("encrypted cannot be null");
  487. + }
  488. + if (galoisKeys == nullptr)
  489. + {
  490. + throw gcnew ArgumentNullException("galoisKeys cannot be null");
  491. + }
  492. + if (destination == nullptr)
  493. + {
  494. + throw gcnew ArgumentNullException("destination cannot be null");
  495. + }
  496. + try
  497. + {
  498. + evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt,
  499. + galoisKeys->GetKeys(), destination->GetCiphertext());
  500. + GC::KeepAlive(encrypted);
  501. + GC::KeepAlive(galoisKeys);
  502. + GC::KeepAlive(destination);
  503. + }
  504. + catch (const exception &e)
  505. + {
  506. + HandleException(&e);
  507. + }
  508. + catch (...)
  509. + {
  510. + HandleException(nullptr);
  511. + }
  512. + }
  513. +
  514. + void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys,
  515. + Ciphertext ^destination, MemoryPoolHandle ^pool)
  516. + {
  517. + if (evaluator_ == nullptr)
  518. + {
  519. + throw gcnew ObjectDisposedException("Evaluator is disposed");
  520. + }
  521. + if (encrypted == nullptr)
  522. + {
  523. + throw gcnew ArgumentNullException("encrypted cannot be null");
  524. + }
  525. + if (galoisKeys == nullptr)
  526. + {
  527. + throw gcnew ArgumentNullException("galoisKeys cannot be null");
  528. + }
  529. + if (destination == nullptr)
  530. + {
  531. + throw gcnew ArgumentNullException("destination cannot be null");
  532. + }
  533. + if (pool == nullptr)
  534. + {
  535. + throw gcnew ArgumentNullException("pool cannot be null");
  536. + }
  537. + try
  538. + {
  539. + evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt,
  540. + galoisKeys->GetKeys(), destination->GetCiphertext(), pool->GetHandle());
  541. + GC::KeepAlive(encrypted);
  542. + GC::KeepAlive(galoisKeys);
  543. + GC::KeepAlive(destination);
  544. + GC::KeepAlive(pool);
  545. + }
  546. + catch (const exception &e)
  547. + {
  548. + HandleException(&e);
  549. + }
  550. + catch (...)
  551. + {
  552. + HandleException(nullptr);
  553. + }
  554. + }
  555. +
  556. void Evaluator::RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys)
  557. {
  558. if (evaluator_ == nullptr)
  559. diff --git a/SEALNET/sealnet/EvaluatorWrapper.h b/SEALNET/sealnet/EvaluatorWrapper.h
  560. index 1f99af1..7a7ef05 100644
  561. --- a/SEALNET/sealnet/EvaluatorWrapper.h
  562. +++ b/SEALNET/sealnet/EvaluatorWrapper.h
  563. @@ -113,7 +113,7 @@ namespace Microsoft
  564. by the given <see cref="MemoryPoolHandle" />.
  565. </remarks
  566. <param name="context">The SEALContext</param>
  567. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  568. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  569. <exception cref="System::ArgumentException">if encryption parameters are not valid</exception>
  570. <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  571. <exception cref="System::ArgumentNullException">if context or pool is null</exception>
  572. @@ -256,7 +256,7 @@ namespace Microsoft
  573. </remarks>
  574. <param name="encrypted1">The first ciphertext to multiply</param>
  575. <param name="encrypted2">The second ciphertext to multiply</param>
  576. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  577. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  578. <exception cref="System::ArgumentException">if encrypted1 or encrypted2 is not valid
  579. for the encryption parameters</exception>
  580. <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  581. @@ -296,7 +296,7 @@ namespace Microsoft
  582. <param name="encrypted1">The first ciphertext to multiply</param>
  583. <param name="encrypted2">The second ciphertext to multiply</param>
  584. <param name="destination">The ciphertext to overwrite with the multiplication result</param>
  585. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  586. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  587. <exception cref="System::ArgumentException">if encrypted1 or encrypted2 is not valid
  588. for the encryption parameters</exception>
  589. <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  590. @@ -330,7 +330,7 @@ namespace Microsoft
  591. the memory pool pointed to by the given <see cref="MemoryPoolHandle" />.
  592. </remarks>
  593. <param name="encrypted">The ciphertext to square</param>
  594. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  595. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  596. <exception cref="System::ArgumentException">if encrypted is not valid for the
  597. encryption parameters</exception>
  598. <exception cref="System::ArgumentNullException">if encrypted or pool is
  599. @@ -365,7 +365,7 @@ namespace Microsoft
  600. </remarks>
  601. <param name="encrypted">The ciphertext to square</param>
  602. <param name="destination">The ciphertext to overwrite with the square</param>
  603. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  604. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  605. <exception cref="System::ArgumentException">if encrypted is not valid for the
  606. encryption parameters</exception>
  607. <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  608. @@ -385,7 +385,7 @@ namespace Microsoft
  609. </remarks>
  610. <param name="encrypted">The ciphertext to relinearize</param>
  611. <param name="evaluationKeys">The evaluation keys</param>
  612. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  613. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  614. <exception cref="System::ArgumentException">if encrypted or evaluationKeys is not
  615. valid for the encryption parameters</exception>
  616. <exception cref="System::ArgumentException">if the size of evaluationKeys is too
  617. @@ -450,7 +450,7 @@ namespace Microsoft
  618. <param name="encrypted">The ciphertext to relinearize</param>
  619. <param name="evaluationKeys">The evaluation keys</param>
  620. <param name="destination">The ciphertext to overwrite with the relinearized result</param>
  621. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  622. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  623. <exception cref="System::ArgumentException">if encrypted or evaluationKeys is not valid
  624. for the encryption parameters</exception>
  625. <exception cref="System::ArgumentException">if the size of evaluationKeys is too
  626. @@ -1024,6 +1024,121 @@ namespace Microsoft
  627. */
  628. void MultiplyPlainNTT(Ciphertext ^encryptedNTT, Plaintext ^plainNTT);
  629. + /**
  630. + <summary>Applies a Galois automorphism to a ciphertext.</summary>
  631. +
  632. + <remarks>
  633. + Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
  634. + an appropriate set of Galois keys must also be provided. Dynamic memory allocations
  635. + in the process are allocated from the memory pool pointed to by the local
  636. + <see cref="MemoryPoolHandle" />.
  637. + </remarks>
  638. + <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
  639. + <param name="galoisElt">The Galois element</param>
  640. + <param name="galoisKeys">The Galois keys</param>
  641. + <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  642. + for the encryption parameters</exception>
  643. + <exception cref="System::ArgumentException">if encrypted has size greater than
  644. + two</exception>
  645. + <exception cref="System::ArgumentException">if the Galois element is not
  646. + valid</exception>
  647. + <exception cref="System::ArgumentException">if necessary Galois keys are not
  648. + present</exception>
  649. + <exception cref="System::ArgumentNullException">if encrypted or galoisKeys is
  650. + null</exception>
  651. + */
  652. + void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
  653. + GaloisKeys ^galoisKeys);
  654. +
  655. + /**
  656. + <summary>Applies a Galois automorphism to a ciphertext.</summary>
  657. +
  658. + <remarks>
  659. + Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
  660. + an appropriate set of Galois keys must also be provided. Dynamic memory allocations
  661. + in the process are allocated from the memory pool pointed to by the given
  662. + <see cref="MemoryPoolHandle" />.
  663. + </remarks>
  664. + <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
  665. + <param name="galoisElt">The Galois element</param>
  666. + <param name="galoisKeys">The Galois keys</param>
  667. + <param name="destination">The
  668. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  669. + <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  670. + for the encryption parameters</exception>
  671. + <exception cref="System::ArgumentException">if encrypted has size greater than
  672. + two</exception>
  673. + <exception cref="System::ArgumentException">if the Galois element is not
  674. + valid</exception>
  675. + <exception cref="System::ArgumentException">if necessary Galois keys are not
  676. + present</exception>
  677. + <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  678. + <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
  679. + is null</exception>
  680. + */
  681. + void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
  682. + GaloisKeys ^galoisKeys, MemoryPoolHandle ^pool);
  683. +
  684. + /**
  685. + <summary>Applies a Galois automorphism to a ciphertext and writes the result
  686. + to the destination parameter.</summary>
  687. +
  688. + <remarks>
  689. + Applies a Galois automorphism to a ciphertext and writes the result to the
  690. + destination parameter. To evaluate the Galois automorphism, an appropriate
  691. + set of Galois keys must also be provided. Dynamic memory allocations in the
  692. + process are allocated from the memory pool pointed to by the local
  693. + <see cref="MemoryPoolHandle" />.
  694. + </remarks>
  695. + <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
  696. + <param name="galoisElt">The Galois element</param>
  697. + <param name="galoisKeys">The Galois keys</param>
  698. + <param name="destination">The ciphertext to overwrite with the result</param>
  699. + <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  700. + for the encryption parameters</exception>
  701. + <exception cref="System::ArgumentException">if encrypted has size greater than
  702. + two</exception>
  703. + <exception cref="System::ArgumentException">if the Galois element is not
  704. + valid</exception>
  705. + <exception cref="System::ArgumentException">if necessary Galois keys are not
  706. + present</exception>
  707. + <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or
  708. + destination is null</exception>
  709. + */
  710. + void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
  711. + GaloisKeys ^galoisKeys, Ciphertext ^destination);
  712. +
  713. + /**
  714. + <summary>Applies a Galois automorphism to a ciphertext and writes the result
  715. + to the destination parameter.</summary>
  716. +
  717. + <remarks>
  718. + Applies a Galois automorphism to a ciphertext and writes the result to the
  719. + destination parameter. To evaluate the Galois automorphism, an appropriate
  720. + set of Galois keys must also be provided. Dynamic memory allocations in the
  721. + process are allocated from the memory pool pointed to by the given
  722. + <see cref="MemoryPoolHandle" />.
  723. + </remarks>
  724. + <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
  725. + <param name="galoisElt">The Galois element</param>
  726. + <param name="galoisKeys">The Galois keys</param>
  727. + <param name="destination">The ciphertext to overwrite with the result</param>
  728. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  729. + <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  730. + for the encryption parameters</exception>
  731. + <exception cref="System::ArgumentException">if encrypted has size greater than
  732. + two</exception>
  733. + <exception cref="System::ArgumentException">if the Galois element is not
  734. + valid</exception>
  735. + <exception cref="System::ArgumentException">if necessary Galois keys are not
  736. + present</exception>
  737. + <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  738. + <exception cref="System::ArgumentNullException">if encrypted, galoisKeys,
  739. + destination, or pool is null</exception>
  740. + */
  741. + void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
  742. + GaloisKeys ^galoisKeys, Ciphertext ^destination, MemoryPoolHandle ^pool);
  743. +
  744. /**
  745. <summary>Rotates plaintext matrix rows cyclically.</summary>
  746. @@ -1038,6 +1153,8 @@ namespace Microsoft
  747. <param name="encrypted">The ciphertext to rotate</param>
  748. <param name="steps">The number of steps to rotate (negative left, positive right)</param>
  749. <param name="galoisKeys">The Galois keys</param>
  750. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  751. + not support batching</exception>
  752. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  753. for the encryption parameters</exception>
  754. <exception cref="System::ArgumentException">if encrypted has size greater than
  755. @@ -1046,7 +1163,7 @@ namespace Microsoft
  756. value</exception>
  757. <exception cref="System::ArgumentException">if necessary Galois keys are not
  758. present</exception>
  759. - <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
  760. + <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or pool
  761. is null</exception>
  762. */
  763. void RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys);
  764. @@ -1065,7 +1182,9 @@ namespace Microsoft
  765. <param name="encrypted">The ciphertext to rotate</param>
  766. <param name="steps">The number of steps to rotate (negative left, positive right)</param>
  767. <param name="galoisKeys">The Galois keys</param>
  768. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  769. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  770. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  771. + not support batching</exception>
  772. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  773. for the encryption parameters</exception>
  774. <exception cref="System::ArgumentException">if encrypted has size greater than
  775. @@ -1075,7 +1194,7 @@ namespace Microsoft
  776. <exception cref="System::ArgumentException">if necessary Galois keys are not
  777. present</exception>
  778. <exception cref="System::ArgumentException">if pool is uninitialized</exception>
  779. - <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
  780. + <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or pool
  781. is null</exception>
  782. */
  783. void RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys,
  784. @@ -1097,6 +1216,8 @@ namespace Microsoft
  785. <param name="steps">The number of steps to rotate (negative left, positive right)</param>
  786. <param name="galoisKeys">The Galois keys</param>
  787. <param name="destination">The ciphertext to overwrite with the rotated result</param>
  788. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  789. + not support batching</exception>
  790. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  791. for the encryption parameters</exception>
  792. <exception cref="System::ArgumentException">if encrypted has size greater than
  793. @@ -1127,7 +1248,9 @@ namespace Microsoft
  794. <param name="steps">The number of steps to rotate (negative left, positive right)</param>
  795. <param name="galoisKeys">The Galois keys</param>
  796. <param name="destination">The ciphertext to overwrite with the rotated result</param>
  797. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  798. + <param name="pool">The MemoryPoolHandle pointing to a valid memory param>
  799. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  800. + not support batching</exception>
  801. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  802. for the encryption parameters</exception>
  803. <exception cref="System::ArgumentException">if encrypted has size greater than
  804. @@ -1156,6 +1279,8 @@ namespace Microsoft
  805. </remarks>
  806. <param name="encrypted">The ciphertext to rotate</param>
  807. <param name="galoisKeys">The Galois keys</param>
  808. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  809. + not support batching</exception>
  810. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  811. for the encryption parameters</exception>
  812. <exception cref="System::ArgumentException">if encrypted has size greater than
  813. @@ -1180,7 +1305,9 @@ namespace Microsoft
  814. </remarks>
  815. <param name="encrypted">The ciphertext to rotate</param>
  816. <param name="galoisKeys">The Galois keys</param>
  817. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  818. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  819. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  820. + not support batching</exception>
  821. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  822. for the encryption parameters</exception>
  823. <exception cref="System::ArgumentException">if encrypted has size greater than
  824. @@ -1208,6 +1335,8 @@ namespace Microsoft
  825. <param name="encrypted">The ciphertext to rotate</param>
  826. <param name="galoisKeys">The Galois keys</param>
  827. <param name="destination">The ciphertext to overwrite with the rotated result</param>
  828. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  829. + not support batching</exception>
  830. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  831. for the encryption parameters</exception>
  832. <exception cref="System::ArgumentException">if encrypted has size greater than
  833. @@ -1234,7 +1363,9 @@ namespace Microsoft
  834. <param name="encrypted">The ciphertext to rotate</param>
  835. <param name="galoisKeys">The Galois keys</param>
  836. <param name="destination">The ciphertext to overwrite with the rotated result</param>
  837. - <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
  838. + <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
  839. + <exception cref="System::InvalidOperationException">if the encryption parameters do
  840. + not support batching</exception>
  841. <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
  842. for the encryption parameters</exception>
  843. <exception cref="System::ArgumentException">if necessary Galois keys are not
  844. diff --git a/SEALNET/sealnet/KeyGeneratorWrapper.cpp b/SEALNET/sealnet/KeyGeneratorWrapper.cpp
  845. index c9d52de..e1547f1 100644
  846. --- a/SEALNET/sealnet/KeyGeneratorWrapper.cpp
  847. +++ b/SEALNET/sealnet/KeyGeneratorWrapper.cpp
  848. @@ -1,10 +1,12 @@
  849. #include <cstddef>
  850. +#include <vector>
  851. #include "sealnet/KeyGeneratorWrapper.h"
  852. #include "sealnet/BigPolyWrapper.h"
  853. #include "sealnet/BigUIntWrapper.h"
  854. #include "sealnet/Common.h"
  855. using namespace System;
  856. +using namespace System::Collections::Generic;
  857. using namespace std;
  858. namespace Microsoft
  859. @@ -205,6 +207,37 @@ namespace Microsoft
  860. }
  861. }
  862. + void KeyGenerator::GenerateGaloisKeys(int decompositionBitCount, List<UInt64> ^galoisElts,
  863. + GaloisKeys ^galoisKeys)
  864. + {
  865. + if (generator_ == nullptr)
  866. + {
  867. + throw gcnew ObjectDisposedException("KeyGenerator is disposed");
  868. + }
  869. + if (galoisKeys == nullptr)
  870. + {
  871. + throw gcnew ArgumentNullException("galoisKeys cannot be null");
  872. + }
  873. + try
  874. + {
  875. + std::vector<std::uint64_t> v_galois_elts;
  876. + for (int i = 0; i < galoisElts->Count; i++)
  877. + {
  878. + v_galois_elts.push_back(galoisElts[i]);
  879. + }
  880. + generator_->generate_galois_keys(decompositionBitCount, v_galois_elts, galoisKeys->GetKeys());
  881. + GC::KeepAlive(galoisElts);
  882. + }
  883. + catch (const exception &e)
  884. + {
  885. + HandleException(&e);
  886. + }
  887. + catch (...)
  888. + {
  889. + HandleException(nullptr);
  890. + }
  891. + }
  892. +
  893. Microsoft::Research::SEAL::PublicKey ^KeyGenerator::PublicKey::get()
  894. {
  895. if (generator_ == nullptr)
  896. diff --git a/SEALNET/sealnet/KeyGeneratorWrapper.h b/SEALNET/sealnet/KeyGeneratorWrapper.h
  897. index 7fd722c..cf7f1fc 100644
  898. --- a/SEALNET/sealnet/KeyGeneratorWrapper.h
  899. +++ b/SEALNET/sealnet/KeyGeneratorWrapper.h
  900. @@ -158,6 +158,12 @@ namespace Microsoft
  901. /**
  902. <summary>Generates Galois keys.</summary>
  903. + <remarks>
  904. + Generates Galois keys. This function creates logarithmically many (in degree of the
  905. + polynomial modulus) Galois keys that is sufficient to apply any Galois automorphism
  906. + (e.g. rotations) on encrypted data. Most users will want to use this overload of
  907. + the function.
  908. + </remarks>
  909. <param name="decompositionBitCount">The decomposition bit count</param>
  910. <param name="galoisKeys">The Galois keys instance to overwrite with the generated
  911. keys</param>
  912. @@ -167,6 +173,35 @@ namespace Microsoft
  913. */
  914. void GenerateGaloisKeys(int decompositionBitCount, GaloisKeys ^galoisKeys);
  915. + /**
  916. + <summary>Generates Galois keys.</summary>
  917. +
  918. + <remarks>
  919. + Generates Galois keys. This function creates specific Galois keys that can be used to
  920. + apply specific Galois automorphisms on encrypted data. The user needs to give as
  921. + input a vector of Galois elements corresponding to the keys that are to be created.
  922. +
  923. + The Galois elements are odd integers in the interval [1, M-1], where M = 2*N, and
  924. + N = degree(PolyModulus). Used with batching, a Galois element 3^i % M corresponds
  925. + to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M
  926. + corresponds to a cyclic row rotation i steps to the right. The Galois element M-1
  927. + corresponds to a column rotation (row swap). In the polynomial view (not batching),
  928. + a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
  929. + </remarks>
  930. + <param name="decompositionBitCount">The decomposition bit count</param>
  931. + <param name="galoisElts">The Galois elements for which to generate keys</param>
  932. + <param name="galoisKeys">The Galois keys instance to overwrite with the generated
  933. + keys</param>
  934. + <exception cref="System::ArgumentException">if decompositionBitCount is not
  935. + within [0, 60]</exception>
  936. + <exception cref="System::ArgumentException">if the Galois elements are not
  937. + valid</exception>
  938. + <exception cref="System::ArgumentNullException">if galoisKeys is null</exception>
  939. + */
  940. + void GenerateGaloisKeys(int decompositionBitCount,
  941. + System::Collections::Generic::List<System::UInt64> ^galoisElts,
  942. + GaloisKeys ^galoisKeys);
  943. +
  944. /**
  945. <summary>Destroys the KeyGenerator.</summary>
  946. */
  947. diff --git a/SEALNETTest/EvaluatorWrapper.cs b/SEALNETTest/EvaluatorWrapper.cs
  948. index 541786c..4321ecd 100644
  949. --- a/SEALNETTest/EvaluatorWrapper.cs
  950. +++ b/SEALNETTest/EvaluatorWrapper.cs
  951. @@ -982,6 +982,88 @@ namespace SEALNETTest
  952. Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);
  953. }
  954. + [TestMethod]
  955. + public void FVEncryptApplyGaloisDecryptNET()
  956. + {
  957. + var parms = new EncryptionParameters();
  958. + var plain_modulus = new SmallModulus(257);
  959. + parms.NoiseStandardDeviation = 3.19;
  960. + parms.PlainModulus = plain_modulus;
  961. + parms.PolyModulus = "1x^8 + 1";
  962. + parms.CoeffModulus = new List<SmallModulus> {
  963. + DefaultParams.SmallMods40Bit(0), DefaultParams.SmallMods40Bit(1)
  964. + };
  965. + var context = new SEALContext(parms);
  966. + var keygen = new KeyGenerator(context);
  967. + var glk = new GaloisKeys();
  968. + keygen.GenerateGaloisKeys(24, new List<UInt64> { 1, 3, 5, 15 }, glk);
  969. +
  970. + var encryptor = new Encryptor(context, keygen.PublicKey);
  971. + var evaluator = new Evaluator(context);
  972. + var decryptor = new Decryptor(context, keygen.SecretKey);
  973. +
  974. + var plain = new Plaintext("1");
  975. + var encrypted = new Ciphertext();
  976. + encryptor.Encrypt(plain, encrypted);
  977. + evaluator.ApplyGalois(encrypted, 1, glk);
  978. + decryptor.Decrypt(encrypted, plain);
  979. + Assert.AreEqual("1", plain.ToString());
  980. + evaluator.ApplyGalois(encrypted, 3, glk);
  981. + decryptor.Decrypt(encrypted, plain);
  982. + Assert.AreEqual("1", plain.ToString());
  983. + evaluator.ApplyGalois(encrypted, 5, glk);
  984. + decryptor.Decrypt(encrypted, plain);
  985. + Assert.AreEqual("1", plain.ToString());
  986. + evaluator.ApplyGalois(encrypted, 15, glk);
  987. + decryptor.Decrypt(encrypted, plain);
  988. + Assert.AreEqual("1", plain.ToString());
  989. +
  990. + plain.Set("1x^1");
  991. + encryptor.Encrypt(plain, encrypted);
  992. + evaluator.ApplyGalois(encrypted, 1, glk);
  993. + decryptor.Decrypt(encrypted, plain);
  994. + Assert.AreEqual("1x^1", plain.ToString());
  995. + evaluator.ApplyGalois(encrypted, 3, glk);
  996. + decryptor.Decrypt(encrypted, plain);
  997. + Assert.AreEqual("1x^3", plain.ToString());
  998. + evaluator.ApplyGalois(encrypted, 5, glk);
  999. + decryptor.Decrypt(encrypted, plain);
  1000. + Assert.AreEqual("100x^7", plain.ToString());
  1001. + evaluator.ApplyGalois(encrypted, 15, glk);
  1002. + decryptor.Decrypt(encrypted, plain);
  1003. + Assert.AreEqual("1x^1", plain.ToString());
  1004. +
  1005. + plain.Set("1x^2");
  1006. + encryptor.Encrypt(plain, encrypted);
  1007. + evaluator.ApplyGalois(encrypted, 1, glk);
  1008. + decryptor.Decrypt(encrypted, plain);
  1009. + Assert.AreEqual("1x^2", plain.ToString());
  1010. + evaluator.ApplyGalois(encrypted, 3, glk);
  1011. + decryptor.Decrypt(encrypted, plain);
  1012. + Assert.AreEqual("1x^6", plain.ToString());
  1013. + evaluator.ApplyGalois(encrypted, 5, glk);
  1014. + decryptor.Decrypt(encrypted, plain);
  1015. + Assert.AreEqual("100x^6", plain.ToString());
  1016. + evaluator.ApplyGalois(encrypted, 15, glk);
  1017. + decryptor.Decrypt(encrypted, plain);
  1018. + Assert.AreEqual("1x^2", plain.ToString());
  1019. +
  1020. + plain.Set("1x^3 + 2x^2 + 1x^1 + 1");
  1021. + encryptor.Encrypt(plain, encrypted);
  1022. + evaluator.ApplyGalois(encrypted, 1, glk);
  1023. + decryptor.Decrypt(encrypted, plain);
  1024. + Assert.AreEqual("1x^3 + 2x^2 + 1x^1 + 1", plain.ToString());
  1025. + evaluator.ApplyGalois(encrypted, 3, glk);
  1026. + decryptor.Decrypt(encrypted, plain);
  1027. + Assert.AreEqual("2x^6 + 1x^3 + 100x^1 + 1", plain.ToString());
  1028. + evaluator.ApplyGalois(encrypted, 5, glk);
  1029. + decryptor.Decrypt(encrypted, plain);
  1030. + Assert.AreEqual("100x^7 + FFx^6 + 100x^5 + 1", plain.ToString());
  1031. + evaluator.ApplyGalois(encrypted, 15, glk);
  1032. + decryptor.Decrypt(encrypted, plain);
  1033. + Assert.AreEqual("1x^3 + 2x^2 + 1x^1 + 1", plain.ToString());
  1034. + }
  1035. +
  1036. [TestMethod]
  1037. public void FVEncryptRotateMatrixDecryptNET()
  1038. {
  1039. diff --git a/SEALNETTest/KeyGeneratorWrapper.cs b/SEALNETTest/KeyGeneratorWrapper.cs
  1040. index 04f9738..2a74a89 100644
  1041. --- a/SEALNETTest/KeyGeneratorWrapper.cs
  1042. +++ b/SEALNETTest/KeyGeneratorWrapper.cs
  1043. @@ -1,6 +1,7 @@
  1044. using Microsoft.VisualStudio.TestTools.UnitTesting;
  1045. using Microsoft.Research.SEAL;
  1046. using System.Collections.Generic;
  1047. +using System;
  1048. namespace SEALNETTest
  1049. {
  1050. @@ -35,6 +36,79 @@ namespace SEALNETTest
  1051. keygen.GenerateEvaluationKeys(2, 2, evk);
  1052. Assert.AreEqual(evk.HashBlock, parms.HashBlock);
  1053. Assert.AreEqual(60, evk.Key(2)[0].Size);
  1054. +
  1055. + var galks = new GaloisKeys();
  1056. + keygen.GenerateGaloisKeys(60, galks);
  1057. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1058. + Assert.AreEqual(2, galks.Key(3)[0].Size);
  1059. + Assert.AreEqual(10, galks.Size);
  1060. +
  1061. + keygen.GenerateGaloisKeys(30, galks);
  1062. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1063. + Assert.AreEqual(4, galks.Key(3)[0].Size);
  1064. + Assert.AreEqual(10, galks.Size);
  1065. +
  1066. + keygen.GenerateGaloisKeys(2, galks);
  1067. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1068. + Assert.AreEqual(60, galks.Key(3)[0].Size);
  1069. + Assert.AreEqual(10, galks.Size);
  1070. +
  1071. + keygen.GenerateGaloisKeys(60, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1072. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1073. + Assert.IsTrue(galks.HasKey(1));
  1074. + Assert.IsTrue(galks.HasKey(3));
  1075. + Assert.IsTrue(galks.HasKey(5));
  1076. + Assert.IsTrue(galks.HasKey(7));
  1077. + Assert.IsFalse(galks.HasKey(9));
  1078. + Assert.IsFalse(galks.HasKey(127));
  1079. + Assert.AreEqual(2, galks.Key(1)[0].Size);
  1080. + Assert.AreEqual(2, galks.Key(3)[0].Size);
  1081. + Assert.AreEqual(2, galks.Key(5)[0].Size);
  1082. + Assert.AreEqual(2, galks.Key(7)[0].Size);
  1083. + Assert.AreEqual(4, galks.Size);
  1084. +
  1085. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1086. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1087. + Assert.IsTrue(galks.HasKey(1));
  1088. + Assert.IsTrue(galks.HasKey(3));
  1089. + Assert.IsTrue(galks.HasKey(5));
  1090. + Assert.IsTrue(galks.HasKey(7));
  1091. + Assert.IsFalse(galks.HasKey(9));
  1092. + Assert.IsFalse(galks.HasKey(127));
  1093. + Assert.AreEqual(4, galks.Key(1)[0].Size);
  1094. + Assert.AreEqual(4, galks.Key(3)[0].Size);
  1095. + Assert.AreEqual(4, galks.Key(5)[0].Size);
  1096. + Assert.AreEqual(4, galks.Key(7)[0].Size);
  1097. + Assert.AreEqual(4, galks.Size);
  1098. +
  1099. + keygen.GenerateGaloisKeys(2, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1100. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1101. + Assert.IsTrue(galks.HasKey(1));
  1102. + Assert.IsTrue(galks.HasKey(3));
  1103. + Assert.IsTrue(galks.HasKey(5));
  1104. + Assert.IsTrue(galks.HasKey(7));
  1105. + Assert.IsFalse(galks.HasKey(9));
  1106. + Assert.IsFalse(galks.HasKey(127));
  1107. + Assert.AreEqual(60, galks.Key(1)[0].Size);
  1108. + Assert.AreEqual(60, galks.Key(3)[0].Size);
  1109. + Assert.AreEqual(60, galks.Key(5)[0].Size);
  1110. + Assert.AreEqual(60, galks.Key(7)[0].Size);
  1111. + Assert.AreEqual(4, galks.Size);
  1112. +
  1113. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 1 }, galks);
  1114. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1115. + Assert.IsTrue(galks.HasKey(1));
  1116. + Assert.IsFalse(galks.HasKey(3));
  1117. + Assert.IsFalse(galks.HasKey(127));
  1118. + Assert.AreEqual(4, galks.Key(1)[0].Size);
  1119. + Assert.AreEqual(1, galks.Size);
  1120. +
  1121. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 127 }, galks);
  1122. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1123. + Assert.IsFalse(galks.HasKey(1));
  1124. + Assert.IsTrue(galks.HasKey(127));
  1125. + Assert.AreEqual(4, galks.Key(127)[0].Size);
  1126. + Assert.AreEqual(1, galks.Size);
  1127. }
  1128. {
  1129. parms.NoiseStandardDeviation = 3.19;
  1130. @@ -61,6 +135,79 @@ namespace SEALNETTest
  1131. keygen.GenerateEvaluationKeys(4, 1, evk);
  1132. Assert.AreEqual(evk.HashBlock, parms.HashBlock);
  1133. Assert.AreEqual(30, evk.Key(2)[0].Size);
  1134. +
  1135. + var galks = new GaloisKeys();
  1136. + keygen.GenerateGaloisKeys(60, galks);
  1137. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1138. + Assert.AreEqual(2, galks.Key(3)[0].Size);
  1139. + Assert.AreEqual(14, galks.Size);
  1140. +
  1141. + keygen.GenerateGaloisKeys(30, galks);
  1142. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1143. + Assert.AreEqual(4, galks.Key(3)[0].Size);
  1144. + Assert.AreEqual(14, galks.Size);
  1145. +
  1146. + keygen.GenerateGaloisKeys(2, galks);
  1147. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1148. + Assert.AreEqual(60, galks.Key(3)[0].Size);
  1149. + Assert.AreEqual(14, galks.Size);
  1150. +
  1151. + keygen.GenerateGaloisKeys(60, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1152. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1153. + Assert.IsTrue(galks.HasKey(1));
  1154. + Assert.IsTrue(galks.HasKey(3));
  1155. + Assert.IsTrue(galks.HasKey(5));
  1156. + Assert.IsTrue(galks.HasKey(7));
  1157. + Assert.IsFalse(galks.HasKey(9));
  1158. + Assert.IsFalse(galks.HasKey(511));
  1159. + Assert.AreEqual(2, galks.Key(1)[0].Size);
  1160. + Assert.AreEqual(2, galks.Key(3)[0].Size);
  1161. + Assert.AreEqual(2, galks.Key(5)[0].Size);
  1162. + Assert.AreEqual(2, galks.Key(7)[0].Size);
  1163. + Assert.AreEqual(4, galks.Size);
  1164. +
  1165. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1166. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1167. + Assert.IsTrue(galks.HasKey(1));
  1168. + Assert.IsTrue(galks.HasKey(3));
  1169. + Assert.IsTrue(galks.HasKey(5));
  1170. + Assert.IsTrue(galks.HasKey(7));
  1171. + Assert.IsFalse(galks.HasKey(9));
  1172. + Assert.IsFalse(galks.HasKey(511));
  1173. + Assert.AreEqual(4, galks.Key(1)[0].Size);
  1174. + Assert.AreEqual(4, galks.Key(3)[0].Size);
  1175. + Assert.AreEqual(4, galks.Key(5)[0].Size);
  1176. + Assert.AreEqual(4, galks.Key(7)[0].Size);
  1177. + Assert.AreEqual(4, galks.Size);
  1178. +
  1179. + keygen.GenerateGaloisKeys(2, new List<UInt64> { 1, 3, 5, 7 }, galks);
  1180. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1181. + Assert.IsTrue(galks.HasKey(1));
  1182. + Assert.IsTrue(galks.HasKey(3));
  1183. + Assert.IsTrue(galks.HasKey(5));
  1184. + Assert.IsTrue(galks.HasKey(7));
  1185. + Assert.IsFalse(galks.HasKey(9));
  1186. + Assert.IsFalse(galks.HasKey(511));
  1187. + Assert.AreEqual(60, galks.Key(1)[0].Size);
  1188. + Assert.AreEqual(60, galks.Key(3)[0].Size);
  1189. + Assert.AreEqual(60, galks.Key(5)[0].Size);
  1190. + Assert.AreEqual(60, galks.Key(7)[0].Size);
  1191. + Assert.AreEqual(4, galks.Size);
  1192. +
  1193. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 1 }, galks);
  1194. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1195. + Assert.IsTrue(galks.HasKey(1));
  1196. + Assert.IsFalse(galks.HasKey(3));
  1197. + Assert.IsFalse(galks.HasKey(511));
  1198. + Assert.AreEqual(4, galks.Key(1)[0].Size);
  1199. + Assert.AreEqual(1, galks.Size);
  1200. +
  1201. + keygen.GenerateGaloisKeys(30, new List<UInt64> { 511 }, galks);
  1202. + Assert.AreEqual(galks.HashBlock, parms.HashBlock);
  1203. + Assert.IsFalse(galks.HasKey(1));
  1204. + Assert.IsTrue(galks.HasKey(511));
  1205. + Assert.AreEqual(4, galks.Key(511)[0].Size);
  1206. + Assert.AreEqual(1, galks.Size);
  1207. }
  1208. }
  1209. }
  1210. diff --git a/SEALTest/evaluator.cpp b/SEALTest/evaluator.cpp
  1211. index 51e083a..edde078 100644
  1212. --- a/SEALTest/evaluator.cpp
  1213. +++ b/SEALTest/evaluator.cpp
  1214. @@ -964,6 +964,85 @@ namespace SEALTest
  1215. Assert::IsTrue(encrypted.hash_block() == parms.hash_block());
  1216. }
  1217. + TEST_METHOD(FVEncryptApplyGaloisDecrypt)
  1218. + {
  1219. + EncryptionParameters parms;
  1220. + SmallModulus plain_modulus(257);
  1221. + BigPoly poly_modulus("1x^8 + 1");
  1222. + parms.set_poly_modulus(poly_modulus);
  1223. + parms.set_plain_modulus(plain_modulus);
  1224. + parms.set_coeff_modulus({ small_mods_40bit(0), small_mods_40bit(1) });
  1225. + SEALContext context(parms);
  1226. + KeyGenerator keygen(context);
  1227. + GaloisKeys glk;
  1228. + keygen.generate_galois_keys(24, { 1, 3, 5, 15 }, glk);
  1229. +
  1230. + Encryptor encryptor(context, keygen.public_key());
  1231. + Evaluator evaluator(context);
  1232. + Decryptor decryptor(context, keygen.secret_key());
  1233. +
  1234. + Plaintext plain("1");
  1235. + Ciphertext encrypted;
  1236. + encryptor.encrypt(plain, encrypted);
  1237. + evaluator.apply_galois(encrypted, 1, glk);
  1238. + decryptor.decrypt(encrypted, plain);
  1239. + Assert::IsTrue("1" == plain.to_string());
  1240. + evaluator.apply_galois(encrypted, 3, glk);
  1241. + decryptor.decrypt(encrypted, plain);
  1242. + Assert::IsTrue("1" == plain.to_string());
  1243. + evaluator.apply_galois(encrypted, 5, glk);
  1244. + decryptor.decrypt(encrypted, plain);
  1245. + Assert::IsTrue("1" == plain.to_string());
  1246. + evaluator.apply_galois(encrypted, 15, glk);
  1247. + decryptor.decrypt(encrypted, plain);
  1248. + Assert::IsTrue("1" == plain.to_string());
  1249. +
  1250. + plain = "1x^1";
  1251. + encryptor.encrypt(plain, encrypted);
  1252. + evaluator.apply_galois(encrypted, 1, glk);
  1253. + decryptor.decrypt(encrypted, plain);
  1254. + Assert::IsTrue("1x^1" == plain.to_string());
  1255. + evaluator.apply_galois(encrypted, 3, glk);
  1256. + decryptor.decrypt(encrypted, plain);
  1257. + Assert::IsTrue("1x^3" == plain.to_string());
  1258. + evaluator.apply_galois(encrypted, 5, glk);
  1259. + decryptor.decrypt(encrypted, plain);
  1260. + Assert::IsTrue("100x^7" == plain.to_string());
  1261. + evaluator.apply_galois(encrypted, 15, glk);
  1262. + decryptor.decrypt(encrypted, plain);
  1263. + Assert::IsTrue("1x^1" == plain.to_string());
  1264. +
  1265. + plain = "1x^2";
  1266. + encryptor.encrypt(plain, encrypted);
  1267. + evaluator.apply_galois(encrypted, 1, glk);
  1268. + decryptor.decrypt(encrypted, plain);
  1269. + Assert::IsTrue("1x^2" == plain.to_string());
  1270. + evaluator.apply_galois(encrypted, 3, glk);
  1271. + decryptor.decrypt(encrypted, plain);
  1272. + Assert::IsTrue("1x^6" == plain.to_string());
  1273. + evaluator.apply_galois(encrypted, 5, glk);
  1274. + decryptor.decrypt(encrypted, plain);
  1275. + Assert::IsTrue("100x^6" == plain.to_string());
  1276. + evaluator.apply_galois(encrypted, 15, glk);
  1277. + decryptor.decrypt(encrypted, plain);
  1278. + Assert::IsTrue("1x^2" == plain.to_string());
  1279. +
  1280. + plain = "1x^3 + 2x^2 + 1x^1 + 1";
  1281. + encryptor.encrypt(plain, encrypted);
  1282. + evaluator.apply_galois(encrypted, 1, glk);
  1283. + decryptor.decrypt(encrypted, plain);
  1284. + Assert::IsTrue("1x^3 + 2x^2 + 1x^1 + 1" == plain.to_string());
  1285. + evaluator.apply_galois(encrypted, 3, glk);
  1286. + decryptor.decrypt(encrypted, plain);
  1287. + Assert::IsTrue("2x^6 + 1x^3 + 100x^1 + 1" == plain.to_string());
  1288. + evaluator.apply_galois(encrypted, 5, glk);
  1289. + decryptor.decrypt(encrypted, plain);
  1290. + Assert::IsTrue("100x^7 + FFx^6 + 100x^5 + 1" == plain.to_string());
  1291. + evaluator.apply_galois(encrypted, 15, glk);
  1292. + decryptor.decrypt(encrypted, plain);
  1293. + Assert::IsTrue("1x^3 + 2x^2 + 1x^1 + 1" == plain.to_string());
  1294. + }
  1295. +
  1296. TEST_METHOD(FVEncryptRotateMatrixDecrypt)
  1297. {
  1298. EncryptionParameters parms;
  1299. diff --git a/SEALTest/keygenerator.cpp b/SEALTest/keygenerator.cpp
  1300. index b4e15b3..a64b1af 100644
  1301. --- a/SEALTest/keygenerator.cpp
  1302. +++ b/SEALTest/keygenerator.cpp
  1303. @@ -68,6 +68,79 @@ namespace SEALTest
  1304. }
  1305. }
  1306. }
  1307. +
  1308. + GaloisKeys galks;
  1309. + keygen.generate_galois_keys(60, galks);
  1310. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1311. + Assert::AreEqual(2, galks.key(3)[0].size());
  1312. + Assert::AreEqual(10, galks.size());
  1313. +
  1314. + keygen.generate_galois_keys(30, galks);
  1315. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1316. + Assert::AreEqual(4, galks.key(3)[0].size());
  1317. + Assert::AreEqual(10, galks.size());
  1318. +
  1319. + keygen.generate_galois_keys(2, galks);
  1320. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1321. + Assert::AreEqual(60, galks.key(3)[0].size());
  1322. + Assert::AreEqual(10, galks.size());
  1323. +
  1324. + keygen.generate_galois_keys(60, { 1, 3, 5, 7 }, galks);
  1325. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1326. + Assert::IsTrue(galks.has_key(1));
  1327. + Assert::IsTrue(galks.has_key(3));
  1328. + Assert::IsTrue(galks.has_key(5));
  1329. + Assert::IsTrue(galks.has_key(7));
  1330. + Assert::IsFalse(galks.has_key(9));
  1331. + Assert::IsFalse(galks.has_key(127));
  1332. + Assert::AreEqual(2, galks.key(1)[0].size());
  1333. + Assert::AreEqual(2, galks.key(3)[0].size());
  1334. + Assert::AreEqual(2, galks.key(5)[0].size());
  1335. + Assert::AreEqual(2, galks.key(7)[0].size());
  1336. + Assert::AreEqual(4, galks.size());
  1337. +
  1338. + keygen.generate_galois_keys(30, { 1, 3, 5, 7 }, galks);
  1339. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1340. + Assert::IsTrue(galks.has_key(1));
  1341. + Assert::IsTrue(galks.has_key(3));
  1342. + Assert::IsTrue(galks.has_key(5));
  1343. + Assert::IsTrue(galks.has_key(7));
  1344. + Assert::IsFalse(galks.has_key(9));
  1345. + Assert::IsFalse(galks.has_key(127));
  1346. + Assert::AreEqual(4, galks.key(1)[0].size());
  1347. + Assert::AreEqual(4, galks.key(3)[0].size());
  1348. + Assert::AreEqual(4, galks.key(5)[0].size());
  1349. + Assert::AreEqual(4, galks.key(7)[0].size());
  1350. + Assert::AreEqual(4, galks.size());
  1351. +
  1352. + keygen.generate_galois_keys(2, { 1, 3, 5, 7 }, galks);
  1353. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1354. + Assert::IsTrue(galks.has_key(1));
  1355. + Assert::IsTrue(galks.has_key(3));
  1356. + Assert::IsTrue(galks.has_key(5));
  1357. + Assert::IsTrue(galks.has_key(7));
  1358. + Assert::IsFalse(galks.has_key(9));
  1359. + Assert::IsFalse(galks.has_key(127));
  1360. + Assert::AreEqual(60, galks.key(1)[0].size());
  1361. + Assert::AreEqual(60, galks.key(3)[0].size());
  1362. + Assert::AreEqual(60, galks.key(5)[0].size());
  1363. + Assert::AreEqual(60, galks.key(7)[0].size());
  1364. + Assert::AreEqual(4, galks.size());
  1365. +
  1366. + keygen.generate_galois_keys(30, { 1 }, galks);
  1367. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1368. + Assert::IsTrue(galks.has_key(1));
  1369. + Assert::IsFalse(galks.has_key(3));
  1370. + Assert::IsFalse(galks.has_key(127));
  1371. + Assert::AreEqual(4, galks.key(1)[0].size());
  1372. + Assert::AreEqual(1, galks.size());
  1373. +
  1374. + keygen.generate_galois_keys(30, { 127 }, galks);
  1375. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1376. + Assert::IsFalse(galks.has_key(1));
  1377. + Assert::IsTrue(galks.has_key(127));
  1378. + Assert::AreEqual(4, galks.key(127)[0].size());
  1379. + Assert::AreEqual(1, galks.size());
  1380. }
  1381. {
  1382. parms.set_noise_standard_deviation(3.19);
  1383. @@ -121,6 +194,79 @@ namespace SEALTest
  1384. }
  1385. }
  1386. }
  1387. +
  1388. + GaloisKeys galks;
  1389. + keygen.generate_galois_keys(60, galks);
  1390. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1391. + Assert::AreEqual(2, galks.key(3)[0].size());
  1392. + Assert::AreEqual(14, galks.size());
  1393. +
  1394. + keygen.generate_galois_keys(30, galks);
  1395. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1396. + Assert::AreEqual(4, galks.key(3)[0].size());
  1397. + Assert::AreEqual(14, galks.size());
  1398. +
  1399. + keygen.generate_galois_keys(2, galks);
  1400. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1401. + Assert::AreEqual(60, galks.key(3)[0].size());
  1402. + Assert::AreEqual(14, galks.size());
  1403. +
  1404. + keygen.generate_galois_keys(60, { 1, 3, 5, 7 }, galks);
  1405. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1406. + Assert::IsTrue(galks.has_key(1));
  1407. + Assert::IsTrue(galks.has_key(3));
  1408. + Assert::IsTrue(galks.has_key(5));
  1409. + Assert::IsTrue(galks.has_key(7));
  1410. + Assert::IsFalse(galks.has_key(9));
  1411. + Assert::IsFalse(galks.has_key(511));
  1412. + Assert::AreEqual(2, galks.key(1)[0].size());
  1413. + Assert::AreEqual(2, galks.key(3)[0].size());
  1414. + Assert::AreEqual(2, galks.key(5)[0].size());
  1415. + Assert::AreEqual(2, galks.key(7)[0].size());
  1416. + Assert::AreEqual(4, galks.size());
  1417. +
  1418. + keygen.generate_galois_keys(30, { 1, 3, 5, 7 }, galks);
  1419. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1420. + Assert::IsTrue(galks.has_key(1));
  1421. + Assert::IsTrue(galks.has_key(3));
  1422. + Assert::IsTrue(galks.has_key(5));
  1423. + Assert::IsTrue(galks.has_key(7));
  1424. + Assert::IsFalse(galks.has_key(9));
  1425. + Assert::IsFalse(galks.has_key(511));
  1426. + Assert::AreEqual(4, galks.key(1)[0].size());
  1427. + Assert::AreEqual(4, galks.key(3)[0].size());
  1428. + Assert::AreEqual(4, galks.key(5)[0].size());
  1429. + Assert::AreEqual(4, galks.key(7)[0].size());
  1430. + Assert::AreEqual(4, galks.size());
  1431. +
  1432. + keygen.generate_galois_keys(2, { 1, 3, 5, 7 }, galks);
  1433. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1434. + Assert::IsTrue(galks.has_key(1));
  1435. + Assert::IsTrue(galks.has_key(3));
  1436. + Assert::IsTrue(galks.has_key(5));
  1437. + Assert::IsTrue(galks.has_key(7));
  1438. + Assert::IsFalse(galks.has_key(9));
  1439. + Assert::IsFalse(galks.has_key(511));
  1440. + Assert::AreEqual(60, galks.key(1)[0].size());
  1441. + Assert::AreEqual(60, galks.key(3)[0].size());
  1442. + Assert::AreEqual(60, galks.key(5)[0].size());
  1443. + Assert::AreEqual(60, galks.key(7)[0].size());
  1444. + Assert::AreEqual(4, galks.size());
  1445. +
  1446. + keygen.generate_galois_keys(30, { 1 }, galks);
  1447. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1448. + Assert::IsTrue(galks.has_key(1));
  1449. + Assert::IsFalse(galks.has_key(3));
  1450. + Assert::IsFalse(galks.has_key(511));
  1451. + Assert::AreEqual(4, galks.key(1)[0].size());
  1452. + Assert::AreEqual(1, galks.size());
  1453. +
  1454. + keygen.generate_galois_keys(30, { 511 }, galks);
  1455. + Assert::IsTrue(galks.hash_block() == parms.hash_block());
  1456. + Assert::IsFalse(galks.has_key(1));
  1457. + Assert::IsTrue(galks.has_key(511));
  1458. + Assert::AreEqual(4, galks.key(511)[0].size());
  1459. + Assert::AreEqual(1, galks.size());
  1460. }
  1461. }
  1462. };
  1463. --
  1464. 2.14.1
  1465. From 1fdfa03edbb50835beedefe26d74f17918c4f1e1 Mon Sep 17 00:00:00 2001
  1466. From: Kim Laine <kim.laine@microsoft.com>
  1467. Date: Mon, 4 Dec 2017 17:31:18 -0800
  1468. Subject: [PATCH 2/3] Added negacyclic_shift_poly_coeffmod
  1469. ---
  1470. SEAL/seal/util/polyarithsmallmod.cpp | 28 ++++++---
  1471. SEAL/seal/util/polyarithsmallmod.h | 54 +++++++++++++++++-
  1472. SEALTest/util/polyarithsmallmod.cpp | 108 +++++++++++++++++++++++++++++++++++
  1473. 3 files changed, 181 insertions(+), 9 deletions(-)
  1474. diff --git a/SEAL/seal/util/polyarithsmallmod.cpp b/SEAL/seal/util/polyarithsmallmod.cpp
  1475. index 5bfeede..4719348 100644
  1476. --- a/SEAL/seal/util/polyarithsmallmod.cpp
  1477. +++ b/SEAL/seal/util/polyarithsmallmod.cpp
  1478. @@ -407,16 +407,30 @@ namespace seal
  1479. }
  1480. }
  1481. - uint64_t poly_infty_norm_coeffmod(const std::uint64_t *poly, int poly_coeff_count, const SmallModulus &modulus)
  1482. + uint64_t poly_infty_norm_coeffmod(const std::uint64_t *operand, int coeff_count, const SmallModulus &modulus)
  1483. {
  1484. +#ifdef SEAL_DEBUG
  1485. + if (operand == nullptr && coeff_count > 0)
  1486. + {
  1487. + throw invalid_argument("operand");
  1488. + }
  1489. + if (coeff_count < 0)
  1490. + {
  1491. + throw invalid_argument("coeff_count");
  1492. + }
  1493. + if (modulus.is_zero())
  1494. + {
  1495. + throw invalid_argument("modulus");
  1496. + }
  1497. +#endif
  1498. // Construct negative threshold (first negative modulus value) to compute absolute values of coeffs.
  1499. uint64_t modulus_neg_threshold = (modulus.value() + 1) >> 1;
  1500. // Mod out the poly coefficients and choose a symmetric representative from [-modulus,modulus). Keep track of the max.
  1501. uint64_t result = 0;
  1502. - for (int coeff_index = 0; coeff_index < poly_coeff_count; coeff_index++)
  1503. + for (int coeff_index = 0; coeff_index < coeff_count; coeff_index++)
  1504. {
  1505. - uint64_t poly_coeff = poly[coeff_index] % modulus.value();
  1506. + uint64_t poly_coeff = operand[coeff_index] % modulus.value();
  1507. if (poly_coeff >= modulus_neg_threshold)
  1508. {
  1509. poly_coeff = modulus.value() - poly_coeff;
  1510. @@ -594,14 +608,14 @@ namespace seal
  1511. return true;
  1512. }
  1513. - void exponentiate_poly_polymod_coeffmod(const uint64_t *poly, const uint64_t *exponent, int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus, uint64_t *result, MemoryPool &pool)
  1514. + void exponentiate_poly_polymod_coeffmod(const uint64_t *operand, const uint64_t *exponent, int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus, uint64_t *result, MemoryPool &pool)
  1515. {
  1516. int poly_modulus_coeff_count = poly_modulus.coeff_count();
  1517. #ifdef SEAL_DEBUG
  1518. int poly_modulus_coeff_uint64_count = poly_modulus.coeff_uint64_count();
  1519. - if (poly == nullptr)
  1520. + if (operand == nullptr)
  1521. {
  1522. - throw invalid_argument("poly");
  1523. + throw invalid_argument("operand");
  1524. }
  1525. if (exponent == nullptr)
  1526. {
  1527. @@ -631,7 +645,7 @@ namespace seal
  1528. return;
  1529. }
  1530. - modulo_poly(poly, poly_modulus_coeff_count, poly_modulus, modulus, result, pool);
  1531. + modulo_poly(operand, poly_modulus_coeff_count, poly_modulus, modulus, result, pool);
  1532. if (is_equal_uint(exponent, exponent_uint64_count, 1))
  1533. {
  1534. diff --git a/SEAL/seal/util/polyarithsmallmod.h b/SEAL/seal/util/polyarithsmallmod.h
  1535. index d660439..f081184 100644
  1536. --- a/SEAL/seal/util/polyarithsmallmod.h
  1537. +++ b/SEAL/seal/util/polyarithsmallmod.h
  1538. @@ -556,14 +556,64 @@ namespace seal
  1539. modulo_poly_inplace(result, result_coeff_count, poly_modulus, modulus);
  1540. }
  1541. - std::uint64_t poly_infty_norm_coeffmod(const std::uint64_t *poly, int poly_coeff_count,
  1542. + std::uint64_t poly_infty_norm_coeffmod(const std::uint64_t *operand, int coeff_count,
  1543. const SmallModulus &modulus);
  1544. bool try_invert_poly_coeffmod(const std::uint64_t *operand, const std::uint64_t *poly_modulus,
  1545. int coeff_count, const SmallModulus &modulus, std::uint64_t *result, MemoryPool &pool);
  1546. - void exponentiate_poly_polymod_coeffmod(const std::uint64_t *poly, const std::uint64_t *exponent,
  1547. + void exponentiate_poly_polymod_coeffmod(const std::uint64_t *operand, const std::uint64_t *exponent,
  1548. int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus,
  1549. std::uint64_t *result, MemoryPool &pool);
  1550. +
  1551. + inline void negacyclic_shift_poly_coeffmod(const std::uint64_t *operand, int coeff_count, int shift,
  1552. + const SmallModulus &modulus, std::uint64_t *result)
  1553. + {
  1554. +#ifdef SEAL_DEBUG
  1555. + if (operand == nullptr && coeff_count > 0)
  1556. + {
  1557. + throw std::invalid_argument("operand");
  1558. + }
  1559. + if (result == nullptr && coeff_count > 0)
  1560. + {
  1561. + throw std::invalid_argument("result");
  1562. + }
  1563. + if (operand == result && coeff_count > 0)
  1564. + {
  1565. + throw std::invalid_argument("operand cannot point to the same location as result");
  1566. + }
  1567. + if (coeff_count < 0)
  1568. + {
  1569. + throw std::invalid_argument("coeff_count");
  1570. + }
  1571. + if (modulus.is_zero())
  1572. + {
  1573. + throw std::invalid_argument("modulus");
  1574. + }
  1575. + if (shift < 0)
  1576. + {
  1577. + throw std::invalid_argument("shift");
  1578. + }
  1579. + if (util::get_power_of_two(static_cast<std::uint64_t>(coeff_count)) < 0)
  1580. + {
  1581. + throw std::invalid_argument("coeff_count");
  1582. + }
  1583. +#endif
  1584. + std::uint64_t index_raw = shift;
  1585. + std::uint64_t coeff_count_mod_mask = static_cast<std::uint64_t>(coeff_count) - 1;
  1586. + std::uint64_t index;
  1587. + for (int i = 0; i < coeff_count; i++, operand++, index_raw++)
  1588. + {
  1589. + index = index_raw & coeff_count_mod_mask;
  1590. + if (!(index_raw & static_cast<std::uint64_t>(coeff_count)) || (*operand == 0))
  1591. + {
  1592. + result[index] = *operand;
  1593. + }
  1594. + else
  1595. + {
  1596. + result[index] = modulus.value() - *operand;
  1597. + }
  1598. + }
  1599. + }
  1600. }
  1601. }
  1602. diff --git a/SEALTest/util/polyarithsmallmod.cpp b/SEALTest/util/polyarithsmallmod.cpp
  1603. index e917034..93df00b 100644
  1604. --- a/SEALTest/util/polyarithsmallmod.cpp
  1605. +++ b/SEALTest/util/polyarithsmallmod.cpp
  1606. @@ -470,6 +470,114 @@ namespace SEALTest
  1607. Assert::AreEqual(9ULL, result[1]);
  1608. Assert::AreEqual(0ULL, result[2]);
  1609. }
  1610. +
  1611. + TEST_METHOD(NegacyclicShiftPolyCoeffSmallMod)
  1612. + {
  1613. + MemoryPool &pool = *global_variables::global_memory_pool;
  1614. + Pointer poly(allocate_zero_poly(4, 1, pool));
  1615. + Pointer result(allocate_zero_poly(4, 1, pool));
  1616. +
  1617. + SmallModulus mod(10);
  1618. + int coeff_count = 4;
  1619. +
  1620. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
  1621. + Assert::AreEqual(0ULL, result[0]);
  1622. + Assert::AreEqual(0ULL, result[1]);
  1623. + Assert::AreEqual(0ULL, result[2]);
  1624. + Assert::AreEqual(0ULL, result[3]);
  1625. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
  1626. + Assert::AreEqual(0ULL, result[0]);
  1627. + Assert::AreEqual(0ULL, result[1]);
  1628. + Assert::AreEqual(0ULL, result[2]);
  1629. + Assert::AreEqual(0ULL, result[3]);
  1630. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
  1631. + Assert::AreEqual(0ULL, result[0]);
  1632. + Assert::AreEqual(0ULL, result[1]);
  1633. + Assert::AreEqual(0ULL, result[2]);
  1634. + Assert::AreEqual(0ULL, result[3]);
  1635. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
  1636. + Assert::AreEqual(0ULL, result[0]);
  1637. + Assert::AreEqual(0ULL, result[1]);
  1638. + Assert::AreEqual(0ULL, result[2]);
  1639. + Assert::AreEqual(0ULL, result[3]);
  1640. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
  1641. + Assert::AreEqual(0ULL, result[0]);
  1642. + Assert::AreEqual(0ULL, result[1]);
  1643. + Assert::AreEqual(0ULL, result[2]);
  1644. + Assert::AreEqual(0ULL, result[3]);
  1645. +
  1646. + poly[0] = 1;
  1647. + poly[1] = 2;
  1648. + poly[2] = 3;
  1649. + poly[3] = 4;
  1650. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
  1651. + Assert::AreEqual(1ULL, result[0]);
  1652. + Assert::AreEqual(2ULL, result[1]);
  1653. + Assert::AreEqual(3ULL, result[2]);
  1654. + Assert::AreEqual(4ULL, result[3]);
  1655. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
  1656. + Assert::AreEqual(6ULL, result[0]);
  1657. + Assert::AreEqual(1ULL, result[1]);
  1658. + Assert::AreEqual(2ULL, result[2]);
  1659. + Assert::AreEqual(3ULL, result[3]);
  1660. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
  1661. + Assert::AreEqual(9ULL, result[0]);
  1662. + Assert::AreEqual(8ULL, result[1]);
  1663. + Assert::AreEqual(7ULL, result[2]);
  1664. + Assert::AreEqual(6ULL, result[3]);
  1665. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
  1666. + Assert::AreEqual(4ULL, result[0]);
  1667. + Assert::AreEqual(9ULL, result[1]);
  1668. + Assert::AreEqual(8ULL, result[2]);
  1669. + Assert::AreEqual(7ULL, result[3]);
  1670. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
  1671. + Assert::AreEqual(1ULL, result[0]);
  1672. + Assert::AreEqual(2ULL, result[1]);
  1673. + Assert::AreEqual(3ULL, result[2]);
  1674. + Assert::AreEqual(4ULL, result[3]);
  1675. +
  1676. + poly[0] = 1;
  1677. + poly[1] = 2;
  1678. + poly[2] = 0;
  1679. + poly[3] = 4;
  1680. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
  1681. + Assert::AreEqual(1ULL, result[0]);
  1682. + Assert::AreEqual(2ULL, result[1]);
  1683. + Assert::AreEqual(0ULL, result[2]);
  1684. + Assert::AreEqual(4ULL, result[3]);
  1685. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
  1686. + Assert::AreEqual(6ULL, result[0]);
  1687. + Assert::AreEqual(1ULL, result[1]);
  1688. + Assert::AreEqual(2ULL, result[2]);
  1689. + Assert::AreEqual(0ULL, result[3]);
  1690. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
  1691. + Assert::AreEqual(9ULL, result[0]);
  1692. + Assert::AreEqual(8ULL, result[1]);
  1693. + Assert::AreEqual(0ULL, result[2]);
  1694. + Assert::AreEqual(6ULL, result[3]);
  1695. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
  1696. + Assert::AreEqual(4ULL, result[0]);
  1697. + Assert::AreEqual(9ULL, result[1]);
  1698. + Assert::AreEqual(8ULL, result[2]);
  1699. + Assert::AreEqual(0ULL, result[3]);
  1700. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
  1701. + Assert::AreEqual(1ULL, result[0]);
  1702. + Assert::AreEqual(2ULL, result[1]);
  1703. + Assert::AreEqual(0ULL, result[2]);
  1704. + Assert::AreEqual(4ULL, result[3]);
  1705. +
  1706. + poly[0] = 1;
  1707. + poly[1] = 2;
  1708. + poly[2] = 3;
  1709. + poly[3] = 4;
  1710. + coeff_count = 2;
  1711. + negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
  1712. + negacyclic_shift_poly_coeffmod(poly.get() + 2, coeff_count, 1, mod, result.get() + 2);
  1713. + Assert::AreEqual(8ULL, result[0]);
  1714. + Assert::AreEqual(1ULL, result[1]);
  1715. + Assert::AreEqual(6ULL, result[2]);
  1716. + Assert::AreEqual(3ULL, result[3]);
  1717. + }
  1718. };
  1719. }
  1720. }
  1721. \ No newline at end of file
  1722. --
  1723. 2.14.1
  1724. From 9c5a16fb3e8ffc5bae69ba175867d89b774091c5 Mon Sep 17 00:00:00 2001
  1725. From: Sebastian Angel <sebs@cs.utexas.edu>
  1726. Date: Tue, 15 May 2018 00:11:24 +0000
  1727. Subject: [PATCH 3/3] enable mutable
  1728. ---
  1729. SEAL/seal/util/defines.h | 4 ++--
  1730. 1 file changed, 2 insertions(+), 2 deletions(-)
  1731. diff --git a/SEAL/seal/util/defines.h b/SEAL/seal/util/defines.h
  1732. index 20c0bf2..4e1b2fb 100644
  1733. --- a/SEAL/seal/util/defines.h
  1734. +++ b/SEAL/seal/util/defines.h
  1735. @@ -19,7 +19,7 @@
  1736. // parameter compatibility checks pass in cases where they normally
  1737. // should not pass. Please note that it is extremely easy to break
  1738. // things by doing this, and the consequences can be unexpected.
  1739. -//#define SEAL_EXPOSE_MUTABLE_HASH_BLOCK
  1740. +#define SEAL_EXPOSE_MUTABLE_HASH_BLOCK
  1741. // Allow ciphertext data to be directly modified by exposing the
  1742. // functions seal::Ciphertext::mutable_pointer(int) and
  1743. @@ -28,7 +28,7 @@
  1744. // way of mutating ciphertext data is by allocating memory manually,
  1745. // and using aliased ciphertexts pointing to the allocated memory,
  1746. // which can then be mutated freely.
  1747. -//#define SEAL_EXPOSE_MUTABLE_CIPHERTEXT
  1748. +#define SEAL_EXPOSE_MUTABLE_CIPHERTEXT
  1749. // For security reasons one should never throw when decoding fails due
  1750. // to overflow, but in some cases this might help in diagnosing problems.
  1751. --
  1752. 2.14.1