simple_real_numbers.rst 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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`.
  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, SharedPtr};
  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. // Define cryptographic parameters for CKKS
  21. let _mult_depth: u32 = 1;
  22. let _scale_mod_size: u32 = 50;
  23. let _batch_size: u32 = 8;
  24. Generating Parameters
  25. ~~~~~~~~~~~~~~~~~~~~
  26. We define the cryptographic parameters for the CKKS scheme, including multiplicative depth, scaling modulus size, and batch size.
  27. .. code-block:: rust
  28. // Generate parameters for CKKS scheme
  29. let mut _cc_params_ckksrns = ffi::GenParamsCKKSRNS();
  30. _cc_params_ckksrns.pin_mut().SetMultiplicativeDepth(_mult_depth);
  31. _cc_params_ckksrns.pin_mut().SetScalingModSize(_scale_mod_size);
  32. _cc_params_ckksrns.pin_mut().SetBatchSize(_batch_size);
  33. Creating Crypto Context
  34. ~~~~~~~~~~~~~~~~~~~~~~~
  35. We create a crypto context based on the defined parameters and enable necessary features.
  36. .. code-block:: rust
  37. // Create crypto context based on parameters
  38. let _cc = ffi::GenCryptoContextByParamsCKKSRNS(&_cc_params_ckksrns);
  39. _cc.Enable(ffi::PKESchemeFeature::PKE);
  40. _cc.Enable(ffi::PKESchemeFeature::KEYSWITCH);
  41. _cc.Enable(ffi::PKESchemeFeature::LEVELEDSHE);
  42. // Outputing the ring dimension for clarity
  43. println!("CKKS scheme is using ring dimension {}\n", _cc.GetRingDimension());
  44. Key Generation
  45. ~~~~~~~~~~~~~~
  46. We generate the necessary keys for encryption, including evaluation keys for multiplication and rotation.
  47. .. code-block:: rust
  48. // Key generation
  49. let _key_pair = _cc.KeyGen();
  50. _cc.EvalMultKeyGen(&_key_pair.GetPrivateKey());
  51. // Generate rotation keys
  52. let mut _index_list = CxxVector::<i32>::new();
  53. _index_list.pin_mut().push(1);
  54. _index_list.pin_mut().push(-2);
  55. _cc.EvalRotateKeyGen(&_key_pair.GetPrivateKey(), &_index_list, &ffi::GenNullPublicKey());
  56. Creating Input Vectors
  57. ~~~~~~~~~~~~~~~~~~~~~~
  58. We create two input vectors for the demonstration.
  59. .. code-block:: rust
  60. // Create input vectors
  61. let mut _x_1 = CxxVector::<f64>::new();
  62. _x_1.pin_mut().push(0.25);
  63. ...
  64. _x_1.pin_mut().push(5.0);
  65. let mut _x_2 = CxxVector::<f64>::new();
  66. _x_2.pin_mut().push(5.0);
  67. ...
  68. _x_2.pin_mut().push(0.25);
  69. Creating Plaintext Objects
  70. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  71. We convert the input vectors into plaintext objects.
  72. .. code-block:: rust
  73. // Create plaintext objects from vectors
  74. let _p_txt_1 = _cc.MakeCKKSPackedPlaintext(&_x_1, 1, 0, SharedPtr::<ffi::DCRTPolyParams>::null(), 0);
  75. let _p_txt_2 = _cc.MakeCKKSPackedPlaintext(&_x_2, 1, 0, SharedPtr::<ffi::DCRTPolyParams>::null(), 0);
  76. // Outputing the vectors for clarity
  77. println!("Input x1: {}", _p_txt_1.GetString());
  78. println!("Input x2: {}", _p_txt_2.GetString());
  79. Encrypting Plaintext Vectors
  80. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  81. We encrypt the plaintext vectors using the generated public key.
  82. .. code-block:: rust
  83. // Encrypt plaintext vectors
  84. let _c1 = _cc.EncryptByPublicKey(&_key_pair.GetPublicKey(), &_p_txt_1);
  85. let _c2 = _cc.EncryptByPublicKey(&_key_pair.GetPublicKey(), &_p_txt_2);
  86. Performing Homomorphic Operations
  87. ----------------------------------
  88. We perform various homomorphic operations on the encrypted data, including addition, subtraction, multiplication by a constant, multiplication of ciphertexts, and rotations.
  89. .. code-block:: rust
  90. // Perform homomorphic operations
  91. let _c_add = _cc.EvalAddByCiphertexts(&_c1, &_c2);
  92. let _c_sub = _cc.EvalSubByCiphertexts(&_c1, &_c2);
  93. let _c_scalar = _cc.EvalMultByCiphertextAndConst(&_c1, 4.0);
  94. let _c_mul = _cc.EvalMultByCiphertexts(&_c1, &_c2);
  95. let _c_rot_1 = _cc.EvalRotate(&_c1, 1);
  96. let _c_rot_2 = _cc.EvalRotate(&_c1, -2);
  97. Decrypting and Printing Results
  98. --------------------------------
  99. Finally, we decrypt the results of the homomorphic computations and print them.
  100. .. code-block:: rust
  101. // Prepare for decryption
  102. let mut _result = ffi::GenNullPlainText();
  103. println!("\nResults of homomorphic computations:");
  104. // Decrypt and print results
  105. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c1, _result.pin_mut());
  106. _result.SetLength(_batch_size.try_into().unwrap());
  107. println!("x1 = {}Estimated precision in bits: {}", _result.GetString(), _result.GetLogPrecision());
  108. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_add, _result.pin_mut());
  109. _result.SetLength(_batch_size.try_into().unwrap());
  110. println!("x1 + x2 = {}Estimated precision in bits: {}",_result.GetString(), _result.GetLogPrecision());
  111. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_sub, _result.pin_mut());
  112. _result.SetLength(_batch_size.try_into().unwrap());
  113. println!("x1 - x2 = {}", _result.GetString());
  114. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_scalar, _result.pin_mut());
  115. _result.SetLength(_batch_size.try_into().unwrap());
  116. println!("4 * x1 = {}", _result.GetString());
  117. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_mul, _result.pin_mut());
  118. _result.SetLength(_batch_size.try_into().unwrap());
  119. println!("x1 * x2 = {}", _result.GetString());
  120. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_rot_1, _result.pin_mut());
  121. _result.SetLength(_batch_size.try_into().unwrap());
  122. println!("\nIn rotations, very small outputs (~10^-10 here) correspond to 0's:");
  123. println!("x1 rotate by 1 = {}", _result.GetString());
  124. _cc.DecryptByPrivateKeyAndCiphertext(&_key_pair.GetPrivateKey(), &_c_rot_2, _result.pin_mut());
  125. _result.SetLength(_batch_size.try_into().unwrap());
  126. println!("x1 rotate by -2 = {}", _result.GetString());
  127. Running the example
  128. --------------------
  129. 1. Ensure the `openfhe-rs` library is installed and properly configured, see the `Installation guide <../getting-started/installation.md>`_.
  130. 2. Go to the `examples` directory and make sure that the needed example is there - `simple_real_numbers.rs`.
  131. 3. Compile and run the Rust file:
  132. .. code-block:: sh
  133. rustc simple_real_numbers.rs -o simple_real_numbers
  134. ./simple_real_numbers
  135. This should output the results of the homomorphic computations to the console.