scheme-switching.py 42 KB

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