iterative-ckks-bootstrapping.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from openfhe import *
  2. import math
  3. import random
  4. def main():
  5. iterative_bootstrap_example()
  6. def calculate_approximation_error(result,expected_result):
  7. if len(result) != len(expected_result):
  8. raise Exception("Cannot compare vectors with different numbers of elements")
  9. # using the infinity norm
  10. # error is abs of the difference of real parts
  11. max_error = max([abs(el1.real - el2.real) for (el1, el2) in zip(result, expected_result)])
  12. # return absolute value of log base2 of the error
  13. return abs(math.log(max_error,2))
  14. def iterative_bootstrap_example():
  15. # Step 1: Set CryptoContext
  16. parameters = CCParamsCKKSRNS()
  17. secret_key_dist = SecretKeyDist.UNIFORM_TERNARY
  18. parameters.SetSecretKeyDist(secret_key_dist)
  19. parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet)
  20. parameters.SetRingDim(1 << 12)
  21. rescale_tech = ScalingTechnique.FLEXIBLEAUTO
  22. dcrt_bits = 59
  23. first_mod = 60
  24. parameters.SetScalingModSize(dcrt_bits)
  25. parameters.SetScalingTechnique(rescale_tech)
  26. parameters.SetFirstModSize(first_mod)
  27. # Here, we specify the number of iterations to run bootstrapping.
  28. # Note that we currently only support 1 or 2 iterations.
  29. # Two iterations should give us approximately double the precision of one iteration.
  30. num_iterations = 2
  31. level_budget = [3, 3]
  32. # Each extra iteration on top of 1 requires an extra level to be consumed.
  33. approx_bootstrapp_depth = 8 + (num_iterations - 1)
  34. bsgs_dim = [0,0]
  35. levels_used_before_bootstrap = 10
  36. depth = levels_used_before_bootstrap + FHECKKSRNS.GetBootstrapDepth(approx_bootstrapp_depth, level_budget, secret_key_dist)
  37. parameters.SetMultiplicativeDepth(depth)
  38. # Generate crypto context
  39. cryptocontext = GenCryptoContext(parameters)
  40. # Enable features that you wish to use. Note, we must enable FHE to use bootstrapping.
  41. cryptocontext.Enable(PKESchemeFeature.PKE)
  42. cryptocontext.Enable(PKESchemeFeature.KEYSWITCH)
  43. cryptocontext.Enable(PKESchemeFeature.LEVELEDSHE)
  44. cryptocontext.Enable(PKESchemeFeature.ADVANCEDSHE)
  45. cryptocontext.Enable(PKESchemeFeature.FHE)
  46. ring_dim = cryptocontext.GetRingDimension()
  47. print(f"CKKS is using ring dimension {ring_dim}\n\n")
  48. # Step 2: Precomputations for bootstrapping
  49. # We use a sparse packing
  50. num_slots = 8
  51. cryptocontext.EvalBootstrapSetup(level_budget, bsgs_dim, num_slots)
  52. # Step 3: Key generation
  53. key_pair = cryptocontext.KeyGen()
  54. cryptocontext.EvalMultKeyGen(key_pair.secretKey)
  55. # Generate bootstrapping keys.
  56. cryptocontext.EvalBootstrapKeyGen(key_pair.secretKey, num_slots)
  57. # Step 4: Encoding and encryption of inputs
  58. # Generate random input
  59. x = [random.uniform(0, 1) for i in range(num_slots)]
  60. """ Encoding as plaintexts
  61. We specify the number of slots as num_slots to achieve a performance improvement.
  62. We use the other default values of depth 1, levels 0, and no params.
  63. Alternatively, you can also set batch size as a parameter in the CryptoContext as follows:
  64. parameters.SetBatchSize(num_slots);
  65. Here, we assume all ciphertexts in the cryptoContext will have num_slots slots.
  66. We start with a depleted ciphertext that has used up all of its levels."""
  67. ptxt = cryptocontext.MakeCKKSPackedPlaintext(x, 1, depth -1,None,num_slots)
  68. # Encrypt the encoded vectors
  69. ciph = cryptocontext.Encrypt(key_pair.publicKey, ptxt)
  70. # Step 5: Measure the precision of a single bootstrapping operation.
  71. ciphertext_after = cryptocontext.EvalBootstrap(ciph)
  72. result = cryptocontext.Decrypt(ciphertext_after,key_pair.secretKey)
  73. result.SetLength(num_slots)
  74. precision = calculate_approximation_error(result.GetCKKSPackedValue(),ptxt.GetCKKSPackedValue())
  75. print(f"Bootstrapping precision after 1 iteration: {precision} bits\n")
  76. # Set the precision equal to empirically measured value after many test runs.
  77. precision = 17
  78. print(f"Precision input to algorithm: {precision}\n")
  79. # Step 6: Run bootstrapping with multiple iterations
  80. ciphertext_two_iterations = cryptocontext.EvalBootstrap(ciph,num_iterations,precision)
  81. result_two_iterations = cryptocontext.Decrypt(ciphertext_two_iterations,key_pair.secretKey)
  82. result_two_iterations.SetLength(num_slots)
  83. actual_result = result_two_iterations.GetCKKSPackedValue()
  84. print(f"Output after two interations of bootstrapping: {actual_result}\n")
  85. precision_multiple_iterations = calculate_approximation_error(actual_result,ptxt.GetCKKSPackedValue())
  86. print(f"Bootstrapping precision after 2 iterations: {precision_multiple_iterations} bits\n")
  87. print(f"Number of levels remaining after 2 bootstrappings: {depth - ciphertext_two_iterations.GetLevel()}\n")
  88. if __name__ == "__main__":
  89. main()