scheme-switching.py 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. from openfhe import *
  2. from math import *
  3. def main():
  4. SwitchCKKSToFHEW()
  5. SwitchFHEWtoCKKS()
  6. FloorViaSchemeSwitching()
  7. # FuncViaSchemeSwitching()
  8. # PolyViaSchemeSwitching()
  9. ComparisonViaSchemeSwitching()
  10. ArgminViaSchemeSwitching()
  11. ArgminViaSchemeSwitchingAlt()
  12. #ArgminViaSchemeSwitchingUnit()
  13. #ArgminViaSchemeSwitchingAltUnit()
  14. def SwitchCKKSToFHEW():
  15. # Example of switching a packed ciphertext from CKKS to multiple FHEW ciphertexts.
  16. print("\n-----SwitchCKKSToFHEW-----\n")
  17. # Step 1: Setup CryptoContext for CKKS
  18. # Specify main parameters
  19. multDepth = 3
  20. firstModSize = 60
  21. scaleModSize = 50
  22. ringDim = 4096
  23. sl = HEStd_NotSet
  24. slBin = TOY
  25. logQ_ccLWE = 25
  26. # slots = ringDim / 2 # Uncomment for fully-packed
  27. slots = 16 # sparsely-packed
  28. batchSize = slots
  29. parameters = CCParamsCKKSRNS()
  30. parameters.SetMultiplicativeDepth(multDepth)
  31. parameters.SetFirstModSize(firstModSize)
  32. parameters.SetScalingModSize(scaleModSize)
  33. parameters.SetScalingTechnique(FIXEDMANUAL)
  34. parameters.SetSecurityLevel(sl)
  35. parameters.SetRingDim(ringDim)
  36. parameters.SetBatchSize(batchSize)
  37. cc = GenCryptoContext(parameters)
  38. # Enable the features that you wish to use
  39. cc.Enable(PKE)
  40. cc.Enable(KEYSWITCH)
  41. cc.Enable(LEVELEDSHE)
  42. cc.Enable(SCHEMESWITCH)
  43. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},")
  44. print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n")
  45. # Generate encryption keys
  46. keys = cc.KeyGen()
  47. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  48. FHEWparams = cc.EvalCKKStoFHEWSetup(sl, slBin, False, logQ_ccLWE, False, slots)
  49. ccLWE = FHEWparams[0]
  50. privateKeyFHEW = FHEWparams[1]
  51. cc.EvalCKKStoFHEWKeyGen(keys, privateKeyFHEW)
  52. print(f"FHEW scheme is using a lattice parameter {ccLWE.Getn()},")
  53. print(f"logQ {logQ_ccLWE},")
  54. print(f"and modulus q {ccLWE.Getq()}\n")
  55. # Compute the scaling factor to decrypt correctly in FHEW; the LWE mod switch is performed on the ciphertext at the last level
  56. modulus_CKKS_from = cc.GetModulusCKKS()
  57. pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision
  58. modulus_LWE = 1 << logQ_ccLWE
  59. beta = ccLWE.GetBeta()
  60. pLWE2 = modulus_LWE / (2*beta) # Large precision
  61. scFactor = cc.GetScalingFactorReal(0)
  62. # if (cc.GetScalingTechnique() == FLEXIBLEAUTOEXT):
  63. # scFactor = cc.GetScalingFactorReal(1)
  64. scale1 = modulus_CKKS_from / (scFactor * pLWE1)
  65. scale2 = modulus_CKKS_from / (scFactor * pLWE2)
  66. # Perform the precomputation for switching
  67. cc.EvalCKKStoFHEWPrecompute(scale1)
  68. # Step 3: Encoding and encryption of inputs
  69. # Inputs
  70. x1 = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
  71. x2 = [0.0, 271.1, 30000.0, pLWE2-2]
  72. encodedLength1 = len(x1)
  73. encodedLength2 = len(x2)
  74. # Encoding as plaintexts
  75. ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0)
  76. ptxt2 = cc.MakeCKKSPackedPlaintext(x2, 1, 0)
  77. # Encrypt the encoded vectors
  78. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  79. c2 = cc.Encrypt(keys.publicKey, ptxt2)
  80. # Step 4: Scheme Switching from CKKS to FHEW
  81. cTemp = cc.EvalCKKStoFHEW(c1, encodedLength1)
  82. print(f"\n---Decrypting switched ciphertext with small precision (plaintext modulus {pLWE1}) ---\n")
  83. x1Int = [round(x) % pLWE1 for x in x1]
  84. ptxt1.SetLength(encodedLength1)
  85. print(f"Input x1: {ptxt1.GetRealPackedValue()}; which rounds to {x1Int}")
  86. print("FHEW Decryption")
  87. for i in range(len(cTemp)):
  88. result = ccLWE.Decrypt(privateKeyFHEW, cTemp[i], pLWE1)
  89. print(result, end=" ")
  90. print("\n")
  91. # B: Second scheme switching case
  92. # Perform the precomputation for switching
  93. cc.EvalCKKStoFHEWPrecompute(scale2)
  94. # Transform the ciphertext from CKKS to FHEW (only for the number of inputs given)
  95. cTemp2 = cc.EvalCKKStoFHEW(c2, encodedLength2)
  96. print(f"\n---Decrypting switched ciphertext with large precision (plaintext modulus {pLWE2}) ---\n")
  97. ptxt2.SetLength(encodedLength2)
  98. print(f"Input x2: {ptxt2.GetRealPackedValue()}")
  99. print("FHEW Decryption")
  100. for i in range(len(cTemp2)):
  101. result = ccLWE.Decrypt(privateKeyFHEW, cTemp2[i], int(pLWE2))
  102. print(result, end=" ")
  103. print("\n")
  104. # C: Decompose the FHEW ciphertexts in smaller digits
  105. print(f"Decomposed values for digit size of {pLWE1}:")
  106. # Generate the bootstrapping keys (refresh and switching keys)
  107. ccLWE.BTKeyGen(privateKeyFHEW)
  108. for j in range(len(cTemp2)):
  109. # Decompose the large ciphertext into small ciphertexts that fit in q
  110. decomp = ccLWE.EvalDecomp(cTemp2[j])
  111. # Decryption
  112. p = ccLWE.GetMaxPlaintextSpace()
  113. for i in range(len(decomp)):
  114. ct = decomp[i]
  115. if i == len(decomp) - 1:
  116. p = int(pLWE2 / (pLWE1 ** floor(log(pLWE2)/log(pLWE1))))
  117. # The last digit should be up to P / p^floor(log_p(P))
  118. resultDecomp = ccLWE.Decrypt(privateKeyFHEW, ct, p)
  119. print(f"( {resultDecomp} * {pLWE1} ^ {i} )")
  120. if i != len(decomp) - 1:
  121. print("+", end=" ")
  122. print("\n")
  123. def SwitchFHEWtoCKKS():
  124. print("\n-----SwitchFHEWtoCKKS-----\n")
  125. print("Output precision is only wrt the operations in CKKS after switching back.\n")
  126. # Step 1: Setup CryptoContext for CKKS to be switched into
  127. # A. Specify main parameters
  128. scTech = FIXEDAUTO
  129. multDepth = 3 + 9 + 1
  130. # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling
  131. if scTech == FLEXIBLEAUTOEXT:
  132. multDepth += 1
  133. scaleModSize = 50
  134. ringDim = 8192
  135. sl = HEStd_NotSet # If this is not HEStd_NotSet, ensure ringDim is compatible
  136. logQ_ccLWE = 28
  137. # slots = ringDim/2; # Uncomment for fully-packed
  138. slots = 16 # sparsely-packed
  139. batchSize = slots
  140. parameters = CCParamsCKKSRNS()
  141. parameters.SetMultiplicativeDepth(multDepth)
  142. parameters.SetScalingModSize(scaleModSize)
  143. parameters.SetScalingTechnique(scTech)
  144. parameters.SetSecurityLevel(sl)
  145. parameters.SetRingDim(ringDim)
  146. parameters.SetBatchSize(batchSize)
  147. cc = GenCryptoContext(parameters)
  148. # Enable the features that you wish to use
  149. cc.Enable(PKE)
  150. cc.Enable(KEYSWITCH)
  151. cc.Enable(LEVELEDSHE)
  152. cc.Enable(ADVANCEDSHE)
  153. cc.Enable(SCHEMESWITCH)
  154. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n")
  155. # Generate encryption keys
  156. keys = cc.KeyGen()
  157. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  158. ccLWE = BinFHEContext()
  159. ccLWE.GenerateBinFHEContext(TOY, False, logQ_ccLWE, 0, GINX, False)
  160. # LWE private key
  161. lwesk = ccLWE.KeyGen()
  162. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  163. # Step 3. Precompute the necessary keys and information for switching from FHEW to CKKS
  164. cc.EvalFHEWtoCKKSSetup(ccLWE, slots, logQ_ccLWE)
  165. cc.EvalFHEWtoCKKSKeyGen(keys, lwesk)
  166. # Step 4: Encoding and encryption of inputs
  167. # For correct CKKS decryption, the messages have to be much smaller than the FHEW plaintext modulus!
  168. pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision
  169. pLWE2 = 256 # Medium precision
  170. modulus_LWE = 1 << logQ_ccLWE
  171. beta = ccLWE.GetBeta()
  172. pLWE3 = int(modulus_LWE / (2 * beta)) # Large precision
  173. x1 = [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
  174. x2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
  175. if len(x1) < slots:
  176. zeros = [0] * (slots - len(x1))
  177. x1.extend(zeros)
  178. x2.extend(zeros)
  179. # Encrypt
  180. # Encrypted nder small plaintext modulus p = 4 and ciphertext modulus:
  181. ctxtsLWE1 = [ccLWE.Encrypt(lwesk, x1[i]) for i in range(slots)]
  182. # Encrypted under larger plaintext modulus p = 16 but small ciphertext modulus:
  183. ctxtsLWE2 = [ccLWE.Encrypt(lwesk, x1[i], FRESH, pLWE1) for i in range(slots)]
  184. # Encrypted under larger plaintext modulus and large ciphertext modulus:
  185. ctxtsLWE3 = [ccLWE.Encrypt(lwesk, x2[i], FRESH, pLWE2, modulus_LWE) for i in range(slots)]
  186. # Encrypted under large plaintext modulus and large ciphertext modulus:
  187. ctxtsLWE4 = [ccLWE.Encrypt(lwesk, x2[i], FRESH, pLWE3, modulus_LWE) for i in range(slots)]
  188. # Step 5. Perform the scheme switching
  189. cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE1, slots, slots)
  190. print(f"\n---Input x1: {x1} encrypted under p = 4 and Q = {ctxtsLWE1[0].GetModulus()} ---")
  191. # Step 6. Decrypt
  192. plaintextDec = cc.Decrypt(keys.secretKey, cTemp)
  193. plaintextDec.SetLength(slots)
  194. print(f"Switched CKKS decryption 1: {plaintextDec}")
  195. # Step 5'. Perform the scheme switching
  196. cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE2, slots, slots, pLWE1, 0, pLWE1)
  197. print(f"\n---Input x1: {x1} encrypted under p = {pLWE1} and Q = {ctxtsLWE2[0].GetModulus()} ---")
  198. # Step 6'. Decrypt
  199. plaintextDec = cc.Decrypt(keys.secretKey, cTemp)
  200. plaintextDec.SetLength(slots)
  201. print(f"Switched CKKS decryption 2: {plaintextDec}")
  202. # Step 5''. Perform the scheme switching
  203. cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE3, slots, slots, pLWE2, 0, pLWE2)
  204. print(f"\n---Input x2: {x2} encrypted under p = {pLWE2} and Q = {ctxtsLWE3[0].GetModulus()} ---")
  205. # Step 6''. Decrypt
  206. plaintextDec = cc.Decrypt(keys.secretKey, cTemp)
  207. plaintextDec.SetLength(slots)
  208. print(f"Switched CKKS decryption 3: {plaintextDec}")
  209. # Step 5'''. Perform the scheme switching
  210. cTemp2 = cc.EvalFHEWtoCKKS(ctxtsLWE4, slots, slots, pLWE3, 0, pLWE3)
  211. print(f"\n---Input x2: {x2} encrypted under p = {pLWE3} and Q = {ctxtsLWE4[0].GetModulus()} ---")
  212. # Step 6'''. Decrypt
  213. plaintextDec = cc.Decrypt(keys.secretKey, cTemp2)
  214. plaintextDec.SetLength(slots)
  215. print(f"Switched CKKS decryption 4: {plaintextDec}")
  216. def FloorViaSchemeSwitching():
  217. print("\n-----FloorViaSchemeSwitching-----\n")
  218. print("Output precision is only wrt the operations in CKKS after switching back.\n")
  219. # Step 1: Setup CryptoContext for CKKS
  220. scTech = FIXEDAUTO
  221. multDepth = 3 + 9 + 1 # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling
  222. if scTech == FLEXIBLEAUTOEXT:
  223. multDepth += 1
  224. scaleModSize = 50
  225. ringDim = 8192
  226. sl = HEStd_NotSet
  227. slBin = TOY
  228. logQ_ccLWE = 23
  229. slots = 16 # sparsely-packed
  230. batchSize = slots
  231. parameters = CCParamsCKKSRNS()
  232. parameters.SetMultiplicativeDepth(multDepth)
  233. parameters.SetScalingModSize(scaleModSize)
  234. parameters.SetScalingTechnique(scTech)
  235. parameters.SetSecurityLevel(sl)
  236. parameters.SetRingDim(ringDim)
  237. parameters.SetBatchSize(batchSize)
  238. cc = GenCryptoContext(parameters)
  239. # Enable the features that you wish to use
  240. cc.Enable(PKE)
  241. cc.Enable(KEYSWITCH)
  242. cc.Enable(LEVELEDSHE)
  243. cc.Enable(ADVANCEDSHE)
  244. cc.Enable(SCHEMESWITCH)
  245. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n")
  246. # Generate encryption keys.
  247. keys = cc.KeyGen()
  248. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  249. arbFunc = False
  250. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  251. ccLWE = FHEWparams[0]
  252. privateKeyFHEW = FHEWparams[1]
  253. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW)
  254. # Generate bootstrapping key for EvalFloor
  255. ccLWE.BTKeyGen(privateKeyFHEW)
  256. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  257. # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level
  258. modulus_CKKS_from = cc.GetModulusCKKS()
  259. modulus_LWE = 1 << logQ_ccLWE
  260. beta = ccLWE.GetBeta()
  261. pLWE = int(modulus_LWE / (2 * beta)) # Large precision
  262. scFactor = cc.GetScalingFactorReal(0)
  263. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  264. scFactor = cc.GetScalingFactorReal(1)
  265. scaleCF = int(modulus_CKKS_from) / (scFactor * pLWE)
  266. cc.EvalCKKStoFHEWPrecompute(scaleCF)
  267. # Step 3: Encoding and encryption of inputs
  268. # Inputs
  269. x1 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0]
  270. # Encoding as plaintexts
  271. ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0)#, None)
  272. # Encrypt the encoded vectors
  273. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  274. # Step 4: Scheme switching from CKKS to FHEW
  275. cTemp = cc.EvalCKKStoFHEW(c1)
  276. # Step 5: Evaluate the floor function
  277. bits = 2
  278. cFloor = [ccLWE.EvalFloor(cTemp[i], bits) for i in range(len(cTemp))]
  279. print(f"Input x1: {ptxt1.GetRealPackedValue()}")
  280. print(f"Expected result for EvalFloor with {bits} bits: ", end="")
  281. for i in range(slots):
  282. print(int(ptxt1.GetRealPackedValue()[i]) >> bits, end=" ")
  283. print(f"\nFHEW decryption p = {pLWE}/(1 << bits) = {pLWE // (1 << bits)}: ", end="")
  284. for i in range(len(cFloor)):
  285. pFloor = ccLWE.Decrypt(privateKeyFHEW, cFloor[i], pLWE // (1 << bits))
  286. print(pFloor, end=" ")
  287. print("\n")
  288. # Step 6: Scheme switching from FHEW to CKKS
  289. cTemp2 = cc.EvalFHEWtoCKKS(cFloor, slots, slots, pLWE // (1 << bits), 0, pLWE / (1 << bits))
  290. plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2)
  291. plaintextDec2.SetLength(slots)
  292. print(f"Switched floor decryption modulus_LWE mod {pLWE // (1 << bits)}: {plaintextDec2}")
  293. def FuncViaSchemeSwitching():
  294. print("\n-----FuncViaSchemeSwitching-----\n")
  295. print("Output precision is only wrt the operations in CKKS after switching back.\n")
  296. # Step 1: Setup CryptoContext for CKKS
  297. multDepth = 9 + 3 + 2 # 1 for CKKS to FHEW, 14 for FHEW to CKKS
  298. scaleModSize = 50
  299. ringDim = 2048
  300. sl = HEStd_NotSet
  301. slBin = TOY
  302. logQ_ccLWE = 25
  303. arbFunc = True
  304. slots = 8 # sparsely-packed
  305. batchSize = slots
  306. parameters = CCParamsCKKSRNS()
  307. parameters.SetMultiplicativeDepth(multDepth)
  308. parameters.SetScalingModSize(scaleModSize)
  309. parameters.SetScalingTechnique(FIXEDMANUAL)
  310. parameters.SetSecurityLevel(sl)
  311. parameters.SetRingDim(ringDim)
  312. parameters.SetBatchSize(batchSize)
  313. cc = GenCryptoContext(parameters)
  314. # Enable the features that you wish to use
  315. cc.Enable(PKE)
  316. cc.Enable(KEYSWITCH)
  317. cc.Enable(LEVELEDSHE)
  318. cc.Enable(ADVANCEDSHE)
  319. cc.Enable(SCHEMESWITCH)
  320. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n and number of slots {slots}\n")
  321. # Generate encryption keys.
  322. keys = cc.KeyGen()
  323. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  324. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  325. ccLWE = FHEWparams[0]
  326. privateKeyFHEW = FHEWparams[1]
  327. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW)
  328. # Generate the bootstrapping keys for EvalFunc in FHEW
  329. ccLWE.BTKeyGen(privateKeyFHEW)
  330. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  331. # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level
  332. modulus_CKKS_from = cc.GetModulusCKKS()
  333. pLWE = ccLWE.GetMaxPlaintextSpace() # Small precision because GenerateLUTviaFunction needs p < q
  334. scFactor = cc.GetScalingFactorReal(0)
  335. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  336. scFactor = cc.GetScalingFactorReal(1)
  337. scaleCF = modulus_CKKS_from / (scFactor * pLWE)
  338. cc.EvalCKKStoFHEWPrecompute(scaleCF)
  339. # Step 3: Initialize the function
  340. # Initialize Function f(x) = x^3 + 2x + 1 % p
  341. def fp(m, p1):
  342. if m < p1:
  343. return (m * m * m + 2 * m * m + 1) % p1
  344. else:
  345. return ((m - p1 / 2) * (m - p1 / 2) * (m - p1 / 2) + 2 * (m - p1 / 2) * (m - p1 / 2) + 1) % p1
  346. # Generate LUT from function f(x)
  347. lut = ccLWE.GenerateLUTviaFunction(fp, pLWE)
  348. # Step 4: Encoding and encryption of inputs
  349. # Inputs
  350. x1 = [0.0, 0.3, 2.0, 4.0, 5.0, 6.0, 7.0, 8.0]
  351. # Encoding as plaintexts
  352. ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None)
  353. # Encrypt the encoded vectors
  354. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  355. # Step 5: Scheme switching from CKKS to FHEW
  356. cTemp = cc.EvalCKKStoFHEW(c1)
  357. print(f"Input x1: {ptxt1.GetRealPackedValue()}")
  358. print("FHEW decryption: ", end="")
  359. for i in range(len(cTemp)):
  360. result = ccLWE.Decrypt(privateKeyFHEW, cTemp[i], pLWE)
  361. print(result, end=" ")
  362. # Step 6: Evaluate the function
  363. cFunc = [ccLWE.EvalFunc(cTemp[i], lut) for i in range(len(cTemp))]
  364. print("\nExpected result x^3 + 2*x + 1 mod p: ", end="")
  365. for i in range(slots):
  366. print(fp(int(x1[i]) % pLWE, pLWE), end=" ")
  367. print(f"\nFHEW decryption mod {pLWE}: ", end="")
  368. for i in range(len(cFunc)):
  369. pFunc = ccLWE.Decrypt(privateKeyFHEW, cFunc[i], pLWE)
  370. print(pFunc, end=" ")
  371. print("\n")
  372. # Step 7: Scheme switching from FHEW to CKKS
  373. cTemp2 = cc.EvalFHEWtoCKKS(cFunc, slots, slots, pLWE, 0, pLWE)
  374. plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2)
  375. plaintextDec2.SetLength(slots)
  376. print(f"\nSwitched decryption modulus_LWE mod {pLWE}\nwoeks only for messages << p: {plaintextDec2}")
  377. # Transform through arcsine
  378. cTemp2 = cc.EvalFHEWtoCKKS(cFunc, slots, slots, 4, 0, 2)
  379. plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2)
  380. plaintextDec2.SetLength(slots)
  381. print("Arcsin(switched result) * p/2pi gives the correct result if messages are < p/4: ", end="")
  382. for i in range(slots):
  383. x = max(min(plaintextDec2.GetRealPackedValue()[i], 1.0), -1.0)
  384. print(asin(x) * pLWE / (2 * pi), end=" ")
  385. print()
  386. def PolyViaSchemeSwitching():
  387. print("\n-----PolyViaSchemeSwitching-----\n")
  388. # Step 1: Setup CryptoContext for CKKS to be switched into
  389. # A. Specify main parameters
  390. scTech = FIXEDAUTO
  391. multDepth = 3 + 9 + 1 + 2 # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling, 3 levels for functionality
  392. if scTech == FLEXIBLEAUTOEXT:
  393. multDepth += 1
  394. scaleModSize = 50
  395. ringDim = 2048
  396. sl = HEStd_NotSet
  397. slBin = TOY
  398. logQ_ccLWE = 25
  399. slots = 16 # sparsely-packed
  400. batchSize = slots
  401. # Create encryption parameters
  402. parameters = CCParamsCKKSRNS()
  403. parameters.SetMultiplicativeDepth(multDepth)
  404. parameters.SetScalingModSize(scaleModSize)
  405. parameters.SetScalingTechnique(scTech)
  406. parameters.SetSecurityLevel(sl)
  407. parameters.SetRingDim(ringDim)
  408. parameters.SetBatchSize(batchSize)
  409. cc = GenCryptoContext(parameters)
  410. # Enable the features that you wish to use
  411. cc.Enable(PKE)
  412. cc.Enable(KEYSWITCH)
  413. cc.Enable(LEVELEDSHE)
  414. cc.Enable(ADVANCEDSHE)
  415. cc.Enable(SCHEMESWITCH)
  416. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n")
  417. # Generate encryption keys
  418. keys = cc.KeyGen()
  419. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  420. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, False, logQ_ccLWE, False, slots)
  421. ccLWE = FHEWparams[0]
  422. privateKeyFHEW = FHEWparams[1]
  423. # Step 3: Precompute the necessary keys and information for switching from FHEW to CKKS
  424. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, slots)
  425. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  426. pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision
  427. modulus_LWE = 1 << logQ_ccLWE
  428. beta = ccLWE.GetBeta()
  429. pLWE2 = modulus_LWE // (2 * beta) # Large precision
  430. modulus_from_CKKS = cc.GetModulusCKKS()
  431. scFactor = cc.GetScalingFactorReal(0)
  432. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  433. scFactor = cc.GetScalingFactorReal(1)
  434. scale1 = modulus_from_CKKS // (scFactor * pLWE1)
  435. scale2 = modulus_from_CKKS // (scFactor * pLWE2)
  436. # Generate keys for the CKKS intermediate computation
  437. cc.EvalMultKeyGen(keys.secretKey)
  438. cc.EvalRotateKeyGen(keys.secretKey, [1,2])
  439. # Step 4: Encoding and encryption of inputs
  440. # For correct CKKS decryption, the messages have to be much smaller than the FHEW plaintext modulus!
  441. # Inputs
  442. x1 = [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
  443. x2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
  444. x1Rot = RotateInt(x1,1)
  445. x1Rot = [x1Rot[i] + x1[i] for i in range(len(x1))]
  446. x1Int = [int(round(0.25 * elem * elem) % pLWE1) for elem in x1Rot]
  447. x2Rot = RotateInt(x2,2)
  448. x2Rot = [x2Rot[i] + x2[i] for i in range(len(x2))]
  449. x2Int = [int(round(0.25 * elem * elem) % pLWE2) for elem in x2Rot]
  450. # Encrypt
  451. # encrypted under small plantext modulus p = 4 and ciphertext modulus
  452. ctxtsLWE1 = [ccLWE.Encrypt(privateKeyFHEW, x1[i]) for i in range(slots)]
  453. # encrypted under large plaintext modulus and large ciphertext modulus
  454. ctxtsLWE2 = [ccLWE.Encrypt(privateKeyFHEW, x2[i], FRESH, pLWE2, modulus_LWE) for i in range(slots)]
  455. # Step 5. Perform the scheme switching
  456. cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE1, slots, slots)
  457. print(f"\n---Input x1: {x1} encrypted under p = 4 and Q = {ctxtsLWE1[0].GetModulus()} ---\n")
  458. print(f"round( 0.5 * (x1 + rot(x1,1) )^2 ): {x1Int}\n")
  459. # Step 6. Perform the desired computation in CKKS
  460. cPoly = cc.EvalAdd(cTemp, cc.EvalRotate(cTemp, 1))
  461. cPoly = cc.EvalMult(cc.EvalMult(cPoly, cPoly), 0.25)
  462. # Perform the precomputation for switching back to CKKS
  463. cc.EvalCKKStoFHEWPrecompute(scale1)
  464. # Tranform the ciphertext from CKKS to FHEW
  465. cTemp1 = cc.EvalCKKStoFHEW(cPoly, slots)
  466. print(f"\nFHEW decryption with plaintext modulus {pLWE1}: ", end="")
  467. for i in range(len(cTemp1)):
  468. result = ccLWE.Decrypt(privateKeyFHEW, cTemp1[i], pLWE1)
  469. print(result, end=" ")
  470. print("\n")
  471. # Step 5'. Perform the scheme switching
  472. cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE2, slots, slots, pLWE2, 0, pLWE2)
  473. print(f"\n---Input x2: {x2} encrypted under p = {pLWE2} and Q = {ctxtsLWE2[0].GetModulus()} ---\n")
  474. print(f"round( 0.5 * (x2 + rot(x2,2) )^2 ): {x2Int}\n")
  475. # Step 6'. Perform the desired computation in CKKS
  476. cPoly = cc.EvalAdd(cTemp, cc.EvalRotate(cTemp, 2))
  477. cPoly = cc.EvalMult(cc.EvalMult(cPoly, cPoly), 0.25)
  478. # Perform the precomputation for switching back to CKKS
  479. cc.EvalCKKStoFHEWPrecompute(scale2)
  480. # Tranform the ciphertext from CKKS to FHEW
  481. cTemp2 = cc.EvalCKKStoFHEW(cPoly, slots)
  482. print(f"\nFHEW decryption with plaintext modulus {pLWE2}: ", end="")
  483. for i in range(len(cTemp2)):
  484. result = ccLWE.Decrypt(privateKeyFHEW, cTemp2[i], pLWE2)
  485. print(result, end=" ")
  486. print("\n")
  487. def ComparisonViaSchemeSwitching():
  488. print("\n-----ComparisonViaSchemeSwitching-----\n")
  489. print("Output precision is only wrt the operations in CKKS after switching back.\n")
  490. # Step 1: Setup CryptoContext for CKKS
  491. scTech = FIXEDAUTO
  492. multDepth = 17
  493. if scTech == FLEXIBLEAUTOEXT:
  494. multDepth += 1
  495. scaleModSize = 50
  496. firstModSize = 60
  497. ringDim = 8192
  498. sl = HEStd_NotSet
  499. slBin = TOY
  500. logQ_ccLWE = 25
  501. slots = 16 # sparsely-packed
  502. batchSize = slots
  503. parameters = CCParamsCKKSRNS()
  504. parameters.SetMultiplicativeDepth(multDepth)
  505. parameters.SetScalingModSize(scaleModSize)
  506. parameters.SetFirstModSize(firstModSize)
  507. parameters.SetScalingTechnique(scTech)
  508. parameters.SetSecurityLevel(sl)
  509. parameters.SetRingDim(ringDim)
  510. parameters.SetBatchSize(batchSize)
  511. parameters.SetSecretKeyDist(UNIFORM_TERNARY)
  512. parameters.SetKeySwitchTechnique(HYBRID)
  513. parameters.SetNumLargeDigits(3)
  514. cc = GenCryptoContext(parameters)
  515. # Enable the features that you wish to use
  516. cc.Enable(PKE)
  517. cc.Enable(KEYSWITCH)
  518. cc.Enable(LEVELEDSHE)
  519. cc.Enable(ADVANCEDSHE)
  520. cc.Enable(SCHEMESWITCH)
  521. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n and number of slots {slots}\n and supports a multiplicative depth of {multDepth}\n")
  522. # Generate encryption keys.
  523. keys = cc.KeyGen()
  524. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  525. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, False, logQ_ccLWE, False, slots)
  526. ccLWE = FHEWparams[0]
  527. privateKeyFHEW = FHEWparams[1]
  528. ccLWE.BTKeyGen(privateKeyFHEW)
  529. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW)
  530. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  531. # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level
  532. pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision
  533. modulus_LWE = 1 << logQ_ccLWE
  534. beta = ccLWE.GetBeta()
  535. pLWE2 = modulus_LWE // (2 * beta) # Large precision
  536. scaleSignFHEW = 1
  537. init_level = 0
  538. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  539. init_level = 1
  540. cc.EvalCompareSwitchPrecompute(pLWE2, init_level, scaleSignFHEW)
  541. # Step 3: Encoding and encryption of inputs
  542. x1 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0]
  543. x2 = [5.25] * slots
  544. ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None, slots)
  545. ptxt2 = cc.MakeCKKSPackedPlaintext(x2, 1, 0, None, slots)
  546. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  547. c2 = cc.Encrypt(keys.publicKey, ptxt2)
  548. cDiff = cc.EvalSub(c1, c2)
  549. # Step 4: CKKS to FHEW switching and sign evaluation to test correctness
  550. pDiff = cc.Decrypt(keys.secretKey, cDiff)
  551. pDiff.SetLength(slots)
  552. print("Difference of inputs: ", end="")
  553. for i in range(slots):
  554. print(pDiff.GetRealPackedValue()[i], end=" ")
  555. eps = 0.0001
  556. print("\nExpected sign result from CKKS: ", end="")
  557. for i in range(slots):
  558. print(int(round(pDiff.GetRealPackedValue()[i] / eps) * eps < 0), end=" ")
  559. print()
  560. LWECiphertexts = cc.EvalCKKStoFHEW(cDiff, slots)
  561. print("\nFHEW decryption with plaintext modulus ", pLWE2, ": ", end="")
  562. for i in range(len(LWECiphertexts)):
  563. plainLWE = ccLWE.Decrypt(privateKeyFHEW, LWECiphertexts[i], pLWE2)
  564. print(plainLWE, end=" ")
  565. print("\nExpected sign result in FHEW with plaintext modulus ", pLWE2, " and scale ", scaleSignFHEW, ": ", end="")
  566. for i in range(slots):
  567. print((int(round(pDiff.GetRealPackedValue()[i] * scaleSignFHEW)) % pLWE2 - pLWE2 / 2.0 >= 0), end=" ")
  568. print()
  569. print("Obtained sign result in FHEW with plaintext modulus ", pLWE2, " and scale ", scaleSignFHEW, ": ", end="")
  570. LWESign = [None] * len(LWECiphertexts)
  571. for i in range(len(LWECiphertexts)):
  572. LWESign[i] = ccLWE.EvalSign(LWECiphertexts[i])
  573. plainLWE = ccLWE.Decrypt(privateKeyFHEW, LWESign[i], 2)
  574. print(plainLWE, end=" ")
  575. print()
  576. # Step 5'': Direct comparison via CKKS->FHEW->CKKS
  577. cResult = cc.EvalCompareSchemeSwitching(c1, c2, slots, 0, scaleSignFHEW)
  578. plaintextDec3 = cc.Decrypt(keys.secretKey, cResult)
  579. plaintextDec3.SetLength(slots)
  580. print(f"Decrypted swutched result: {plaintextDec3}\n")
  581. def ArgminViaSchemeSwitching():
  582. print("\n-----ArgminViaSchemeSwitching-----\n")
  583. print("Output precision is only wrt the operations in CKKS after switching back\n")
  584. # Step 1: Setup CryptoContext for CKKS
  585. scaleModSize = 50
  586. firstModSize = 60
  587. ringDim = 8192
  588. sl = HEStd_NotSet
  589. slBin = TOY
  590. logQ_ccLWE = 25
  591. arbFunc = False
  592. oneHot = True # Change to false if the output should not be one-hot encoded
  593. slots = 16 # sparsely-packed
  594. batchSize = slots
  595. numValues = 16
  596. scTech = FIXEDMANUAL
  597. multDepth = 9 + 3 + 1 + int(log2(numValues)) # 13 for FHEW to CKKS, log2(numValues) for argmin
  598. if scTech == FLEXIBLEAUTOEXT:
  599. multDepth += 1
  600. parameters = CCParamsCKKSRNS()
  601. parameters.SetMultiplicativeDepth(multDepth)
  602. parameters.SetScalingModSize(scaleModSize)
  603. parameters.SetFirstModSize(firstModSize)
  604. parameters.SetScalingTechnique(scTech)
  605. parameters.SetSecurityLevel(sl)
  606. parameters.SetRingDim(ringDim)
  607. parameters.SetBatchSize(batchSize)
  608. cc = GenCryptoContext(parameters)
  609. # Enable the features that you wish to use
  610. cc.Enable(PKE)
  611. cc.Enable(KEYSWITCH)
  612. cc.Enable(LEVELEDSHE)
  613. cc.Enable(ADVANCEDSHE)
  614. cc.Enable(SCHEMESWITCH)
  615. print("CKKS scheme is using ring dimension ", cc.GetRingDimension())
  616. print(", and number of slots ", slots, ", and supports a depth of ", multDepth, "\n")
  617. # Generate encryption keys
  618. keys = cc.KeyGen()
  619. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  620. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  621. ccLWE = FHEWparams[0]
  622. privateKeyFHEW = FHEWparams[1]
  623. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot)
  624. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  625. # Scale the inputs to ensure their difference is correctly represented after switching to FHEW
  626. scaleSign = 512
  627. modulus_LWE = 1 << logQ_ccLWE
  628. beta = ccLWE.GetBeta()
  629. pLWE = modulus_LWE // (2 * beta) # Large precision
  630. init_level = 0
  631. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  632. init_level = 1
  633. cc.EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign)
  634. # Step 3: Encoding and encryption of inputs
  635. x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30]
  636. print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1)))
  637. print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1)))
  638. ptxt1 = cc.MakeCKKSPackedPlaintext(x1)
  639. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  640. # Step 4: Argmin evaluation
  641. result = cc.EvalMinSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot)
  642. ptxtMin = cc.Decrypt(keys.secretKey, result[0])
  643. ptxtMin.SetLength(1)
  644. print("Minimum value: ", ptxtMin)
  645. ptxtMin = cc.Decrypt(keys.secretKey, result[1])
  646. if oneHot:
  647. ptxtMin.SetLength(numValues)
  648. print("Argmin indicator vector: ", ptxtMin)
  649. else:
  650. ptxtMin.SetLength(1)
  651. print("Argmin: ", ptxtMin)
  652. result = cc.EvalMaxSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot)
  653. ptxtMax = cc.Decrypt(keys.secretKey, result[0])
  654. ptxtMax.SetLength(1)
  655. print("Maximum value: ", ptxtMax)
  656. ptxtMax = cc.Decrypt(keys.secretKey, result[1])
  657. if oneHot:
  658. ptxtMax.SetLength(numValues)
  659. print("Argmax indicator vector: ", ptxtMax)
  660. else:
  661. ptxtMax.SetLength(1)
  662. print("Argmax: ", ptxtMax)
  663. def ArgminViaSchemeSwitchingAlt():
  664. print("\n-----ArgminViaSchemeSwitchingAlt-----\n")
  665. print("Output precision is only wrt the operations in CKKS after switching back\n")
  666. # Step 1: Setup CryptoContext for CKKS
  667. scaleModSize = 50
  668. firstModSize = 60
  669. ringDim = 8192
  670. sl = HEStd_NotSet
  671. slBin = TOY
  672. logQ_ccLWE = 25
  673. arbFunc = False
  674. oneHot = True
  675. alt = True
  676. slots = 16
  677. batchSize = slots
  678. numValues = 16
  679. scTech = FIXEDAUTO
  680. multDepth = 9 + 3 + 1 + int(log2(numValues))
  681. parameters = CCParamsCKKSRNS()
  682. parameters.SetMultiplicativeDepth(multDepth)
  683. parameters.SetScalingModSize(scaleModSize)
  684. parameters.SetFirstModSize(firstModSize)
  685. parameters.SetScalingTechnique(scTech)
  686. parameters.SetSecurityLevel(sl)
  687. parameters.SetRingDim(ringDim)
  688. parameters.SetBatchSize(batchSize)
  689. cc = GenCryptoContext(parameters)
  690. cc.Enable(PKE)
  691. cc.Enable(KEYSWITCH)
  692. cc.Enable(LEVELEDSHE)
  693. cc.Enable(ADVANCEDSHE)
  694. cc.Enable(SCHEMESWITCH)
  695. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},")
  696. print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n")
  697. keys = cc.KeyGen()
  698. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  699. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  700. ccLWE = FHEWparams[0]
  701. privateKeyFHEW = FHEWparams[1]
  702. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot, alt)
  703. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  704. scaleSign = 512
  705. modulus_LWE = 1 << logQ_ccLWE
  706. beta = ccLWE.GetBeta()
  707. pLWE = modulus_LWE // (2 * beta)
  708. init_level = 0
  709. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  710. init_level = 1
  711. cc.EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign)
  712. # But we can also include the scaleSign in pLWE (here we use the fact both pLWE and scaleSign are powers of two)
  713. # cc.EvalCompareSwitchPrecompute(pLWE / scaleSign, init_level, 1)
  714. # Step 3: Encoding and encryption of inputs
  715. # Inputs
  716. x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30]
  717. print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1)))
  718. print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1)))
  719. # Encoding as plaintexts
  720. ptxt1 = cc.MakeCKKSPackedPlaintext(x1) # Only if we set batchsize
  721. # ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None, slots) # If batchsize is not set
  722. # Encrypt the encoded vectors
  723. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  724. # Step 4: Argmin evaluation
  725. result = cc.EvalMinSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot)
  726. ptxtMin = cc.Decrypt(keys.secretKey, result[0])
  727. ptxtMin.SetLength(1)
  728. print("Minimum value: ", ptxtMin)
  729. ptxtMin = cc.Decrypt(keys.secretKey, result[1])
  730. if oneHot:
  731. ptxtMin.SetLength(numValues)
  732. print("Argmin indicator vector: ", ptxtMin)
  733. else:
  734. ptxtMin.SetLength(1)
  735. print("Argmin: ", ptxtMin)
  736. result = cc.EvalMaxSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot)
  737. ptxtMax = cc.Decrypt(keys.secretKey, result[0])
  738. ptxtMax.SetLength(1)
  739. print("Maximum value: ", ptxtMax)
  740. ptxtMax = cc.Decrypt(keys.secretKey, result[1])
  741. if oneHot:
  742. ptxtMax.SetLength(numValues)
  743. print("Argmax indicator vector: ", ptxtMax)
  744. else:
  745. ptxtMax.SetLength(1)
  746. print("Argmax: ", ptxtMax)
  747. def ArgminViaSchemeSwitchingUnit():
  748. print("\n-----ArgminViaSchemeSwitchingUnit-----\n")
  749. print("Output precision is only wrt the operations in CKKS after switching back\n")
  750. # Step 1: Setup CryptoContext for CKKS
  751. scaleModSize = 50
  752. firstModSize = 60
  753. ringDim = 8192
  754. sl = HEStd_NotSet
  755. slBin = TOY
  756. logQ_ccLWE = 25
  757. arbFunc = False
  758. oneHot = True
  759. slots = 32 # sparsely-packed
  760. batchSize = slots
  761. numValues = 32
  762. scTech = FLEXIBLEAUTOEXT
  763. multDepth = 9 + 3 + 1 + int(log2(numValues)) # 1 for CKKS to FHEW, 13 for FHEW to CKKS, log2(numValues) for argmin
  764. if scTech == FLEXIBLEAUTOEXT:
  765. multDepth += 1
  766. parameters = CCParamsCKKSRNS()
  767. parameters.SetMultiplicativeDepth(multDepth)
  768. parameters.SetScalingModSize(scaleModSize)
  769. parameters.SetFirstModSize(firstModSize)
  770. parameters.SetScalingTechnique(scTech)
  771. parameters.SetSecurityLevel(sl)
  772. parameters.SetRingDim(ringDim)
  773. parameters.SetBatchSize(batchSize)
  774. cc = GenCryptoContext(parameters)
  775. # Enable the features that you wish to use
  776. cc.Enable(PKE)
  777. cc.Enable(KEYSWITCH)
  778. cc.Enable(LEVELEDSHE)
  779. cc.Enable(ADVANCEDSHE)
  780. cc.Enable(SCHEMESWITCH)
  781. cc.Enable(FHE)
  782. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},")
  783. print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n")
  784. # Generate encryption keys.
  785. keys = cc.KeyGen()
  786. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  787. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  788. ccLWE = FHEWparams[0]
  789. privateKeyFHEW = FHEWparams[1]
  790. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot)
  791. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  792. init_level = 0
  793. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  794. init_level = 1
  795. # Here we assume the message does not need scaling, as they are in the unit circle.
  796. cc.EvalCompareSwitchPrecompute(1, init_level, 1)
  797. # Step 3: Encoding and encryption of inputs
  798. # Inputs
  799. x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30]
  800. if len(x1) < slots:
  801. x1.extend([0] * (slots - len(x1)))
  802. print("Input: ", x1)
  803. p = 1 << (firstModSize - scaleModSize - 1)
  804. x1 = [elem / (2 * p) for elem in x1]
  805. print("Input scaled: ", x1)
  806. print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1)))
  807. print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1)))
  808. # Encoding as plaintexts
  809. ptxt1 = cc.MakeCKKSPackedPlaintext(x1)
  810. # Encrypt the encoded vectors
  811. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  812. # Step 4: Argmin evaluation
  813. result = cc.EvalMinSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot)
  814. ptxtMin = cc.Decrypt(keys.secretKey, result[0])
  815. ptxtMin.SetLength(1)
  816. print("Minimum value: ", ptxtMin)
  817. ptxtMin = cc.Decrypt(keys.secretKey, result[1])
  818. if oneHot:
  819. ptxtMin.SetLength(numValues)
  820. print("Argmin indicator vector: ", ptxtMin)
  821. else:
  822. ptxtMin.SetLength(1)
  823. print("Argmin: ", ptxtMin)
  824. result = cc.EvalMaxSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot)
  825. ptxtMax = cc.Decrypt(keys.secretKey, result[0])
  826. ptxtMax.SetLength(1)
  827. print("Maximum value: ", ptxtMax)
  828. ptxtMax = cc.Decrypt(keys.secretKey, result[1])
  829. if oneHot:
  830. ptxtMax.SetLength(numValues)
  831. print("Argmax indicator vector: ", ptxtMax)
  832. else:
  833. ptxtMax.SetLength(1)
  834. print("Argmax: ", ptxtMax)
  835. def ArgminViaSchemeSwitchingAltUnit():
  836. print("\n-----ArgminViaSchemeSwitchingAltUnit-----\n")
  837. print("Output precision is only wrt the operations in CKKS after switching back\n")
  838. # Step 1: Setup CryptoContext for CKKS
  839. scaleModSize = 50
  840. firstModSize = 60
  841. ringDim = 8192
  842. sl = HEStd_NotSet
  843. slBin = TOY
  844. logQ_ccLWE = 25
  845. arbFunc = False
  846. oneHot = True
  847. alt = True # alternative mode of argmin which has fewer rotation keys and does more operations in FHEW than in CKKS
  848. slots = 32 # sparsely-packed
  849. batchSize = slots
  850. numValues = 32
  851. scTech = FLEXIBLEAUTOEXT
  852. multDepth = 9 + 3 + 1 + int(log2(numValues)) # 1 for CKKS to FHEW, 13 for FHEW to CKKS, log2(numValues) for argmin
  853. if scTech == FLEXIBLEAUTOEXT:
  854. multDepth += 1
  855. parameters = CCParamsCKKSRNS()
  856. parameters.SetMultiplicativeDepth(multDepth)
  857. parameters.SetScalingModSize(scaleModSize)
  858. parameters.SetFirstModSize(firstModSize)
  859. parameters.SetScalingTechnique(scTech)
  860. parameters.SetSecurityLevel(sl)
  861. parameters.SetRingDim(ringDim)
  862. parameters.SetBatchSize(batchSize)
  863. cc = GenCryptoContext(parameters)
  864. # Enable the features that you wish to use
  865. cc.Enable(PKE)
  866. cc.Enable(KEYSWITCH)
  867. cc.Enable(LEVELEDSHE)
  868. cc.Enable(ADVANCEDSHE)
  869. cc.Enable(SCHEMESWITCH)
  870. cc.Enable(FHE)
  871. print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},")
  872. print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n")
  873. # Generate encryption keys.
  874. keys = cc.KeyGen()
  875. # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  876. FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots)
  877. ccLWE = FHEWparams[0]
  878. privateKeyFHEW = FHEWparams[1]
  879. cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot, alt)
  880. print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n")
  881. init_level = 0
  882. if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT:
  883. init_level = 1
  884. # Here we assume the message does not need scaling, as they are in the unit circle.
  885. cc.EvalCompareSwitchPrecompute(1, init_level, 1)
  886. # Step 3: Encoding and encryption of inputs
  887. # Inputs
  888. x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30]
  889. if len(x1) < slots:
  890. zeros = [0] * (slots - len(x1))
  891. x1.extend(zeros)
  892. print("Input: ", x1)
  893. p = 1 << (firstModSize - scaleModSize - 1)
  894. x1 = [elem / (2 * p) for elem in x1]
  895. print("Input scaled: ", x1)
  896. print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1)))
  897. print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1)))
  898. # Encoding as plaintexts
  899. ptxt1 = cc.MakeCKKSPackedPlaintext(x1)
  900. # Encrypt the encoded vectors
  901. c1 = cc.Encrypt(keys.publicKey, ptxt1)
  902. # Step 4: Argmin evaluation
  903. result = cc.EvalMinSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot)
  904. ptxtMin = cc.Decrypt(keys.secretKey, result[0])
  905. ptxtMin.SetLength(1)
  906. print("Minimum value: ", ptxtMin)
  907. ptxtMin = cc.Decrypt(keys.secretKey, result[1])
  908. if oneHot:
  909. ptxtMin.SetLength(numValues)
  910. print("Argmin indicator vector: ", ptxtMin)
  911. else:
  912. ptxtMin.SetLength(1)
  913. print("Argmin: ", ptxtMin)
  914. result = cc.EvalMaxSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot)
  915. ptxtMax = cc.Decrypt(keys.secretKey, result[0])
  916. ptxtMax.SetLength(1)
  917. print("Maximum value: ", ptxtMax)
  918. ptxtMax = cc.Decrypt(keys.secretKey, result[1])
  919. if oneHot:
  920. ptxtMax.SetLength(numValues)
  921. print("Argmax indicator vector: ", ptxtMax)
  922. else:
  923. ptxtMax.SetLength(1)
  924. print("Argmax: ", ptxtMax)
  925. # Helper functions:
  926. def ReduceRotation(index, slots):
  927. islots = int(slots)
  928. # if slots is a power of 2
  929. if (slots & (slots - 1)) == 0:
  930. n = int(log2(slots))
  931. if index >= 0:
  932. return index - ((index >> n) << n)
  933. return index + islots + ((int(abs(index)) >> n) << n)
  934. return (islots + index % islots) % islots
  935. def RotateInt(a, index):
  936. slots = len(a)
  937. result = [0]*slots
  938. if index < 0 or index > slots:
  939. index = ReduceRotation(index, slots)
  940. if index == 0:
  941. result = a.copy()
  942. else:
  943. # two cases: i+index <= slots and i+index > slots
  944. for i in range(0, slots - index):
  945. result[i] = a[i + index]
  946. for i in range(slots - index, slots):
  947. result[i] = a[i + index - slots]
  948. return result
  949. if __name__ == "__main__":
  950. main()