simple_real_numbers.rst 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. Homomorphic additions, multiplications, and rotations for vectors of real numbers via CKKS
  2. ===========================================================================================
  3. Overview
  4. --------
  5. Homomorphic encryption allows computations on encrypted data without decrypting it. The CKKS (Cheon-Kim-Kim-Song) scheme supports approximate arithmetic operations on encrypted data, making it suitable for real number calculations.
  6. The example walks through the setup of cryptographic parameters, key generation, encryption of plaintext vectors, performing homomorphic operations, and decrypting the results. The example for this code is located in :code:`examples/simple_real_numbers.rs <https://github.com/fairmath/openfhe-rs/blob/master/examples/simple_real_numbers.rs>`_.
  7. Code breakdown
  8. --------------
  9. Importing libraries
  10. ~~~~~~~~~~~~~~~~~~
  11. We start by importing the necessary libraries and modules:
  12. .. code-block:: rust
  13. use openfhe::cxx::{CxxVector};
  14. use openfhe::ffi as ffi;
  15. The code example
  16. ~~~~~~~~~~~~~~~~
  17. The :code:`main` function contains the entire workflow for setting up the CKKS scheme, performing encryption, executing homomorphic operations, and decrypting the results.
  18. .. code-block:: rust
  19. fn main()
  20. {
  21. // Define cryptographic parameters for CKKS
  22. let _mult_depth: u32 = 1;
  23. let _scale_mod_size: u32 = 50;
  24. let _batch_size: u32 = 8;
  25. Generating Parameters
  26. ~~~~~~~~~~~~~~~~~~~~
  27. We define the cryptographic parameters for the CKKS scheme, including multiplicative depth, scaling modulus size, and batch size.
  28. .. code-block:: rust
  29. // Generate parameters for CKKS scheme
  30. let mut _cc_params_ckksrns = ffi::GenParamsCKKSRNS();
  31. _cc_params_ckksrns.pin_mut().SetMultiplicativeDepth(_mult_depth);
  32. _cc_params_ckksrns.pin_mut().SetScalingModSize(_scale_mod_size);
  33. _cc_params_ckksrns.pin_mut().SetBatchSize(_batch_size);
  34. Creating Crypto Context
  35. ~~~~~~~~~~~~~~~~~~~~~~~
  36. We create a crypto context based on the defined parameters and enable necessary features.
  37. .. code-block:: rust
  38. // Create crypto context based on parameters
  39. let _cc = ffi::DCRTPolyGenCryptoContextByParamsCKKSRNS(&_cc_params_ckksrns);
  40. _cc.EnableByFeature(ffi::PKESchemeFeature::PKE);
  41. _cc.EnableByFeature(ffi::PKESchemeFeature::KEYSWITCH);
  42. _cc.EnableByFeature(ffi::PKESchemeFeature::LEVELEDSHE);
  43. // Outputing the ring dimension for clarity
  44. println!("CKKS scheme is using ring dimension {}\n", _cc.GetRingDimension());
  45. Key Generation
  46. ~~~~~~~~~~~~~~
  47. We generate the necessary keys for encryption, including evaluation keys for multiplication and rotation.
  48. .. code-block:: rust
  49. // Key generation
  50. let _key_pair = _cc.KeyGen();
  51. _cc.EvalMultKeyGen(&_key_pair.GetPrivateKey());
  52. // Generate rotation keys
  53. let mut _index_list = CxxVector::<i32>::new();
  54. _index_list.pin_mut().push(1);
  55. _index_list.pin_mut().push(-2);
  56. _cc.EvalRotateKeyGen(&_key_pair.GetPrivateKey(), &_index_list, &ffi::DCRTPolyGenNullPublicKey());
  57. Creating Input Vectors
  58. ~~~~~~~~~~~~~~~~~~~~~~
  59. We create two input vectors for the demonstration.
  60. .. code-block:: rust
  61. // Create input vectors
  62. let mut _x_1 = CxxVector::<f64>::new();
  63. _x_1.pin_mut().push(0.25);
  64. ...
  65. _x_1.pin_mut().push(5.0);
  66. let mut _x_2 = CxxVector::<f64>::new();
  67. _x_2.pin_mut().push(5.0);
  68. ...
  69. _x_2.pin_mut().push(0.25);
  70. Creating Plaintext Objects
  71. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  72. We convert the input vectors into plaintext objects.
  73. .. code-block:: rust
  74. // Create plaintext objects from vectors
  75. let _dcrt_poly_params = ffi::DCRTPolyGenNullParams();
  76. let _p_txt_1 = _cc.MakeCKKSPackedPlaintextByVectorOfDouble(&_x_1, 1, 0, &_dcrt_poly_params, 0);
  77. let _p_txt_2 = _cc.MakeCKKSPackedPlaintextByVectorOfDouble(&_x_2, 1, 0, &_dcrt_poly_params, 0);
  78. // Outputing the vectors for clarity
  79. println!("Input x1: {}", _p_txt_1.GetString());
  80. println!("Input x2: {}", _p_txt_2.GetString());
  81. Encrypting Plaintext Vectors
  82. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  83. We encrypt the plaintext vectors using the generated public key.
  84. .. code-block:: rust
  85. // Encrypt plaintext vectors
  86. let _c1 = _cc.EncryptByPublicKey(&_key_pair.GetPublicKey(), &_p_txt_1);
  87. let _c2 = _cc.EncryptByPublicKey(&_key_pair.GetPublicKey(), &_p_txt_2);
  88. Performing Homomorphic Operations
  89. ----------------------------------
  90. We perform various homomorphic operations on the encrypted data, including addition, subtraction, multiplication by a constant, multiplication of ciphertexts, and rotations.
  91. .. code-block:: rust
  92. // Perform homomorphic operations
  93. let _c_add = _cc.EvalAddByCiphertexts(&_c1, &_c2);
  94. let _c_sub = _cc.EvalSubByCiphertexts(&_c1, &_c2);
  95. let _c_scalar = _cc.EvalMultByCiphertextAndConst(&_c1, 4.0);
  96. let _c_mul = _cc.EvalMultByCiphertexts(&_c1, &_c2);
  97. let _c_rot_1 = _cc.EvalRotate(&_c1, 1);
  98. let _c_rot_2 = _cc.EvalRotate(&_c1, -2);
  99. Decrypting and Printing Results
  100. --------------------------------
  101. Finally, we decrypt the results of the homomorphic computations and print them.
  102. .. code-block:: rust
  103. // Prepare for decryption
  104. let mut _result = ffi::GenNullPlainText();
  105. println!("\nResults of homomorphic computations:");
  106. // Decrypt and print results
  107. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c1, _result.pin_mut());
  108. _result.SetLength(_batch_size.try_into().unwrap());
  109. println!("x1 = {}Estimated precision in bits: {}", _result.GetString(), _result.GetLogPrecision());
  110. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_add, _result.pin_mut());
  111. _result.SetLength(_batch_size.try_into().unwrap());
  112. println!("x1 + x2 = {}Estimated precision in bits: {}",_result.GetString(), _result.GetLogPrecision());
  113. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_sub, _result.pin_mut());
  114. _result.SetLength(_batch_size.try_into().unwrap());
  115. println!("x1 - x2 = {}", _result.GetString());
  116. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_scalar, _result.pin_mut());
  117. _result.SetLength(_batch_size.try_into().unwrap());
  118. println!("4 * x1 = {}", _result.GetString());
  119. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_mul, _result.pin_mut());
  120. _result.SetLength(_batch_size.try_into().unwrap());
  121. println!("x1 * x2 = {}", _result.GetString());
  122. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_rot_1, _result.pin_mut());
  123. _result.SetLength(_batch_size.try_into().unwrap());
  124. println!("\nIn rotations, very small outputs (~10^-10 here) correspond to 0's:");
  125. println!("x1 rotate by 1 = {}", _result.GetString());
  126. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_rot_2, _result.pin_mut());
  127. _result.SetLength(_batch_size.try_into().unwrap());
  128. println!("x1 rotate by -2 = {}", _result.GetString());
  129. Running the example
  130. ~~~~~~~~~~~~~~~~~~~~
  131. 1. Ensure the `openfhe-rs` library is installed and properly configured, see the :doc:`intro` section.
  132. 2. Go to the `openfhe-rs` directory.
  133. 3. Compile and run the `simple_real_numbers.rs` example:
  134. .. code-block:: sh
  135. cargo run --example simple_real_numbers
  136. This should output the results of the homomorphic computations to the console.