├── README.md ├── LICENSE └── src ├── examples.cpp ├── examples.h └── 8_squeezenet.cpp /README.md: -------------------------------------------------------------------------------- 1 | # HEMET 2 | This code is for testing the inference latency of HE-friendly SqueezeNet. 3 | 4 | # How to Run 5 | 6 | 1. Dowload the SEAL library (https://github.com/microsoft/SEAL). 7 | 2. Go into SEAL/native/examples and place all the codes in src/. 8 | 3. Build example codes and run the example project. 9 | 4. Input 8 in the console to run the source code 8-squeezenet.cpp. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 qianlou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/examples.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | #include "examples.h" 5 | 6 | using namespace std; 7 | using namespace seal; 8 | 9 | int main() 10 | { 11 | cout << "Microsoft SEAL version: " << SEAL_VERSION << endl; 12 | while (true) 13 | { 14 | cout << "+---------------------------------------------------------+" << endl; 15 | cout << "| The following examples should be executed while reading |" << endl; 16 | cout << "| comments in associated files in native/examples/. |" << endl; 17 | cout << "+---------------------------------------------------------+" << endl; 18 | cout << "| Examples | Source Files |" << endl; 19 | cout << "+----------------------------+----------------------------+" << endl; 20 | cout << "| 1. BFV Basics | 1_bfv_basics.cpp |" << endl; 21 | cout << "| 2. Encoders | 2_encoders.cpp |" << endl; 22 | cout << "| 3. Levels | 3_levels.cpp |" << endl; 23 | cout << "| 4. CKKS Basics | 4_ckks_basics.cpp |" << endl; 24 | cout << "| 5. Rotation | 5_rotation.cpp |" << endl; 25 | cout << "| 6. Serialization | 6_serialization.cpp |" << endl; 26 | cout << "| 7. Performance Test | 7_performance.cpp |" << endl; 27 | cout << "| 8. SqueezeNet Test | 8_squeezenet.cpp |" << endl; 28 | cout << "+----------------------------+----------------------------+" << endl; 29 | 30 | /* 31 | Print how much memory we have allocated from the current memory pool. 32 | By default the memory pool will be a static global pool and the 33 | MemoryManager class can be used to change it. Most users should have 34 | little or no reason to touch the memory allocation system. 35 | */ 36 | size_t megabytes = MemoryManager::GetPool().alloc_byte_count() >> 20; 37 | cout << "[" << setw(8) << right << megabytes << " MB] " 38 | << "Total allocation from the memory pool" << endl; 39 | 40 | int selection = 0; 41 | bool valid = true; 42 | do 43 | { 44 | cout << endl << "> Run example (1 ~ 10) or exit (0): "; 45 | if (!(cin >> selection)) 46 | { 47 | valid = false; 48 | } 49 | else if (selection < 0 || selection > 10) 50 | { 51 | valid = false; 52 | } 53 | else 54 | { 55 | valid = true; 56 | } 57 | if (!valid) 58 | { 59 | cout << " [Beep~~] valid option: type 0 ~ 10" << endl; 60 | cin.clear(); 61 | cin.ignore(numeric_limits::max(), '\n'); 62 | } 63 | } while (!valid); 64 | 65 | switch (selection) 66 | { 67 | case 1: 68 | example_bfv_basics(); 69 | break; 70 | 71 | case 2: 72 | example_encoders(); 73 | break; 74 | 75 | case 3: 76 | example_levels(); 77 | break; 78 | 79 | case 4: 80 | example_ckks_basics(); 81 | break; 82 | 83 | case 5: 84 | example_rotation(); 85 | break; 86 | 87 | case 6: 88 | example_serialization(); 89 | break; 90 | 91 | case 7: 92 | example_performance_test(); 93 | break; 94 | case 8: 95 | example_squeezenet(); 96 | break; 97 | //case 9: 98 | // example_ckks_our_act(); 99 | // break; 100 | //case 10: 101 | // example_squeezenet(); 102 | // break; 103 | case 0: 104 | return 0; 105 | } 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/examples.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | #pragma once 5 | 6 | #include "seal/seal.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | void example_bfv_basics(); 24 | 25 | void example_encoders(); 26 | 27 | void example_levels(); 28 | 29 | void example_ckks_basics(); 30 | 31 | void example_rotation(); 32 | 33 | void example_serialization(); 34 | 35 | void example_performance_test(); 36 | 37 | //void example_ckks_act(); 38 | 39 | //void example_ckks_our_act(); 40 | 41 | void example_squeezenet(); 42 | /* 43 | Helper function: Prints the name of the example in a fancy banner. 44 | */ 45 | inline void print_example_banner(std::string title) 46 | { 47 | if (!title.empty()) 48 | { 49 | std::size_t title_length = title.length(); 50 | std::size_t banner_length = title_length + 2 * 10; 51 | std::string banner_top = "+" + std::string(banner_length - 2, '-') + "+"; 52 | std::string banner_middle = "|" + std::string(9, ' ') + title + std::string(9, ' ') + "|"; 53 | 54 | std::cout << std::endl << banner_top << std::endl << banner_middle << std::endl << banner_top << std::endl; 55 | } 56 | } 57 | 58 | /* 59 | Helper function: Prints the parameters in a SEALContext. 60 | */ 61 | inline void print_parameters(std::shared_ptr context) 62 | { 63 | // Verify parameters 64 | if (!context) 65 | { 66 | throw std::invalid_argument("context is not set"); 67 | } 68 | auto &context_data = *context->key_context_data(); 69 | 70 | /* 71 | Which scheme are we using? 72 | */ 73 | std::string scheme_name; 74 | switch (context_data.parms().scheme()) 75 | { 76 | case seal::scheme_type::BFV: 77 | scheme_name = "BFV"; 78 | break; 79 | case seal::scheme_type::CKKS: 80 | scheme_name = "CKKS"; 81 | break; 82 | default: 83 | throw std::invalid_argument("unsupported scheme"); 84 | } 85 | std::cout << "/" << std::endl; 86 | std::cout << "| Encryption parameters :" << std::endl; 87 | std::cout << "| scheme: " << scheme_name << std::endl; 88 | std::cout << "| poly_modulus_degree: " << context_data.parms().poly_modulus_degree() << std::endl; 89 | 90 | /* 91 | Print the size of the true (product) coefficient modulus. 92 | */ 93 | std::cout << "| coeff_modulus size: "; 94 | std::cout << context_data.total_coeff_modulus_bit_count() << " ("; 95 | auto coeff_modulus = context_data.parms().coeff_modulus(); 96 | std::size_t coeff_modulus_size = coeff_modulus.size(); 97 | for (std::size_t i = 0; i < coeff_modulus_size - 1; i++) 98 | { 99 | std::cout << coeff_modulus[i].bit_count() << " + "; 100 | } 101 | std::cout << coeff_modulus.back().bit_count(); 102 | std::cout << ") bits" << std::endl; 103 | 104 | /* 105 | For the BFV scheme print the plain_modulus parameter. 106 | */ 107 | if (context_data.parms().scheme() == seal::scheme_type::BFV) 108 | { 109 | std::cout << "| plain_modulus: " << context_data.parms().plain_modulus().value() << std::endl; 110 | } 111 | 112 | std::cout << "\\" << std::endl; 113 | } 114 | 115 | /* 116 | Helper function: Prints the `parms_id' to std::ostream. 117 | */ 118 | inline std::ostream &operator<<(std::ostream &stream, seal::parms_id_type parms_id) 119 | { 120 | /* 121 | Save the formatting information for std::cout. 122 | */ 123 | std::ios old_fmt(nullptr); 124 | old_fmt.copyfmt(std::cout); 125 | 126 | stream << std::hex << std::setfill('0') << std::setw(16) << parms_id[0] << " " << std::setw(16) << parms_id[1] 127 | << " " << std::setw(16) << parms_id[2] << " " << std::setw(16) << parms_id[3] << " "; 128 | 129 | /* 130 | Restore the old std::cout formatting. 131 | */ 132 | std::cout.copyfmt(old_fmt); 133 | 134 | return stream; 135 | } 136 | 137 | /* 138 | Helper function: Prints a vector of floating-point values. 139 | */ 140 | template 141 | inline void print_vector(std::vector vec, std::size_t print_size = 4, int prec = 3) 142 | { 143 | /* 144 | Save the formatting information for std::cout. 145 | */ 146 | std::ios old_fmt(nullptr); 147 | old_fmt.copyfmt(std::cout); 148 | 149 | std::size_t slot_count = vec.size(); 150 | 151 | std::cout << std::fixed << std::setprecision(prec); 152 | std::cout << std::endl; 153 | if (slot_count <= 2 * print_size) 154 | { 155 | std::cout << " ["; 156 | for (std::size_t i = 0; i < slot_count; i++) 157 | { 158 | std::cout << " " << vec[i] << ((i != slot_count - 1) ? "," : " ]\n"); 159 | } 160 | } 161 | else 162 | { 163 | vec.resize(std::max(vec.size(), 2 * print_size)); 164 | std::cout << " ["; 165 | for (std::size_t i = 0; i < print_size; i++) 166 | { 167 | std::cout << " " << vec[i] << ","; 168 | } 169 | if (vec.size() > 2 * print_size) 170 | { 171 | std::cout << " ...,"; 172 | } 173 | for (std::size_t i = slot_count - print_size; i < slot_count; i++) 174 | { 175 | std::cout << " " << vec[i] << ((i != slot_count - 1) ? "," : " ]\n"); 176 | } 177 | } 178 | std::cout << std::endl; 179 | 180 | /* 181 | Restore the old std::cout formatting. 182 | */ 183 | std::cout.copyfmt(old_fmt); 184 | } 185 | 186 | /* 187 | Helper function: Prints a matrix of values. 188 | */ 189 | template 190 | inline void print_matrix(std::vector matrix, std::size_t row_size) 191 | { 192 | /* 193 | We're not going to print every column of the matrix (there are 2048). Instead 194 | print this many slots from beginning and end of the matrix. 195 | */ 196 | std::size_t print_size = 5; 197 | 198 | std::cout << std::endl; 199 | std::cout << " ["; 200 | for (std::size_t i = 0; i < print_size; i++) 201 | { 202 | std::cout << std::setw(3) << std::right << matrix[i] << ","; 203 | } 204 | std::cout << std::setw(3) << " ...,"; 205 | for (std::size_t i = row_size - print_size; i < row_size; i++) 206 | { 207 | std::cout << std::setw(3) << matrix[i] << ((i != row_size - 1) ? "," : " ]\n"); 208 | } 209 | std::cout << " ["; 210 | for (std::size_t i = row_size; i < row_size + print_size; i++) 211 | { 212 | std::cout << std::setw(3) << matrix[i] << ","; 213 | } 214 | std::cout << std::setw(3) << " ...,"; 215 | for (std::size_t i = 2 * row_size - print_size; i < 2 * row_size; i++) 216 | { 217 | std::cout << std::setw(3) << matrix[i] << ((i != 2 * row_size - 1) ? "," : " ]\n"); 218 | } 219 | std::cout << std::endl; 220 | } 221 | 222 | /* 223 | Helper function: Print line number. 224 | */ 225 | inline void print_line(int line_number) 226 | { 227 | std::cout << "Line " << std::setw(3) << line_number << " --> "; 228 | } 229 | -------------------------------------------------------------------------------- /src/8_squeezenet.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | #include "examples.h" 5 | 6 | using namespace std; 7 | using namespace seal; 8 | 9 | //void convolution(Ciphertext Ciph_input, Plaintext Plan_weights, int Kernel_size, Ciphertext Ciph_output, Evaluator Eva, GaloisKeys GK) 10 | //{ 11 | // Eva.multiply_plain(Ciph_input, Plan_weights, Ciph_output); 12 | // Ciphertext Rotated_tmp, Result_tmp; 13 | // for (int i = 1; i < Kernel_size; i++) 14 | // { 15 | // Eva.rotate_vector(Ciph_input, i, GK, Rotated_tmp); 16 | // Eva.multiply_plain(Rotated_tmp, Plan_weights, Result_tmp); 17 | // Eva.add_inplace(Ciph_output, Result_tmp); 18 | // } 19 | //} 20 | 21 | 22 | 23 | void squeeze() 24 | { 25 | 26 | chrono::high_resolution_clock::time_point time_start, time_end; 27 | chrono::microseconds time_diff; 28 | EncryptionParameters parms(scheme_type::CKKS); 29 | 30 | size_t poly_modulus_degree = 8192*8 ; 31 | parms.set_poly_modulus_degree(poly_modulus_degree); 32 | parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, {60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60})); 33 | 34 | double input_scale = pow(2.0, 25); 35 | double weight_scale = pow(2.0, 30); 36 | double scalar_scale = pow(2.0, 10); 37 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 38 | print_parameters(context); 39 | cout << endl; 40 | 41 | KeyGenerator keygen(context); 42 | auto public_key = keygen.public_key(); 43 | auto secret_key = keygen.secret_key(); 44 | auto relin_keys = keygen.relin_keys_local(); 45 | GaloisKeys gal_keys = keygen.galois_keys_local(); 46 | Encryptor encryptor(context, public_key); 47 | Evaluator evaluator(context); 48 | Decryptor decryptor(context, secret_key); 49 | 50 | CKKSEncoder encoder(context); 51 | size_t slot_count = encoder.slot_count(); 52 | cout << "Number of slots: " << slot_count << endl; 53 | 54 | vector input; 55 | input.reserve(slot_count); 56 | double curr_point = 0; 57 | double step_size = 1.0 / (static_cast(slot_count) - 1); 58 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 59 | { 60 | input.push_back(curr_point); 61 | } 62 | cout << "Input vector: " << endl; 63 | print_vector(input, 3, 7); 64 | 65 | Plaintext plain_coeff3, plain_coeff0; 66 | //encoder.encode(3.14159265, scale, plain_coeff3); 67 | encoder.encode(0.4, weight_scale, plain_coeff3); 68 | encoder.encode(1.0, scalar_scale, plain_coeff0); 69 | 70 | Plaintext x_plain; 71 | print_line(__LINE__); 72 | cout << "Encode input vectors." << endl; 73 | encoder.encode(input, input_scale, x_plain); 74 | Ciphertext x1_encrypted; 75 | encryptor.encrypt(x_plain, x1_encrypted); 76 | 77 | 78 | Ciphertext y_encrypted; 79 | print_line(__LINE__); 80 | 81 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 2.048, 40.960, 4.096, 40.960, 2.560, 1.280 }; 82 | double Rot_number[13] = { 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.064, 0.320, 0.128, 0.320, 0.256, 0.128}; 83 | double Rot_Cost[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 84 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 85 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 86 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 87 | 88 | 89 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); //25+30=55, y_encrypted has 3 entries. 90 | Ciphertext Rotated_tmp, Result_tmp; 91 | int run_times = 10; 92 | for (int i = 1; i < run_times; i++) 93 | { 94 | time_start = chrono::high_resolution_clock::now(); 95 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 96 | time_end = chrono::high_resolution_clock::now(); 97 | time_diff = chrono::duration_cast(time_end - time_start); 98 | Rot_latency[0] += time_diff.count(); 99 | 100 | time_start = chrono::high_resolution_clock::now(); 101 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); //25+30=55, Result_tmp has 3 entries. 102 | evaluator.add_inplace(y_encrypted, Result_tmp); 103 | time_end = chrono::high_resolution_clock::now(); 104 | time_diff = chrono::duration_cast(time_end - time_start); 105 | Mul_latency[0] += time_diff.count(); 106 | } 107 | Rot_latency[0] = Rot_latency[0] / run_times; 108 | Mul_latency[0] = Mul_latency[0] / run_times; 109 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 110 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 111 | evaluator.relinearize_inplace(y_encrypted, relin_keys); //25+30=55, y_encrypted has 2 entries. 112 | 113 | 114 | evaluator.square_inplace(y_encrypted); // 55^2=110 115 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 116 | evaluator.rescale_to_next_inplace(y_encrypted);//110-60=50 117 | //cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 118 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 119 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 120 | evaluator.multiply_plain_inplace(y_encrypted,plain_coeff0);//50+10=60 121 | evaluator.relinearize_inplace(y_encrypted, relin_keys);// 122 | 123 | Ciphertext y1_encrypted = y_encrypted; 124 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 125 | for (int i = 1; i < run_times; i++) 126 | { 127 | time_start = chrono::high_resolution_clock::now(); 128 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 129 | time_end = chrono::high_resolution_clock::now(); 130 | time_diff = chrono::duration_cast(time_end - time_start); 131 | Rot_latency[1] += time_diff.count(); 132 | 133 | time_start = chrono::high_resolution_clock::now(); 134 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 135 | evaluator.add_inplace(y_encrypted, Result_tmp); 136 | time_end = chrono::high_resolution_clock::now(); 137 | time_diff = chrono::duration_cast(time_end - time_start); 138 | Mul_latency[1] += time_diff.count(); 139 | } 140 | Rot_latency[1] = Rot_latency[1] / run_times; 141 | Mul_latency[1] = Mul_latency[1] / run_times; 142 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 143 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 144 | 145 | 146 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 147 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 148 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 149 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 150 | 151 | y1_encrypted = y_encrypted; 152 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 153 | for (int i = 1; i < run_times; i++) 154 | { 155 | time_start = chrono::high_resolution_clock::now(); 156 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 157 | time_end = chrono::high_resolution_clock::now(); 158 | time_diff = chrono::duration_cast(time_end - time_start); 159 | Rot_latency[2] += time_diff.count(); 160 | 161 | time_start = chrono::high_resolution_clock::now(); 162 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 163 | evaluator.add_inplace(y_encrypted, Result_tmp); 164 | time_end = chrono::high_resolution_clock::now(); 165 | time_diff = chrono::duration_cast(time_end - time_start); 166 | Mul_latency[2] += time_diff.count(); 167 | } 168 | Rot_latency[2] = Rot_latency[2] / run_times; 169 | Mul_latency[2] = Mul_latency[2] / run_times; 170 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 171 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 172 | 173 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 174 | 175 | 176 | evaluator.square_inplace(y_encrypted); // 60^2=120 177 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 178 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 179 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 180 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 181 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 182 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 183 | 184 | 185 | y1_encrypted = y_encrypted; 186 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 187 | for (int i = 1; i < run_times; i++) 188 | { 189 | time_start = chrono::high_resolution_clock::now(); 190 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 191 | time_end = chrono::high_resolution_clock::now(); 192 | time_diff = chrono::duration_cast(time_end - time_start); 193 | Rot_latency[3] += time_diff.count(); 194 | 195 | time_start = chrono::high_resolution_clock::now(); 196 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 197 | evaluator.add_inplace(y_encrypted, Result_tmp); 198 | time_end = chrono::high_resolution_clock::now(); 199 | time_diff = chrono::duration_cast(time_end - time_start); 200 | Mul_latency[3] += time_diff.count(); 201 | } 202 | Rot_latency[3] = Rot_latency[3] / run_times; 203 | Mul_latency[3] = Mul_latency[3] / run_times; 204 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 205 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 206 | 207 | 208 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 209 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 210 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 211 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 212 | 213 | 214 | 215 | evaluator.square_inplace(y_encrypted); // 40^2=80 216 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 217 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 218 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 219 | evaluator.rescale_to_next_inplace(y_encrypted); 220 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 221 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 222 | 223 | 224 | y1_encrypted = y_encrypted; 225 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 226 | 227 | for (int i = 1; i < run_times; i++) 228 | { 229 | time_start = chrono::high_resolution_clock::now(); 230 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 231 | time_end = chrono::high_resolution_clock::now(); 232 | time_diff = chrono::duration_cast(time_end - time_start); 233 | Rot_latency[4] += time_diff.count(); 234 | 235 | time_start = chrono::high_resolution_clock::now(); 236 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 237 | evaluator.add_inplace(y_encrypted, Result_tmp); 238 | time_end = chrono::high_resolution_clock::now(); 239 | time_diff = chrono::duration_cast(time_end - time_start); 240 | Mul_latency[4] += time_diff.count(); 241 | } 242 | 243 | Rot_latency[4] = Rot_latency[4] / run_times; 244 | Mul_latency[4] = Mul_latency[4] / run_times; 245 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 246 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 247 | 248 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 249 | 250 | evaluator.square_inplace(y_encrypted); // 60^2=120 251 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 252 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 253 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 254 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 255 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 256 | 257 | y1_encrypted = y_encrypted; 258 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 259 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 260 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 261 | for (int i = 1; i < run_times; i++) 262 | { 263 | time_start = chrono::high_resolution_clock::now(); 264 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 265 | time_end = chrono::high_resolution_clock::now(); 266 | time_diff = chrono::duration_cast(time_end - time_start); 267 | Rot_latency[5] += time_diff.count(); 268 | 269 | time_start = chrono::high_resolution_clock::now(); 270 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 271 | evaluator.add_inplace(y_encrypted, Result_tmp); 272 | time_end = chrono::high_resolution_clock::now(); 273 | time_diff = chrono::duration_cast(time_end - time_start); 274 | Mul_latency[5] += time_diff.count(); 275 | } 276 | Rot_latency[5] = Rot_latency[5] / run_times; 277 | Mul_latency[5] = Mul_latency[5] / run_times; 278 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 279 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 280 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 281 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 282 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 283 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 284 | 285 | 286 | evaluator.square_inplace(y_encrypted); // 40^2=80 287 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 288 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 289 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 290 | time_end = chrono::high_resolution_clock::now(); 291 | evaluator.rescale_to_next_inplace(y_encrypted); 292 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 293 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 294 | time_diff = chrono::duration_cast(time_end - time_start); 295 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 296 | 297 | y1_encrypted = y_encrypted; 298 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 299 | 300 | for (int i = 1; i < run_times; i++) 301 | { 302 | time_start = chrono::high_resolution_clock::now(); 303 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 304 | time_end = chrono::high_resolution_clock::now(); 305 | time_diff = chrono::duration_cast(time_end - time_start); 306 | Rot_latency[6] += time_diff.count(); 307 | 308 | time_start = chrono::high_resolution_clock::now(); 309 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 310 | evaluator.add_inplace(y_encrypted, Result_tmp); 311 | time_end = chrono::high_resolution_clock::now(); 312 | time_diff = chrono::duration_cast(time_end - time_start); 313 | Mul_latency[6] += time_diff.count(); 314 | } 315 | Rot_latency[6] = Rot_latency[6] / run_times; 316 | Mul_latency[6] = Mul_latency[6] / run_times; 317 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 318 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 319 | 320 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 321 | y1_encrypted = y_encrypted; 322 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 323 | 324 | for (int i = 1; i < run_times; i++) 325 | { 326 | time_start = chrono::high_resolution_clock::now(); 327 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 328 | time_end = chrono::high_resolution_clock::now(); 329 | time_diff = chrono::duration_cast(time_end - time_start); 330 | Rot_latency[7] += time_diff.count(); 331 | 332 | time_start = chrono::high_resolution_clock::now(); 333 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 334 | evaluator.add_inplace(y_encrypted, Result_tmp); 335 | time_end = chrono::high_resolution_clock::now(); 336 | time_diff = chrono::duration_cast(time_end - time_start); 337 | Mul_latency[7] += time_diff.count(); 338 | } 339 | Rot_latency[7] = Rot_latency[7] / run_times; 340 | Mul_latency[7] = Mul_latency[7] / run_times; 341 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 342 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 343 | 344 | 345 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 346 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 347 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 348 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 349 | 350 | 351 | evaluator.square_inplace(y_encrypted); // 30^2=60 352 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 353 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 354 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 355 | 356 | y1_encrypted = y_encrypted; 357 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 358 | for (int i = 1; i < run_times; i++) 359 | { 360 | time_start = chrono::high_resolution_clock::now(); 361 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 362 | time_end = chrono::high_resolution_clock::now(); 363 | time_diff = chrono::duration_cast(time_end - time_start); 364 | Rot_latency[8] += time_diff.count(); 365 | 366 | time_start = chrono::high_resolution_clock::now(); 367 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 368 | evaluator.add_inplace(y_encrypted, Result_tmp); 369 | time_end = chrono::high_resolution_clock::now(); 370 | time_diff = chrono::duration_cast(time_end - time_start); 371 | Mul_latency[8] += time_diff.count(); 372 | } 373 | Rot_latency[8] = Rot_latency[8] / run_times; 374 | Mul_latency[8] = Mul_latency[8] / run_times; 375 | Rot_Cost[8] = Rot_latency[8] * Rot_number[8]; 376 | Mul_Cost[8] = Mul_latency[8] * Mul_number[8]; 377 | 378 | 379 | 380 | 381 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 382 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 383 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 384 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 385 | 386 | 387 | evaluator.square_inplace(y_encrypted); // 40^2=80 388 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 389 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 390 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 391 | evaluator.rescale_to_next_inplace(y_encrypted); 392 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 393 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 394 | 395 | 396 | y1_encrypted = y_encrypted; 397 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 398 | for (int i = 1; i < run_times; i++) 399 | { 400 | time_start = chrono::high_resolution_clock::now(); 401 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 402 | time_end = chrono::high_resolution_clock::now(); 403 | time_diff = chrono::duration_cast(time_end - time_start); 404 | Rot_latency[9] += time_diff.count(); 405 | 406 | time_start = chrono::high_resolution_clock::now(); 407 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 408 | evaluator.add_inplace(y_encrypted, Result_tmp); 409 | time_end = chrono::high_resolution_clock::now(); 410 | time_diff = chrono::duration_cast(time_end - time_start); 411 | Mul_latency[9] += time_diff.count(); 412 | } 413 | Rot_latency[9] = Rot_latency[9] / run_times; 414 | Mul_latency[9] = Mul_latency[9] / run_times; 415 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 416 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 417 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 418 | //cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 419 | 420 | 421 | evaluator.square_inplace(y_encrypted); // 60^2=120 422 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 423 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 424 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 425 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 426 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 427 | //cout << "#### The ReLU8 Done [" << time_diff.count() << " microseconds]" << endl; 428 | 429 | y1_encrypted = y_encrypted; 430 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 431 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 432 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 433 | for (int i = 1; i < run_times; i++) 434 | { 435 | time_start = chrono::high_resolution_clock::now(); 436 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 437 | time_end = chrono::high_resolution_clock::now(); 438 | time_diff = chrono::duration_cast(time_end - time_start); 439 | Rot_latency[10] += time_diff.count(); 440 | 441 | time_start = chrono::high_resolution_clock::now(); 442 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 443 | evaluator.add_inplace(y_encrypted, Result_tmp); 444 | time_end = chrono::high_resolution_clock::now(); 445 | time_diff = chrono::duration_cast(time_end - time_start); 446 | Mul_latency[10] += time_diff.count(); 447 | } 448 | Rot_latency[10] = Rot_latency[10] / run_times; 449 | Mul_latency[10] = Mul_latency[10] / run_times; 450 | Rot_Cost[10] = Rot_latency[10] * Rot_number[10]; 451 | Mul_Cost[10] = Mul_latency[10] * Mul_number[10]; 452 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 453 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 454 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 455 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 456 | 457 | 458 | evaluator.square_inplace(y_encrypted); // 40^2=80 459 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 460 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 461 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 462 | evaluator.rescale_to_next_inplace(y_encrypted); 463 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 464 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 465 | 466 | y1_encrypted = y_encrypted; 467 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 468 | for (int i = 1; i < run_times; i++) 469 | { 470 | time_start = chrono::high_resolution_clock::now(); 471 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 472 | time_end = chrono::high_resolution_clock::now(); 473 | time_diff = chrono::duration_cast(time_end - time_start); 474 | Rot_latency[11] += time_diff.count(); 475 | 476 | time_start = chrono::high_resolution_clock::now(); 477 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 478 | evaluator.add_inplace(y_encrypted, Result_tmp); 479 | time_end = chrono::high_resolution_clock::now(); 480 | time_diff = chrono::duration_cast(time_end - time_start); 481 | Mul_latency[11] += time_diff.count(); 482 | } 483 | Rot_latency[11] = Rot_latency[11] / run_times; 484 | Mul_latency[11] = Mul_latency[11] / run_times; 485 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 486 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 487 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 488 | 489 | y1_encrypted = y_encrypted; 490 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 491 | for (int i = 1; i < run_times; i++) 492 | { 493 | time_start = chrono::high_resolution_clock::now(); 494 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 495 | time_end = chrono::high_resolution_clock::now(); 496 | time_diff = chrono::duration_cast(time_end - time_start); 497 | Rot_latency[12] += time_diff.count(); 498 | 499 | time_start = chrono::high_resolution_clock::now(); 500 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 501 | evaluator.add_inplace(y_encrypted, Result_tmp); 502 | time_end = chrono::high_resolution_clock::now(); 503 | time_diff = chrono::duration_cast(time_end - time_start); 504 | Mul_latency[12] += time_diff.count(); 505 | } 506 | Rot_latency[12] = Rot_latency[12] / run_times; 507 | Mul_latency[12] = Mul_latency[12] / run_times; 508 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 509 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 510 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 511 | time_end = chrono::high_resolution_clock::now(); 512 | time_diff = chrono::duration_cast(time_end - time_start); 513 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-30=60, Result_tmp has 2 entries. 514 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 515 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 516 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 517 | 518 | for (int i = 0; i < 13; i++) 519 | { 520 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 521 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 522 | } 523 | 524 | double Rot_latency_total = 0.0; 525 | double Mult_latency_total = 0.0; 526 | for (int i = 0; i < 13; i++) 527 | { 528 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 529 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 530 | Rot_latency_total += Rot_Cost[i]; 531 | Mult_latency_total += Mul_Cost[i]; 532 | } 533 | 534 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 535 | << " Mult latency is " << +Mult_latency_total << " ms]" 536 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 537 | } 538 | 539 | 540 | void squeeze_relinearize() 541 | { 542 | chrono::high_resolution_clock::time_point time_start, time_end; 543 | chrono::microseconds time_diff; 544 | EncryptionParameters parms(scheme_type::CKKS); 545 | 546 | size_t poly_modulus_degree = 8192 * 8; 547 | parms.set_poly_modulus_degree(poly_modulus_degree); 548 | parms.set_coeff_modulus(CoeffModulus::Create( 549 | poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 550 | 551 | double input_scale = pow(2.0, 25); 552 | double weight_scale = pow(2.0, 30); 553 | double scalar_scale = pow(2.0, 10); 554 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 555 | print_parameters(context); 556 | cout << endl; 557 | 558 | KeyGenerator keygen(context); 559 | auto public_key = keygen.public_key(); 560 | auto secret_key = keygen.secret_key(); 561 | auto relin_keys = keygen.relin_keys_local(); 562 | GaloisKeys gal_keys = keygen.galois_keys_local(); 563 | Encryptor encryptor(context, public_key); 564 | Evaluator evaluator(context); 565 | Decryptor decryptor(context, secret_key); 566 | 567 | CKKSEncoder encoder(context); 568 | size_t slot_count = encoder.slot_count(); 569 | cout << "Number of slots: " << slot_count << endl; 570 | 571 | vector input; 572 | input.reserve(slot_count); 573 | double curr_point = 0; 574 | double step_size = 1.0 / (static_cast(slot_count) - 1); 575 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 576 | { 577 | input.push_back(curr_point); 578 | } 579 | cout << "Input vector: " << endl; 580 | print_vector(input, 3, 7); 581 | 582 | Plaintext plain_coeff3, plain_coeff0; 583 | // encoder.encode(3.14159265, scale, plain_coeff3); 584 | encoder.encode(0.4, weight_scale, plain_coeff3); 585 | encoder.encode(1.0, scalar_scale, plain_coeff0); 586 | 587 | Plaintext x_plain; 588 | print_line(__LINE__); 589 | cout << "Encode input vectors." << endl; 590 | encoder.encode(input, input_scale, x_plain); 591 | Ciphertext x1_encrypted; 592 | encryptor.encrypt(x_plain, x1_encrypted); 593 | 594 | Ciphertext y_encrypted; 595 | print_line(__LINE__); 596 | 597 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 598 | 2.048, 40.960, 4.096, 40.960, 2.560, 1.280 }; 599 | double Rot_number[13] = { 600 | 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.064, 0.320, 0.128, 0.320, 0.256, 0.128 601 | }; 602 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 603 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 604 | double Rel_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 605 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 606 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 607 | double Rel_latency[13] = {0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 608 | 609 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+30=55, y_encrypted has 3 entries. 610 | Ciphertext Rotated_tmp, Result_tmp; 611 | int run_times = 10; 612 | for (int i = 1; i < run_times; i++) 613 | { 614 | time_start = chrono::high_resolution_clock::now(); 615 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 616 | time_end = chrono::high_resolution_clock::now(); 617 | time_diff = chrono::duration_cast(time_end - time_start); 618 | Rot_latency[0] += time_diff.count(); 619 | 620 | time_start = chrono::high_resolution_clock::now(); 621 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+30=55, Result_tmp has 3 entries. 622 | evaluator.add_inplace(y_encrypted, Result_tmp); 623 | time_end = chrono::high_resolution_clock::now(); 624 | time_diff = chrono::duration_cast(time_end - time_start); 625 | Mul_latency[0] += time_diff.count(); 626 | 627 | time_start = chrono::high_resolution_clock::now(); 628 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+30=55, y_encrypted has 2 entries. 629 | time_end = chrono::high_resolution_clock::now(); 630 | time_diff = chrono::duration_cast(time_end - time_start); 631 | Rel_latency[0] += time_diff.count(); 632 | } 633 | Rot_latency[0] = Rot_latency[0] / run_times; 634 | Mul_latency[0] = Mul_latency[0] / run_times; 635 | Rel_latency[0] = Rel_latency[0] / run_times; 636 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 637 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 638 | Rel_Cost[0] = Rel_latency[0] * Mul_number[0]; 639 | 640 | 641 | evaluator.square_inplace(y_encrypted); // 55^2=110 642 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 643 | evaluator.rescale_to_next_inplace(y_encrypted); // 110-60=50 644 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 645 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 646 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 647 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 50+10=60 648 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 649 | 650 | 651 | Ciphertext y1_encrypted = y_encrypted; 652 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 653 | for (int i = 1; i < run_times; i++) 654 | { 655 | time_start = chrono::high_resolution_clock::now(); 656 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 657 | time_end = chrono::high_resolution_clock::now(); 658 | time_diff = chrono::duration_cast(time_end - time_start); 659 | Rot_latency[1] += time_diff.count(); 660 | 661 | time_start = chrono::high_resolution_clock::now(); 662 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 663 | evaluator.add_inplace(y_encrypted, Result_tmp); 664 | time_end = chrono::high_resolution_clock::now(); 665 | time_diff = chrono::duration_cast(time_end - time_start); 666 | Mul_latency[1] += time_diff.count(); 667 | 668 | time_start = chrono::high_resolution_clock::now(); 669 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 670 | time_end = chrono::high_resolution_clock::now(); 671 | time_diff = chrono::duration_cast(time_end - time_start); 672 | Rel_latency[1] += time_diff.count(); 673 | } 674 | Rot_latency[1] = Rot_latency[1] / run_times; 675 | Mul_latency[1] = Mul_latency[1] / run_times; 676 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 677 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 678 | 679 | Rel_latency[1] = Rel_latency[1] / run_times; 680 | Rel_Cost[1] = Rel_latency[1] * Mul_number[1]; 681 | 682 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 683 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 684 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 685 | 686 | y1_encrypted = y_encrypted; 687 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 688 | for (int i = 1; i < run_times; i++) 689 | { 690 | time_start = chrono::high_resolution_clock::now(); 691 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 692 | time_end = chrono::high_resolution_clock::now(); 693 | time_diff = chrono::duration_cast(time_end - time_start); 694 | Rot_latency[2] += time_diff.count(); 695 | 696 | time_start = chrono::high_resolution_clock::now(); 697 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 698 | evaluator.add_inplace(y_encrypted, Result_tmp); 699 | time_end = chrono::high_resolution_clock::now(); 700 | time_diff = chrono::duration_cast(time_end - time_start); 701 | Mul_latency[2] += time_diff.count(); 702 | 703 | time_start = chrono::high_resolution_clock::now(); 704 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 705 | time_end = chrono::high_resolution_clock::now(); 706 | time_diff = chrono::duration_cast(time_end - time_start); 707 | Rel_latency[2] += time_diff.count(); 708 | 709 | } 710 | Rot_latency[2] = Rot_latency[2] / run_times; 711 | Mul_latency[2] = Mul_latency[2] / run_times; 712 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 713 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 714 | Rel_latency[2] = Rel_latency[2] / run_times; 715 | Rel_Cost[2] = Rel_latency[2] * Mul_number[2]; 716 | 717 | cout << "#### The Squeeze1 Done [" 718 | << " ms]" << endl; 719 | 720 | evaluator.square_inplace(y_encrypted); // 60^2=120 721 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 722 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 723 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 724 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 725 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 726 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 727 | // cout << "#### The ReLU2 Done [" << time_diff.count() << " microseconds]" << endl; 728 | 729 | y1_encrypted = y_encrypted; 730 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 731 | for (int i = 1; i < run_times; i++) 732 | { 733 | time_start = chrono::high_resolution_clock::now(); 734 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 735 | time_end = chrono::high_resolution_clock::now(); 736 | time_diff = chrono::duration_cast(time_end - time_start); 737 | Rot_latency[3] += time_diff.count(); 738 | 739 | time_start = chrono::high_resolution_clock::now(); 740 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 741 | evaluator.add_inplace(y_encrypted, Result_tmp); 742 | time_end = chrono::high_resolution_clock::now(); 743 | time_diff = chrono::duration_cast(time_end - time_start); 744 | Mul_latency[3] += time_diff.count(); 745 | 746 | time_start = chrono::high_resolution_clock::now(); 747 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 748 | time_end = chrono::high_resolution_clock::now(); 749 | time_diff = chrono::duration_cast(time_end - time_start); 750 | Rel_latency[3] += time_diff.count(); 751 | 752 | } 753 | Rot_latency[3] = Rot_latency[3] / run_times; 754 | Mul_latency[3] = Mul_latency[3] / run_times; 755 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 756 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 757 | Rel_latency[3] = Rel_latency[3] / run_times; 758 | Rel_Cost[3] = Rel_latency[3] * Mul_number[3]; 759 | 760 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 761 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 762 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 763 | 764 | 765 | evaluator.square_inplace(y_encrypted); // 40^2=80 766 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 767 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 768 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 769 | evaluator.rescale_to_next_inplace(y_encrypted); 770 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 771 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 772 | 773 | 774 | y1_encrypted = y_encrypted; 775 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 776 | 777 | for (int i = 1; i < run_times; i++) 778 | { 779 | time_start = chrono::high_resolution_clock::now(); 780 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 781 | time_end = chrono::high_resolution_clock::now(); 782 | time_diff = chrono::duration_cast(time_end - time_start); 783 | Rot_latency[4] += time_diff.count(); 784 | 785 | time_start = chrono::high_resolution_clock::now(); 786 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 787 | evaluator.add_inplace(y_encrypted, Result_tmp); 788 | time_end = chrono::high_resolution_clock::now(); 789 | time_diff = chrono::duration_cast(time_end - time_start); 790 | Mul_latency[4] += time_diff.count(); 791 | 792 | time_start = chrono::high_resolution_clock::now(); 793 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 794 | time_end = chrono::high_resolution_clock::now(); 795 | time_diff = chrono::duration_cast(time_end - time_start); 796 | Rel_latency[4] += time_diff.count(); 797 | } 798 | 799 | Rot_latency[4] = Rot_latency[4] / run_times; 800 | Mul_latency[4] = Mul_latency[4] / run_times; 801 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 802 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 803 | Rel_latency[4] = Rel_latency[4] / run_times; 804 | Rel_Cost[4] = Rel_latency[4] * Mul_number[4]; 805 | 806 | 807 | evaluator.square_inplace(y_encrypted); // 60^2=120 808 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 809 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 810 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 811 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 812 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 813 | 814 | y1_encrypted = y_encrypted; 815 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 816 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 817 | for (int i = 1; i < run_times; i++) 818 | { 819 | time_start = chrono::high_resolution_clock::now(); 820 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 821 | time_end = chrono::high_resolution_clock::now(); 822 | time_diff = chrono::duration_cast(time_end - time_start); 823 | Rot_latency[5] += time_diff.count(); 824 | 825 | time_start = chrono::high_resolution_clock::now(); 826 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 827 | evaluator.add_inplace(y_encrypted, Result_tmp); 828 | time_end = chrono::high_resolution_clock::now(); 829 | time_diff = chrono::duration_cast(time_end - time_start); 830 | Mul_latency[5] += time_diff.count(); 831 | 832 | time_start = chrono::high_resolution_clock::now(); 833 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 834 | time_end = chrono::high_resolution_clock::now(); 835 | time_diff = chrono::duration_cast(time_end - time_start); 836 | Rel_latency[5] += time_diff.count(); 837 | } 838 | Rot_latency[5] = Rot_latency[5] / run_times; 839 | Mul_latency[5] = Mul_latency[5] / run_times; 840 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 841 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 842 | Rel_latency[5] = Rel_latency[5] / run_times; 843 | Rel_Cost[5] = Rel_latency[5] * Mul_number[5]; 844 | 845 | 846 | 847 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 848 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 849 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 850 | 851 | evaluator.square_inplace(y_encrypted); // 40^2=80 852 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 853 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 854 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 855 | time_end = chrono::high_resolution_clock::now(); 856 | evaluator.rescale_to_next_inplace(y_encrypted); 857 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 858 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 859 | time_diff = chrono::duration_cast(time_end - time_start); 860 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 861 | 862 | y1_encrypted = y_encrypted; 863 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 864 | 865 | for (int i = 1; i < run_times; i++) 866 | { 867 | time_start = chrono::high_resolution_clock::now(); 868 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 869 | time_end = chrono::high_resolution_clock::now(); 870 | time_diff = chrono::duration_cast(time_end - time_start); 871 | Rot_latency[6] += time_diff.count(); 872 | 873 | time_start = chrono::high_resolution_clock::now(); 874 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 875 | evaluator.add_inplace(y_encrypted, Result_tmp); 876 | time_end = chrono::high_resolution_clock::now(); 877 | time_diff = chrono::duration_cast(time_end - time_start); 878 | Mul_latency[6] += time_diff.count(); 879 | 880 | time_start = chrono::high_resolution_clock::now(); 881 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 882 | time_end = chrono::high_resolution_clock::now(); 883 | time_diff = chrono::duration_cast(time_end - time_start); 884 | Rel_latency[6] += time_diff.count(); 885 | 886 | } 887 | Rot_latency[6] = Rot_latency[6] / run_times; 888 | Mul_latency[6] = Mul_latency[6] / run_times; 889 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 890 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 891 | Rel_latency[6] = Rel_latency[6] / run_times; 892 | Rel_Cost[6] = Rel_latency[6] * Mul_number[6]; 893 | 894 | y1_encrypted = y_encrypted; 895 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 896 | 897 | for (int i = 1; i < run_times; i++) 898 | { 899 | time_start = chrono::high_resolution_clock::now(); 900 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 901 | time_end = chrono::high_resolution_clock::now(); 902 | time_diff = chrono::duration_cast(time_end - time_start); 903 | Rot_latency[7] += time_diff.count(); 904 | 905 | time_start = chrono::high_resolution_clock::now(); 906 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 907 | evaluator.add_inplace(y_encrypted, Result_tmp); 908 | time_end = chrono::high_resolution_clock::now(); 909 | time_diff = chrono::duration_cast(time_end - time_start); 910 | Mul_latency[7] += time_diff.count(); 911 | 912 | time_start = chrono::high_resolution_clock::now(); 913 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 914 | time_end = chrono::high_resolution_clock::now(); 915 | time_diff = chrono::duration_cast(time_end - time_start); 916 | Rel_latency[7] += time_diff.count(); 917 | 918 | } 919 | Rot_latency[7] = Rot_latency[7] / run_times; 920 | Mul_latency[7] = Mul_latency[7] / run_times; 921 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 922 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 923 | Rel_latency[7] = Rel_latency[7] / run_times; 924 | Rel_Cost[7] = Rel_latency[7] * Mul_number[7]; 925 | 926 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 927 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 928 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 929 | 930 | evaluator.square_inplace(y_encrypted); // 30^2=60 931 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 932 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 933 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 934 | 935 | y1_encrypted = y_encrypted; 936 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 937 | for (int i = 1; i < run_times; i++) 938 | { 939 | time_start = chrono::high_resolution_clock::now(); 940 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 941 | time_end = chrono::high_resolution_clock::now(); 942 | time_diff = chrono::duration_cast(time_end - time_start); 943 | Rot_latency[8] += time_diff.count(); 944 | 945 | time_start = chrono::high_resolution_clock::now(); 946 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 947 | evaluator.add_inplace(y_encrypted, Result_tmp); 948 | time_end = chrono::high_resolution_clock::now(); 949 | time_diff = chrono::duration_cast(time_end - time_start); 950 | Mul_latency[8] += time_diff.count(); 951 | 952 | time_start = chrono::high_resolution_clock::now(); 953 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 954 | time_end = chrono::high_resolution_clock::now(); 955 | time_diff = chrono::duration_cast(time_end - time_start); 956 | Rel_latency[8] += time_diff.count(); 957 | 958 | } 959 | Rot_latency[8] = Rot_latency[8] / run_times; 960 | Mul_latency[8] = Mul_latency[8] / run_times; 961 | Rot_Cost[8] = Rot_latency[8] * Rot_number[8]; 962 | Mul_Cost[8] = Mul_latency[8] * Mul_number[8]; 963 | Rel_latency[8] = Rel_latency[8] / run_times; 964 | Rel_Cost[8] = Rel_latency[8] * Mul_number[8]; 965 | 966 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 967 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 968 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 969 | 970 | 971 | evaluator.square_inplace(y_encrypted); // 40^2=80 972 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 973 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 974 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 975 | evaluator.rescale_to_next_inplace(y_encrypted); 976 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 977 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 978 | 979 | 980 | y1_encrypted = y_encrypted; 981 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 982 | for (int i = 1; i < run_times; i++) 983 | { 984 | time_start = chrono::high_resolution_clock::now(); 985 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 986 | time_end = chrono::high_resolution_clock::now(); 987 | time_diff = chrono::duration_cast(time_end - time_start); 988 | Rot_latency[9] += time_diff.count(); 989 | 990 | time_start = chrono::high_resolution_clock::now(); 991 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 992 | evaluator.add_inplace(y_encrypted, Result_tmp); 993 | time_end = chrono::high_resolution_clock::now(); 994 | time_diff = chrono::duration_cast(time_end - time_start); 995 | Mul_latency[9] += time_diff.count(); 996 | 997 | time_start = chrono::high_resolution_clock::now(); 998 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 999 | time_end = chrono::high_resolution_clock::now(); 1000 | time_diff = chrono::duration_cast(time_end - time_start); 1001 | Rel_latency[9] += time_diff.count(); 1002 | 1003 | } 1004 | Rot_latency[9] = Rot_latency[9] / run_times; 1005 | Mul_latency[9] = Mul_latency[9] / run_times; 1006 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 1007 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 1008 | Rel_latency[9] = Rel_latency[9] / run_times; 1009 | Rel_Cost[9] = Rel_latency[9] * Mul_number[9]; 1010 | 1011 | 1012 | evaluator.square_inplace(y_encrypted); // 60^2=120 1013 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1014 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1015 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1016 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1017 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1018 | 1019 | y1_encrypted = y_encrypted; 1020 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1021 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1022 | for (int i = 1; i < run_times; i++) 1023 | { 1024 | time_start = chrono::high_resolution_clock::now(); 1025 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1026 | time_end = chrono::high_resolution_clock::now(); 1027 | time_diff = chrono::duration_cast(time_end - time_start); 1028 | Rot_latency[10] += time_diff.count(); 1029 | 1030 | time_start = chrono::high_resolution_clock::now(); 1031 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1032 | evaluator.add_inplace(y_encrypted, Result_tmp); 1033 | time_end = chrono::high_resolution_clock::now(); 1034 | time_diff = chrono::duration_cast(time_end - time_start); 1035 | Mul_latency[10] += time_diff.count(); 1036 | 1037 | time_start = chrono::high_resolution_clock::now(); 1038 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1039 | time_end = chrono::high_resolution_clock::now(); 1040 | time_diff = chrono::duration_cast(time_end - time_start); 1041 | Rel_latency[10] += time_diff.count(); 1042 | 1043 | } 1044 | Rot_latency[10] = Rot_latency[10] / run_times; 1045 | Mul_latency[10] = Mul_latency[10] / run_times; 1046 | Rot_Cost[10] = Rot_latency[10] * Rot_number[10]; 1047 | Mul_Cost[10] = Mul_latency[10] * Mul_number[10]; 1048 | Rel_latency[10] = Rel_latency[10] / run_times; 1049 | Rel_Cost[10] = Rel_latency[10] * Mul_number[10]; 1050 | 1051 | 1052 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1053 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1054 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1055 | 1056 | evaluator.square_inplace(y_encrypted); // 40^2=80 1057 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1058 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1059 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1060 | evaluator.rescale_to_next_inplace(y_encrypted); 1061 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1062 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1063 | 1064 | y1_encrypted = y_encrypted; 1065 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1066 | for (int i = 1; i < run_times; i++) 1067 | { 1068 | time_start = chrono::high_resolution_clock::now(); 1069 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1070 | time_end = chrono::high_resolution_clock::now(); 1071 | time_diff = chrono::duration_cast(time_end - time_start); 1072 | Rot_latency[11] += time_diff.count(); 1073 | 1074 | time_start = chrono::high_resolution_clock::now(); 1075 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1076 | evaluator.add_inplace(y_encrypted, Result_tmp); 1077 | time_end = chrono::high_resolution_clock::now(); 1078 | time_diff = chrono::duration_cast(time_end - time_start); 1079 | Mul_latency[11] += time_diff.count(); 1080 | 1081 | time_start = chrono::high_resolution_clock::now(); 1082 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1083 | time_end = chrono::high_resolution_clock::now(); 1084 | time_diff = chrono::duration_cast(time_end - time_start); 1085 | Rel_latency[11] += time_diff.count(); 1086 | 1087 | 1088 | } 1089 | Rot_latency[11] = Rot_latency[11] / run_times; 1090 | Mul_latency[11] = Mul_latency[11] / run_times; 1091 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 1092 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 1093 | Rel_latency[11] = Rel_latency[11] / run_times; 1094 | Rel_Cost[11] = Rel_latency[11] * Mul_number[11]; 1095 | 1096 | 1097 | y1_encrypted = y_encrypted; 1098 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 1099 | for (int i = 1; i < run_times; i++) 1100 | { 1101 | time_start = chrono::high_resolution_clock::now(); 1102 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1103 | time_end = chrono::high_resolution_clock::now(); 1104 | time_diff = chrono::duration_cast(time_end - time_start); 1105 | Rot_latency[12] += time_diff.count(); 1106 | 1107 | time_start = chrono::high_resolution_clock::now(); 1108 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1109 | evaluator.add_inplace(y_encrypted, Result_tmp); 1110 | time_end = chrono::high_resolution_clock::now(); 1111 | time_diff = chrono::duration_cast(time_end - time_start); 1112 | Mul_latency[12] += time_diff.count(); 1113 | 1114 | time_start = chrono::high_resolution_clock::now(); 1115 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 1116 | time_end = chrono::high_resolution_clock::now(); 1117 | time_diff = chrono::duration_cast(time_end - time_start); 1118 | Rel_latency[12] += time_diff.count(); 1119 | 1120 | } 1121 | Rot_latency[12] = Rot_latency[12] / run_times; 1122 | Mul_latency[12] = Mul_latency[12] / run_times; 1123 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 1124 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 1125 | Rel_latency[12] = Rel_latency[12] / run_times; 1126 | Rel_Cost[12] = Rel_latency[12] * Mul_number[12]; 1127 | 1128 | 1129 | time_end = chrono::high_resolution_clock::now(); 1130 | time_diff = chrono::duration_cast(time_end - time_start); 1131 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-30=60, Result_tmp has 2 entries. 1132 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1133 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1134 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 1135 | 1136 | for (int i = 0; i < 13; i++) 1137 | { 1138 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 1139 | << " Mult latency is " << +Mul_latency[i] << " ms]" 1140 | << " Relinear. latency is " << +Rel_latency[i] << " ms]" 1141 | << endl; 1142 | } 1143 | 1144 | double Rot_latency_total = 0.0; 1145 | double Mult_latency_total = 0.0; 1146 | double Rel_latency_total = 0.0; 1147 | for (int i = 0; i < 13; i++) 1148 | { 1149 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 1150 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" 1151 | << " **Total** Rel latency is " << +Rel_Cost[i] << " ms]" 1152 | << endl; 1153 | Rot_latency_total += Rot_Cost[i]; 1154 | Mult_latency_total += Mul_Cost[i]; 1155 | Rel_latency_total += Rel_Cost[i]; 1156 | } 1157 | 1158 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 1159 | << " Mult latency is " << Mult_latency_total << " ms]" 1160 | << " Total latency is " << (Rot_latency_total + Mult_latency_total) / 1000 << " s]" 1161 | << " The Relinear. latency is " << Rel_latency_total / 1000 << " s]" 1162 | << endl; 1163 | } 1164 | 1165 | 1166 | void remove_fire4() 1167 | { 1168 | chrono::high_resolution_clock::time_point time_start, time_end; 1169 | chrono::microseconds time_diff; 1170 | EncryptionParameters parms(scheme_type::CKKS); 1171 | 1172 | size_t poly_modulus_degree = 8192*4; 1173 | parms.set_poly_modulus_degree(poly_modulus_degree); 1174 | parms.set_coeff_modulus(CoeffModulus::Create( 1175 | poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 1176 | 1177 | double input_scale = pow(2.0, 25); 1178 | double weight_scale = pow(2.0, 30); 1179 | double scalar_scale = pow(2.0, 10); 1180 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 1181 | print_parameters(context); 1182 | cout << endl; 1183 | 1184 | KeyGenerator keygen(context); 1185 | auto public_key = keygen.public_key(); 1186 | auto secret_key = keygen.secret_key(); 1187 | auto relin_keys = keygen.relin_keys_local(); 1188 | GaloisKeys gal_keys = keygen.galois_keys_local(); 1189 | Encryptor encryptor(context, public_key); 1190 | Evaluator evaluator(context); 1191 | Decryptor decryptor(context, secret_key); 1192 | 1193 | CKKSEncoder encoder(context); 1194 | size_t slot_count = encoder.slot_count(); 1195 | cout << "Number of slots: " << slot_count << endl; 1196 | 1197 | vector input; 1198 | input.reserve(slot_count); 1199 | double curr_point = 0; 1200 | double step_size = 1.0 / (static_cast(slot_count) - 1); 1201 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 1202 | { 1203 | input.push_back(curr_point); 1204 | } 1205 | cout << "Input vector: " << endl; 1206 | print_vector(input, 3, 7); 1207 | 1208 | Plaintext plain_coeff3, plain_coeff0; 1209 | // encoder.encode(3.14159265, scale, plain_coeff3); 1210 | encoder.encode(0.4, weight_scale, plain_coeff3); 1211 | encoder.encode(1.0, scalar_scale, plain_coeff0); 1212 | 1213 | Plaintext x_plain; 1214 | print_line(__LINE__); 1215 | cout << "Encode input vectors." << endl; 1216 | encoder.encode(input, input_scale, x_plain); 1217 | Ciphertext x1_encrypted; 1218 | encryptor.encrypt(x_plain, x1_encrypted); 1219 | 1220 | Ciphertext y_encrypted; 1221 | print_line(__LINE__); 1222 | 1223 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 1224 | 2.048, 40.960, 90, 0, 2.560, 1.280 }; 1225 | double Rot_number[13] = { 1226 | 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.064, 0.320, 0.8, 0, 0.256, 0.128 1227 | }; 1228 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1229 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1230 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1231 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1232 | 1233 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+30=55, y_encrypted has 3 entries. 1234 | Ciphertext Rotated_tmp, Result_tmp; 1235 | int run_times = 10; 1236 | for (int i = 1; i < run_times; i++) 1237 | { 1238 | time_start = chrono::high_resolution_clock::now(); 1239 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 1240 | time_end = chrono::high_resolution_clock::now(); 1241 | time_diff = chrono::duration_cast(time_end - time_start); 1242 | Rot_latency[0] += time_diff.count(); 1243 | 1244 | time_start = chrono::high_resolution_clock::now(); 1245 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+30=55, Result_tmp has 3 entries. 1246 | evaluator.add_inplace(y_encrypted, Result_tmp); 1247 | time_end = chrono::high_resolution_clock::now(); 1248 | time_diff = chrono::duration_cast(time_end - time_start); 1249 | Mul_latency[0] += time_diff.count(); 1250 | } 1251 | Rot_latency[0] = Rot_latency[0] / run_times; 1252 | Mul_latency[0] = Mul_latency[0] / run_times; 1253 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 1254 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 1255 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+30=55, y_encrypted has 2 entries. 1256 | 1257 | evaluator.square_inplace(y_encrypted); // 55^2=110 1258 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1259 | evaluator.rescale_to_next_inplace(y_encrypted); // 110-60=50 1260 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 1261 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1262 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1263 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 50+10=60 1264 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1265 | 1266 | Ciphertext y1_encrypted = y_encrypted; 1267 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 1268 | for (int i = 1; i < run_times; i++) 1269 | { 1270 | time_start = chrono::high_resolution_clock::now(); 1271 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1272 | time_end = chrono::high_resolution_clock::now(); 1273 | time_diff = chrono::duration_cast(time_end - time_start); 1274 | Rot_latency[1] += time_diff.count(); 1275 | 1276 | time_start = chrono::high_resolution_clock::now(); 1277 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1278 | evaluator.add_inplace(y_encrypted, Result_tmp); 1279 | time_end = chrono::high_resolution_clock::now(); 1280 | time_diff = chrono::duration_cast(time_end - time_start); 1281 | Mul_latency[1] += time_diff.count(); 1282 | } 1283 | Rot_latency[1] = Rot_latency[1] / run_times; 1284 | Mul_latency[1] = Mul_latency[1] / run_times; 1285 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 1286 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 1287 | 1288 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 1289 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 1290 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1291 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1292 | 1293 | y1_encrypted = y_encrypted; 1294 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1295 | for (int i = 1; i < run_times; i++) 1296 | { 1297 | time_start = chrono::high_resolution_clock::now(); 1298 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1299 | time_end = chrono::high_resolution_clock::now(); 1300 | time_diff = chrono::duration_cast(time_end - time_start); 1301 | Rot_latency[2] += time_diff.count(); 1302 | 1303 | time_start = chrono::high_resolution_clock::now(); 1304 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 1305 | evaluator.add_inplace(y_encrypted, Result_tmp); 1306 | time_end = chrono::high_resolution_clock::now(); 1307 | time_diff = chrono::duration_cast(time_end - time_start); 1308 | Mul_latency[2] += time_diff.count(); 1309 | } 1310 | Rot_latency[2] = Rot_latency[2] / run_times; 1311 | Mul_latency[2] = Mul_latency[2] / run_times; 1312 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 1313 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 1314 | 1315 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1316 | cout << "#### The Squeeze1 Done [" 1317 | << " ms]" << endl; 1318 | 1319 | evaluator.square_inplace(y_encrypted); // 60^2=120 1320 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1321 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1322 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1323 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1324 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1325 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1326 | 1327 | y1_encrypted = y_encrypted; 1328 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1329 | for (int i = 1; i < run_times; i++) 1330 | { 1331 | time_start = chrono::high_resolution_clock::now(); 1332 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1333 | time_end = chrono::high_resolution_clock::now(); 1334 | time_diff = chrono::duration_cast(time_end - time_start); 1335 | Rot_latency[3] += time_diff.count(); 1336 | 1337 | time_start = chrono::high_resolution_clock::now(); 1338 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 1339 | evaluator.add_inplace(y_encrypted, Result_tmp); 1340 | time_end = chrono::high_resolution_clock::now(); 1341 | time_diff = chrono::duration_cast(time_end - time_start); 1342 | Mul_latency[3] += time_diff.count(); 1343 | } 1344 | Rot_latency[3] = Rot_latency[3] / run_times; 1345 | Mul_latency[3] = Mul_latency[3] / run_times; 1346 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 1347 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 1348 | 1349 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1350 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1351 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1352 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1353 | 1354 | 1355 | evaluator.square_inplace(y_encrypted); // 40^2=80 1356 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1357 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1358 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1359 | evaluator.rescale_to_next_inplace(y_encrypted); 1360 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1361 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1362 | 1363 | 1364 | y1_encrypted = y_encrypted; 1365 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1366 | 1367 | for (int i = 1; i < run_times; i++) 1368 | { 1369 | time_start = chrono::high_resolution_clock::now(); 1370 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1371 | time_end = chrono::high_resolution_clock::now(); 1372 | time_diff = chrono::duration_cast(time_end - time_start); 1373 | Rot_latency[4] += time_diff.count(); 1374 | 1375 | time_start = chrono::high_resolution_clock::now(); 1376 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1377 | evaluator.add_inplace(y_encrypted, Result_tmp); 1378 | time_end = chrono::high_resolution_clock::now(); 1379 | time_diff = chrono::duration_cast(time_end - time_start); 1380 | Mul_latency[4] += time_diff.count(); 1381 | } 1382 | 1383 | Rot_latency[4] = Rot_latency[4] / run_times; 1384 | Mul_latency[4] = Mul_latency[4] / run_times; 1385 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 1386 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 1387 | 1388 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1389 | 1390 | evaluator.square_inplace(y_encrypted); // 60^2=120 1391 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1392 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1393 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1394 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1395 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1396 | // cout << "#### The ReLU4 Done [" << time_diff.count() << " microseconds]" << endl; 1397 | 1398 | y1_encrypted = y_encrypted; 1399 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1400 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 1401 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1402 | for (int i = 1; i < run_times; i++) 1403 | { 1404 | time_start = chrono::high_resolution_clock::now(); 1405 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1406 | time_end = chrono::high_resolution_clock::now(); 1407 | time_diff = chrono::duration_cast(time_end - time_start); 1408 | Rot_latency[5] += time_diff.count(); 1409 | 1410 | time_start = chrono::high_resolution_clock::now(); 1411 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1412 | evaluator.add_inplace(y_encrypted, Result_tmp); 1413 | time_end = chrono::high_resolution_clock::now(); 1414 | time_diff = chrono::duration_cast(time_end - time_start); 1415 | Mul_latency[5] += time_diff.count(); 1416 | } 1417 | Rot_latency[5] = Rot_latency[5] / run_times; 1418 | Mul_latency[5] = Mul_latency[5] / run_times; 1419 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 1420 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 1421 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1422 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1423 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1424 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1425 | 1426 | 1427 | evaluator.square_inplace(y_encrypted); // 40^2=80 1428 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1429 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1430 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1431 | time_end = chrono::high_resolution_clock::now(); 1432 | evaluator.rescale_to_next_inplace(y_encrypted); 1433 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1434 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1435 | time_diff = chrono::duration_cast(time_end - time_start); 1436 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 1437 | 1438 | y1_encrypted = y_encrypted; 1439 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1440 | 1441 | for (int i = 1; i < run_times; i++) 1442 | { 1443 | time_start = chrono::high_resolution_clock::now(); 1444 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1445 | time_end = chrono::high_resolution_clock::now(); 1446 | time_diff = chrono::duration_cast(time_end - time_start); 1447 | Rot_latency[6] += time_diff.count(); 1448 | 1449 | time_start = chrono::high_resolution_clock::now(); 1450 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1451 | evaluator.add_inplace(y_encrypted, Result_tmp); 1452 | time_end = chrono::high_resolution_clock::now(); 1453 | time_diff = chrono::duration_cast(time_end - time_start); 1454 | Mul_latency[6] += time_diff.count(); 1455 | } 1456 | Rot_latency[6] = Rot_latency[6] / run_times; 1457 | Mul_latency[6] = Mul_latency[6] / run_times; 1458 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 1459 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 1460 | 1461 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 1462 | y1_encrypted = y_encrypted; 1463 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 1464 | 1465 | for (int i = 1; i < run_times; i++) 1466 | { 1467 | time_start = chrono::high_resolution_clock::now(); 1468 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1469 | time_end = chrono::high_resolution_clock::now(); 1470 | time_diff = chrono::duration_cast(time_end - time_start); 1471 | Rot_latency[7] += time_diff.count(); 1472 | 1473 | time_start = chrono::high_resolution_clock::now(); 1474 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1475 | evaluator.add_inplace(y_encrypted, Result_tmp); 1476 | time_end = chrono::high_resolution_clock::now(); 1477 | time_diff = chrono::duration_cast(time_end - time_start); 1478 | Mul_latency[7] += time_diff.count(); 1479 | } 1480 | Rot_latency[7] = Rot_latency[7] / run_times; 1481 | Mul_latency[7] = Mul_latency[7] / run_times; 1482 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 1483 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 1484 | 1485 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 1486 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 1487 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1488 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1489 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 1490 | 1491 | evaluator.square_inplace(y_encrypted); // 30^2=60 1492 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1493 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1494 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1495 | 1496 | y1_encrypted = y_encrypted; 1497 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1498 | for (int i = 1; i < run_times; i++) 1499 | { 1500 | time_start = chrono::high_resolution_clock::now(); 1501 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1502 | time_end = chrono::high_resolution_clock::now(); 1503 | time_diff = chrono::duration_cast(time_end - time_start); 1504 | Rot_latency[8] += time_diff.count(); 1505 | 1506 | time_start = chrono::high_resolution_clock::now(); 1507 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1508 | evaluator.add_inplace(y_encrypted, Result_tmp); 1509 | time_end = chrono::high_resolution_clock::now(); 1510 | time_diff = chrono::duration_cast(time_end - time_start); 1511 | Mul_latency[8] += time_diff.count(); 1512 | } 1513 | Rot_latency[8] = Rot_latency[8] / run_times; 1514 | Mul_latency[8] = Mul_latency[8] / run_times; 1515 | Rot_Cost[8] = Rot_latency[8] * Rot_number[8]; 1516 | Mul_Cost[8] = Mul_latency[8] * Mul_number[8]; 1517 | 1518 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1519 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1520 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1521 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1522 | 1523 | 1524 | evaluator.square_inplace(y_encrypted); // 40^2=80 1525 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1526 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1527 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1528 | evaluator.rescale_to_next_inplace(y_encrypted); 1529 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1530 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1531 | 1532 | y1_encrypted = y_encrypted; 1533 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1534 | for (int i = 1; i < run_times; i++) 1535 | { 1536 | time_start = chrono::high_resolution_clock::now(); 1537 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1538 | time_end = chrono::high_resolution_clock::now(); 1539 | time_diff = chrono::duration_cast(time_end - time_start); 1540 | Rot_latency[9] += time_diff.count(); 1541 | 1542 | time_start = chrono::high_resolution_clock::now(); 1543 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1544 | evaluator.add_inplace(y_encrypted, Result_tmp); 1545 | time_end = chrono::high_resolution_clock::now(); 1546 | time_diff = chrono::duration_cast(time_end - time_start); 1547 | Mul_latency[9] += time_diff.count(); 1548 | } 1549 | Rot_latency[9] = Rot_latency[9] / run_times; 1550 | Mul_latency[9] = Mul_latency[9] / run_times; 1551 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 1552 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 1553 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1554 | 1555 | evaluator.square_inplace(y_encrypted); // 60^2=120 1556 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1557 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1558 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1559 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1560 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1561 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1562 | 1563 | 1564 | 1565 | y1_encrypted = y_encrypted; 1566 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1567 | for (int i = 1; i < run_times; i++) 1568 | { 1569 | time_start = chrono::high_resolution_clock::now(); 1570 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1571 | time_end = chrono::high_resolution_clock::now(); 1572 | time_diff = chrono::duration_cast(time_end - time_start); 1573 | Rot_latency[11] += time_diff.count(); 1574 | 1575 | time_start = chrono::high_resolution_clock::now(); 1576 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 1577 | evaluator.add_inplace(y_encrypted, Result_tmp); 1578 | time_end = chrono::high_resolution_clock::now(); 1579 | time_diff = chrono::duration_cast(time_end - time_start); 1580 | Mul_latency[11] += time_diff.count(); 1581 | } 1582 | Rot_latency[11] = Rot_latency[11] / run_times; 1583 | Mul_latency[11] = Mul_latency[11] / run_times; 1584 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 1585 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 1586 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1587 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1588 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1589 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1590 | 1591 | 1592 | y1_encrypted = y_encrypted; 1593 | evaluator.multiply_plain(y1_encrypted, plain_coeff0, y_encrypted); // 40+10=50, y_encrypted has 3 entries. 1594 | for (int i = 1; i < run_times; i++) 1595 | { 1596 | time_start = chrono::high_resolution_clock::now(); 1597 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1598 | time_end = chrono::high_resolution_clock::now(); 1599 | time_diff = chrono::duration_cast(time_end - time_start); 1600 | Rot_latency[12] += time_diff.count(); 1601 | 1602 | time_start = chrono::high_resolution_clock::now(); 1603 | evaluator.multiply_plain(Rotated_tmp, plain_coeff0, Result_tmp); // 40+10=50, Result_tmp has 3 entries. 1604 | evaluator.add_inplace(y_encrypted, Result_tmp); 1605 | time_end = chrono::high_resolution_clock::now(); 1606 | time_diff = chrono::duration_cast(time_end - time_start); 1607 | Mul_latency[12] += time_diff.count(); 1608 | } 1609 | Rot_latency[12] = Rot_latency[12] / run_times; 1610 | Mul_latency[12] = Mul_latency[12] / run_times; 1611 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 1612 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 1613 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 50, y_encrypted has 2 entries. 1614 | time_end = chrono::high_resolution_clock::now(); 1615 | time_diff = chrono::duration_cast(time_end - time_start); 1616 | 1617 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 1618 | 1619 | for (int i = 0; i < 13; i++) 1620 | { 1621 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 1622 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 1623 | } 1624 | 1625 | double Rot_latency_total = 0.0; 1626 | double Mult_latency_total = 0.0; 1627 | for (int i = 0; i < 13; i++) 1628 | { 1629 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 1630 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 1631 | Rot_latency_total += Rot_Cost[i]; 1632 | Mult_latency_total += Mul_Cost[i]; 1633 | } 1634 | 1635 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 1636 | << " Mult latency is " << +Mult_latency_total << " ms]" 1637 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 1638 | } 1639 | 1640 | 1641 | void remove_fire34() 1642 | { 1643 | chrono::high_resolution_clock::time_point time_start, time_end; 1644 | chrono::microseconds time_diff; 1645 | EncryptionParameters parms(scheme_type::CKKS); 1646 | 1647 | size_t poly_modulus_degree = 8192*4; 1648 | parms.set_poly_modulus_degree(poly_modulus_degree); 1649 | parms.set_coeff_modulus( 1650 | CoeffModulus::Create(poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 1651 | 1652 | double input_scale = pow(2.0, 25); 1653 | double weight_scale = pow(2.0, 30); 1654 | double scalar_scale = pow(2.0, 10); 1655 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 1656 | print_parameters(context); 1657 | cout << endl; 1658 | 1659 | KeyGenerator keygen(context); 1660 | auto public_key = keygen.public_key(); 1661 | auto secret_key = keygen.secret_key(); 1662 | auto relin_keys = keygen.relin_keys_local(); 1663 | GaloisKeys gal_keys = keygen.galois_keys_local(); 1664 | Encryptor encryptor(context, public_key); 1665 | Evaluator evaluator(context); 1666 | Decryptor decryptor(context, secret_key); 1667 | 1668 | CKKSEncoder encoder(context); 1669 | size_t slot_count = encoder.slot_count(); 1670 | cout << "Number of slots: " << slot_count << endl; 1671 | 1672 | vector input; 1673 | input.reserve(slot_count); 1674 | double curr_point = 0; 1675 | double step_size = 1.0 / (static_cast(slot_count) - 1); 1676 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 1677 | { 1678 | input.push_back(curr_point); 1679 | } 1680 | cout << "Input vector: " << endl; 1681 | print_vector(input, 3, 7); 1682 | 1683 | Plaintext plain_coeff3, plain_coeff0; 1684 | // encoder.encode(3.14159265, scale, plain_coeff3); 1685 | encoder.encode(0.4, weight_scale, plain_coeff3); 1686 | encoder.encode(1.0, scalar_scale, plain_coeff0); 1687 | 1688 | Plaintext x_plain; 1689 | print_line(__LINE__); 1690 | cout << "Encode input vectors." << endl; 1691 | encoder.encode(input, input_scale, x_plain); 1692 | Ciphertext x1_encrypted; 1693 | encryptor.encrypt(x_plain, x1_encrypted); 1694 | 1695 | Ciphertext y_encrypted; 1696 | print_line(__LINE__); 1697 | 1698 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 73, 0, 90, 0, 2.560, 1.280 }; 1699 | double Rot_number[13] = { 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.576, 0, 0.8, 0, 0.256, 0.128 }; 1700 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1701 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1702 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1703 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1704 | 1705 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+30=55, y_encrypted has 3 entries. 1706 | Ciphertext Rotated_tmp, Result_tmp; 1707 | int run_times = 10; 1708 | for (int i = 1; i < run_times; i++) 1709 | { 1710 | time_start = chrono::high_resolution_clock::now(); 1711 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 1712 | time_end = chrono::high_resolution_clock::now(); 1713 | time_diff = chrono::duration_cast(time_end - time_start); 1714 | Rot_latency[0] += time_diff.count(); 1715 | 1716 | time_start = chrono::high_resolution_clock::now(); 1717 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+30=55, Result_tmp has 3 entries. 1718 | evaluator.add_inplace(y_encrypted, Result_tmp); 1719 | time_end = chrono::high_resolution_clock::now(); 1720 | time_diff = chrono::duration_cast(time_end - time_start); 1721 | Mul_latency[0] += time_diff.count(); 1722 | } 1723 | Rot_latency[0] = Rot_latency[0] / run_times; 1724 | Mul_latency[0] = Mul_latency[0] / run_times; 1725 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 1726 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 1727 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+30=55, y_encrypted has 2 entries. 1728 | 1729 | evaluator.square_inplace(y_encrypted); // 55^2=110 1730 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1731 | evaluator.rescale_to_next_inplace(y_encrypted); // 110-60=50 1732 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 1733 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1734 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1735 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 50+10=60 1736 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1737 | 1738 | Ciphertext y1_encrypted = y_encrypted; 1739 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 1740 | for (int i = 1; i < run_times; i++) 1741 | { 1742 | time_start = chrono::high_resolution_clock::now(); 1743 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1744 | time_end = chrono::high_resolution_clock::now(); 1745 | time_diff = chrono::duration_cast(time_end - time_start); 1746 | Rot_latency[1] += time_diff.count(); 1747 | 1748 | time_start = chrono::high_resolution_clock::now(); 1749 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1750 | evaluator.add_inplace(y_encrypted, Result_tmp); 1751 | time_end = chrono::high_resolution_clock::now(); 1752 | time_diff = chrono::duration_cast(time_end - time_start); 1753 | Mul_latency[1] += time_diff.count(); 1754 | } 1755 | Rot_latency[1] = Rot_latency[1] / run_times; 1756 | Mul_latency[1] = Mul_latency[1] / run_times; 1757 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 1758 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 1759 | 1760 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 1761 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 1762 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1763 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1764 | 1765 | 1766 | y1_encrypted = y_encrypted; 1767 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1768 | for (int i = 1; i < run_times; i++) 1769 | { 1770 | time_start = chrono::high_resolution_clock::now(); 1771 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1772 | time_end = chrono::high_resolution_clock::now(); 1773 | time_diff = chrono::duration_cast(time_end - time_start); 1774 | Rot_latency[2] += time_diff.count(); 1775 | 1776 | time_start = chrono::high_resolution_clock::now(); 1777 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 1778 | evaluator.add_inplace(y_encrypted, Result_tmp); 1779 | time_end = chrono::high_resolution_clock::now(); 1780 | time_diff = chrono::duration_cast(time_end - time_start); 1781 | Mul_latency[2] += time_diff.count(); 1782 | } 1783 | Rot_latency[2] = Rot_latency[2] / run_times; 1784 | Mul_latency[2] = Mul_latency[2] / run_times; 1785 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 1786 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 1787 | 1788 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1789 | cout << "#### The Squeeze1 Done [" 1790 | << " ms]" << endl; 1791 | 1792 | evaluator.square_inplace(y_encrypted); // 60^2=120 1793 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1794 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1795 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1796 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1797 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1798 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1799 | 1800 | 1801 | y1_encrypted = y_encrypted; 1802 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1803 | for (int i = 1; i < run_times; i++) 1804 | { 1805 | time_start = chrono::high_resolution_clock::now(); 1806 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1807 | time_end = chrono::high_resolution_clock::now(); 1808 | time_diff = chrono::duration_cast(time_end - time_start); 1809 | Rot_latency[3] += time_diff.count(); 1810 | 1811 | time_start = chrono::high_resolution_clock::now(); 1812 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 1813 | evaluator.add_inplace(y_encrypted, Result_tmp); 1814 | time_end = chrono::high_resolution_clock::now(); 1815 | time_diff = chrono::duration_cast(time_end - time_start); 1816 | Mul_latency[3] += time_diff.count(); 1817 | } 1818 | Rot_latency[3] = Rot_latency[3] / run_times; 1819 | Mul_latency[3] = Mul_latency[3] / run_times; 1820 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 1821 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 1822 | 1823 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1824 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1825 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1826 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1827 | 1828 | // cout << "#### The Expand1 Done [" << Mul_Cost_list[3] + Rot_Cost_list[3] << " ms]" << endl; 1829 | 1830 | evaluator.square_inplace(y_encrypted); // 40^2=80 1831 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1832 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1833 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1834 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 1835 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1836 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1837 | 1838 | // cout << "#### The ReLU3 Done [" << time_diff.count() << " microseconds]" << endl; 1839 | 1840 | y1_encrypted = y_encrypted; 1841 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1842 | 1843 | for (int i = 1; i < run_times; i++) 1844 | { 1845 | time_start = chrono::high_resolution_clock::now(); 1846 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1847 | time_end = chrono::high_resolution_clock::now(); 1848 | time_diff = chrono::duration_cast(time_end - time_start); 1849 | Rot_latency[4] += time_diff.count(); 1850 | 1851 | time_start = chrono::high_resolution_clock::now(); 1852 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 1853 | evaluator.add_inplace(y_encrypted, Result_tmp); 1854 | time_end = chrono::high_resolution_clock::now(); 1855 | time_diff = chrono::duration_cast(time_end - time_start); 1856 | Mul_latency[4] += time_diff.count(); 1857 | } 1858 | 1859 | Rot_latency[4] = Rot_latency[4] / run_times; 1860 | Mul_latency[4] = Mul_latency[4] / run_times; 1861 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 1862 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 1863 | 1864 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 1865 | 1866 | evaluator.square_inplace(y_encrypted); // 60^2=120 1867 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1868 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 1869 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1870 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1871 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1872 | 1873 | 1874 | y1_encrypted = y_encrypted; 1875 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1876 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 1877 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1878 | for (int i = 1; i < run_times; i++) 1879 | { 1880 | time_start = chrono::high_resolution_clock::now(); 1881 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1882 | time_end = chrono::high_resolution_clock::now(); 1883 | time_diff = chrono::duration_cast(time_end - time_start); 1884 | Rot_latency[5] += time_diff.count(); 1885 | 1886 | time_start = chrono::high_resolution_clock::now(); 1887 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 1888 | evaluator.add_inplace(y_encrypted, Result_tmp); 1889 | time_end = chrono::high_resolution_clock::now(); 1890 | time_diff = chrono::duration_cast(time_end - time_start); 1891 | Mul_latency[5] += time_diff.count(); 1892 | } 1893 | Rot_latency[5] = Rot_latency[5] / run_times; 1894 | Mul_latency[5] = Mul_latency[5] / run_times; 1895 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 1896 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 1897 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 1898 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 1899 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1900 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1901 | 1902 | // cout << "#### The Expand2 Done [" << Mul_Cost_list[5] + Rot_Cost_list[5] << " ms]" << endl; 1903 | 1904 | evaluator.square_inplace(y_encrypted); // 40^2=80 1905 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1906 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 1907 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1908 | time_end = chrono::high_resolution_clock::now(); 1909 | evaluator.rescale_to_next_inplace(y_encrypted); //90-60=30 1910 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1911 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1912 | time_diff = chrono::duration_cast(time_end - time_start); 1913 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 1914 | 1915 | y1_encrypted = y_encrypted; 1916 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 1917 | 1918 | for (int i = 1; i < run_times; i++) 1919 | { 1920 | time_start = chrono::high_resolution_clock::now(); 1921 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1922 | time_end = chrono::high_resolution_clock::now(); 1923 | time_diff = chrono::duration_cast(time_end - time_start); 1924 | Rot_latency[6] += time_diff.count(); 1925 | 1926 | time_start = chrono::high_resolution_clock::now(); 1927 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 1928 | evaluator.add_inplace(y_encrypted, Result_tmp); 1929 | time_end = chrono::high_resolution_clock::now(); 1930 | time_diff = chrono::duration_cast(time_end - time_start); 1931 | Mul_latency[6] += time_diff.count(); 1932 | } 1933 | Rot_latency[6] = Rot_latency[6] / run_times; 1934 | Mul_latency[6] = Mul_latency[6] / run_times; 1935 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 1936 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 1937 | 1938 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 30+30=60, y_encrypted has 2 entries. 1939 | y1_encrypted = y_encrypted; 1940 | 1941 | 1942 | 1943 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 1944 | 1945 | for (int i = 1; i < run_times; i++) 1946 | { 1947 | time_start = chrono::high_resolution_clock::now(); 1948 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1949 | time_end = chrono::high_resolution_clock::now(); 1950 | time_diff = chrono::duration_cast(time_end - time_start); 1951 | Rot_latency[7] += time_diff.count(); 1952 | 1953 | time_start = chrono::high_resolution_clock::now(); 1954 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 1955 | evaluator.add_inplace(y_encrypted, Result_tmp); 1956 | time_end = chrono::high_resolution_clock::now(); 1957 | time_diff = chrono::duration_cast(time_end - time_start); 1958 | Mul_latency[7] += time_diff.count(); 1959 | } 1960 | Rot_latency[7] = Rot_latency[7] / run_times; 1961 | Mul_latency[7] = Mul_latency[7] / run_times; 1962 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 1963 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 1964 | 1965 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 1966 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 1967 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 1968 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 1969 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 1970 | 1971 | evaluator.square_inplace(y_encrypted); // 30^2=60 1972 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 1973 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 1974 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 1975 | // cout << "#### The ReLU6 Done [" << time_diff.count() << " microseconds]" << endl; 1976 | 1977 | 1978 | y1_encrypted = y_encrypted; 1979 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 1980 | for (int i = 1; i < run_times; i++) 1981 | { 1982 | time_start = chrono::high_resolution_clock::now(); 1983 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 1984 | time_end = chrono::high_resolution_clock::now(); 1985 | time_diff = chrono::duration_cast(time_end - time_start); 1986 | Rot_latency[9] += time_diff.count(); 1987 | 1988 | time_start = chrono::high_resolution_clock::now(); 1989 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 1990 | evaluator.add_inplace(y_encrypted, Result_tmp); 1991 | time_end = chrono::high_resolution_clock::now(); 1992 | time_diff = chrono::duration_cast(time_end - time_start); 1993 | Mul_latency[9] += time_diff.count(); 1994 | } 1995 | Rot_latency[9] = Rot_latency[9] / run_times; 1996 | Mul_latency[9] = Mul_latency[9] / run_times; 1997 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 1998 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 1999 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 2000 | 2001 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 2002 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2003 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2004 | // cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 2005 | 2006 | evaluator.square_inplace(y_encrypted); // 40^2=80 2007 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2008 | 2009 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 2010 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2011 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2012 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2013 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2014 | // cout << "#### The ReLU8 Done [" << time_diff.count() << " microseconds]" << endl; 2015 | 2016 | y1_encrypted = y_encrypted; 2017 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 2018 | for (int i = 1; i < run_times; i++) 2019 | { 2020 | time_start = chrono::high_resolution_clock::now(); 2021 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2022 | time_end = chrono::high_resolution_clock::now(); 2023 | time_diff = chrono::duration_cast(time_end - time_start); 2024 | Rot_latency[11] += time_diff.count(); 2025 | 2026 | time_start = chrono::high_resolution_clock::now(); 2027 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 2028 | evaluator.add_inplace(y_encrypted, Result_tmp); 2029 | time_end = chrono::high_resolution_clock::now(); 2030 | time_diff = chrono::duration_cast(time_end - time_start); 2031 | Mul_latency[11] += time_diff.count(); 2032 | } 2033 | Rot_latency[11] = Rot_latency[11] / run_times; 2034 | Mul_latency[11] = Mul_latency[11] / run_times; 2035 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 2036 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 2037 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2038 | 2039 | // cout << "#### The Conv2 Done [" << Rot_Cost_list[11] + Mul_Cost_list[11] << " ms]" << endl; 2040 | 2041 | y1_encrypted = y_encrypted; 2042 | evaluator.multiply_plain(y1_encrypted, plain_coeff0, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 2043 | for (int i = 1; i < run_times; i++) 2044 | { 2045 | time_start = chrono::high_resolution_clock::now(); 2046 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2047 | time_end = chrono::high_resolution_clock::now(); 2048 | time_diff = chrono::duration_cast(time_end - time_start); 2049 | Rot_latency[12] += time_diff.count(); 2050 | 2051 | time_start = chrono::high_resolution_clock::now(); 2052 | evaluator.multiply_plain(Rotated_tmp, plain_coeff0, Result_tmp); // 60+300=90, Result_tmp has 3 entries. 2053 | evaluator.add_inplace(y_encrypted, Result_tmp); 2054 | time_end = chrono::high_resolution_clock::now(); 2055 | time_diff = chrono::duration_cast(time_end - time_start); 2056 | Mul_latency[12] += time_diff.count(); 2057 | } 2058 | Rot_latency[12] = Rot_latency[12] / run_times; 2059 | Mul_latency[12] = Mul_latency[12] / run_times; 2060 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 2061 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 2062 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 2063 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2064 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2065 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2066 | 2067 | time_end = chrono::high_resolution_clock::now(); 2068 | time_diff = chrono::duration_cast(time_end - time_start); 2069 | 2070 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 2071 | 2072 | for (int i = 0; i < 13; i++) 2073 | { 2074 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 2075 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 2076 | } 2077 | 2078 | double Rot_latency_total = 0.0; 2079 | double Mult_latency_total = 0.0; 2080 | for (int i = 0; i < 13; i++) 2081 | { 2082 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 2083 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 2084 | Rot_latency_total += Rot_Cost[i]; 2085 | Mult_latency_total += Mul_Cost[i]; 2086 | } 2087 | 2088 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 2089 | << " Mult latency is " << +Mult_latency_total << " ms]" 2090 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 2091 | } 2092 | 2093 | 2094 | void remove_fire34_merge() 2095 | { 2096 | chrono::high_resolution_clock::time_point time_start, time_end; 2097 | chrono::microseconds time_diff; 2098 | EncryptionParameters parms(scheme_type::CKKS); 2099 | 2100 | size_t poly_modulus_degree = 8192 ; 2101 | parms.set_poly_modulus_degree(poly_modulus_degree); 2102 | parms.set_coeff_modulus( 2103 | CoeffModulus::Create(poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 2104 | 2105 | double input_scale = pow(2.0, 25); 2106 | double weight_scale = pow(2.0, 15); 2107 | double scalar_scale = pow(2.0, 15); 2108 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 2109 | print_parameters(context); 2110 | cout << endl; 2111 | 2112 | KeyGenerator keygen(context); 2113 | auto public_key = keygen.public_key(); 2114 | auto secret_key = keygen.secret_key(); 2115 | auto relin_keys = keygen.relin_keys_local(); 2116 | GaloisKeys gal_keys = keygen.galois_keys_local(); 2117 | Encryptor encryptor(context, public_key); 2118 | Evaluator evaluator(context); 2119 | Decryptor decryptor(context, secret_key); 2120 | 2121 | CKKSEncoder encoder(context); 2122 | size_t slot_count = encoder.slot_count(); 2123 | cout << "Number of slots: " << slot_count << endl; 2124 | 2125 | vector input; 2126 | input.reserve(slot_count); 2127 | double curr_point = 0; 2128 | double step_size = 1.0 / (static_cast(slot_count) - 1); 2129 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 2130 | { 2131 | input.push_back(curr_point); 2132 | } 2133 | cout << "Input vector: " << endl; 2134 | print_vector(input, 3, 7); 2135 | 2136 | Plaintext plain_coeff3, plain_coeff0; 2137 | // encoder.encode(3.14159265, scale, plain_coeff3); 2138 | encoder.encode(0.4, weight_scale, plain_coeff3); 2139 | encoder.encode(1.0, scalar_scale, plain_coeff0); 2140 | 2141 | Plaintext x_plain; 2142 | print_line(__LINE__); 2143 | cout << "Encode input vectors." << endl; 2144 | encoder.encode(input, input_scale, x_plain); 2145 | Ciphertext x1_encrypted; 2146 | encryptor.encrypt(x_plain, x1_encrypted); 2147 | 2148 | Ciphertext y_encrypted; 2149 | print_line(__LINE__); 2150 | 2151 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 73, 0, 90, 0, 2.560, 1.280 }; 2152 | double Rot_number[13] = { 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.576, 0, 0.8, 0, 0.256, 0.128 }; 2153 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2154 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2155 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2156 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2157 | 2158 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+15=40, y_encrypted has 3 entries. 2159 | Ciphertext Rotated_tmp, Result_tmp; 2160 | int run_times = 10; 2161 | for (int i = 1; i < run_times; i++) 2162 | { 2163 | time_start = chrono::high_resolution_clock::now(); 2164 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 2165 | time_end = chrono::high_resolution_clock::now(); 2166 | time_diff = chrono::duration_cast(time_end - time_start); 2167 | Rot_latency[0] += time_diff.count(); 2168 | 2169 | time_start = chrono::high_resolution_clock::now(); 2170 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+15=40, Result_tmp has 3 entries. 2171 | evaluator.add_inplace(y_encrypted, Result_tmp); 2172 | time_end = chrono::high_resolution_clock::now(); 2173 | time_diff = chrono::duration_cast(time_end - time_start); 2174 | Mul_latency[0] += time_diff.count(); 2175 | } 2176 | Rot_latency[0] = Rot_latency[0] / run_times; 2177 | Mul_latency[0] = Mul_latency[0] / run_times; 2178 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 2179 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 2180 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+15=40, y_encrypted has 2 entries. 2181 | // cout << "#### The conv1 Done [" << Mul_Cost[0] + Rot_Cost[0] << " ms]" << endl; 2182 | 2183 | evaluator.square_inplace(y_encrypted); // 40^2=80 2184 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2185 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+15=95 2186 | evaluator.rescale_to_next_inplace(y_encrypted); // 95-60=35 2187 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 2188 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2189 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2190 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2191 | 2192 | // cout << " + Scale of x1_encrypted after ReLU1: " << log2(y_encrypted.scale()) << " bits" << endl; 2193 | // cout << "#### The ReLU1 Done [" << time_diff.count() << " microseconds]" << endl; 2194 | 2195 | Ciphertext y1_encrypted = y_encrypted; 2196 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 35+15=50, y_encrypted has 3 entries. 2197 | for (int i = 1; i < run_times; i++) 2198 | { 2199 | time_start = chrono::high_resolution_clock::now(); 2200 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2201 | time_end = chrono::high_resolution_clock::now(); 2202 | time_diff = chrono::duration_cast(time_end - time_start); 2203 | Rot_latency[1] += time_diff.count(); 2204 | 2205 | time_start = chrono::high_resolution_clock::now(); 2206 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 35+15=50, Result_tmp has 3 entries. 2207 | evaluator.add_inplace(y_encrypted, Result_tmp); 2208 | time_end = chrono::high_resolution_clock::now(); 2209 | time_diff = chrono::duration_cast(time_end - time_start); 2210 | Mul_latency[1] += time_diff.count(); 2211 | } 2212 | Rot_latency[1] = Rot_latency[1] / run_times; 2213 | Mul_latency[1] = Mul_latency[1] / run_times; 2214 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 2215 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 2216 | 2217 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 35+15=50, y_encrypted has 2 entries. 2218 | 2219 | // cout << " + Scale of y_encrypted after pool: " << log2(y_encrypted.scale()) << " bits (30)" << endl; 2220 | // cout << "#### The Pool Done [" << Mul_Cost_list[1] + Rot_Cost_list[1] << " ms]" << endl; 2221 | 2222 | y1_encrypted = y_encrypted; 2223 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 50+15=65, y_encrypted has 3 entries. 2224 | for (int i = 1; i < run_times; i++) 2225 | { 2226 | time_start = chrono::high_resolution_clock::now(); 2227 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2228 | time_end = chrono::high_resolution_clock::now(); 2229 | time_diff = chrono::duration_cast(time_end - time_start); 2230 | Rot_latency[2] += time_diff.count(); 2231 | 2232 | time_start = chrono::high_resolution_clock::now(); 2233 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 50+15=65, Result_tmp has 3 entries. 2234 | evaluator.add_inplace(y_encrypted, Result_tmp); 2235 | time_end = chrono::high_resolution_clock::now(); 2236 | time_diff = chrono::duration_cast(time_end - time_start); 2237 | Mul_latency[2] += time_diff.count(); 2238 | } 2239 | Rot_latency[2] = Rot_latency[2] / run_times; 2240 | Mul_latency[2] = Mul_latency[2] / run_times; 2241 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 2242 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 2243 | 2244 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 65, y_encrypted has 2 entries. 2245 | 2246 | cout << "#### The Squeeze1 Done [" 2247 | << " ms]" << endl; 2248 | 2249 | evaluator.square_inplace(y_encrypted); // 65^2=130 2250 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2251 | evaluator.rescale_to_next_inplace(y_encrypted); // 130-60=70, y_encrypted has 2 entries. 2252 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2253 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2254 | 2255 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 70+15=85 2256 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2257 | // cout << "#### The ReLU2 Done [" << time_diff.count() << " microseconds]" << endl; 2258 | 2259 | y1_encrypted = y_encrypted; 2260 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 85+15=105, y_encrypted has 3 entries. 2261 | for (int i = 1; i < run_times; i++) 2262 | { 2263 | time_start = chrono::high_resolution_clock::now(); 2264 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2265 | time_end = chrono::high_resolution_clock::now(); 2266 | time_diff = chrono::duration_cast(time_end - time_start); 2267 | Rot_latency[3] += time_diff.count(); 2268 | 2269 | time_start = chrono::high_resolution_clock::now(); 2270 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 85+15=105, Result_tmp has 3 entries. 2271 | evaluator.add_inplace(y_encrypted, Result_tmp); 2272 | time_end = chrono::high_resolution_clock::now(); 2273 | time_diff = chrono::duration_cast(time_end - time_start); 2274 | Mul_latency[3] += time_diff.count(); 2275 | } 2276 | Rot_latency[3] = Rot_latency[3] / run_times; 2277 | Mul_latency[3] = Mul_latency[3] / run_times; 2278 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 2279 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 2280 | 2281 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 105, y_encrypted has 2 entries. 2282 | evaluator.rescale_to_next_inplace(y_encrypted); // 105-60=45 2283 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2284 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2285 | 2286 | // cout << "#### The Expand1 Done [" << Mul_Cost_list[3] + Rot_Cost_list[3] << " ms]" << endl; 2287 | 2288 | evaluator.square_inplace(y_encrypted); // 45^2=90 2289 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2290 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2291 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2292 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2293 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2294 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 30+15=45 2295 | 2296 | 2297 | // cout << "#### The ReLU3 Done [" << time_diff.count() << " microseconds]" << endl; 2298 | 2299 | y1_encrypted = y_encrypted; 2300 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 45+15=60, y_encrypted has 3 entries. 2301 | 2302 | for (int i = 1; i < run_times; i++) 2303 | { 2304 | time_start = chrono::high_resolution_clock::now(); 2305 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2306 | time_end = chrono::high_resolution_clock::now(); 2307 | time_diff = chrono::duration_cast(time_end - time_start); 2308 | Rot_latency[4] += time_diff.count(); 2309 | 2310 | time_start = chrono::high_resolution_clock::now(); 2311 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 45+15=60, Result_tmp has 3 entries. 2312 | evaluator.add_inplace(y_encrypted, Result_tmp); 2313 | time_end = chrono::high_resolution_clock::now(); 2314 | time_diff = chrono::duration_cast(time_end - time_start); 2315 | Mul_latency[4] += time_diff.count(); 2316 | } 2317 | 2318 | Rot_latency[4] = Rot_latency[4] / run_times; 2319 | Mul_latency[4] = Mul_latency[4] / run_times; 2320 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 2321 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 2322 | 2323 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2324 | // cout << "#### The Squeeze2 Done [" << Mul_Cost_list[4] + Rot_Cost_list[4] << " ms]" << endl; 2325 | 2326 | evaluator.square_inplace(y_encrypted); // 60^2=120 2327 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2328 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 2329 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2330 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2331 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2332 | // cout << "#### The ReLU4 Done [" << time_diff.count() << " microseconds]" << endl; 2333 | 2334 | y1_encrypted = y_encrypted; 2335 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2336 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 2337 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2338 | for (int i = 1; i < run_times; i++) 2339 | { 2340 | time_start = chrono::high_resolution_clock::now(); 2341 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2342 | time_end = chrono::high_resolution_clock::now(); 2343 | time_diff = chrono::duration_cast(time_end - time_start); 2344 | Rot_latency[5] += time_diff.count(); 2345 | 2346 | time_start = chrono::high_resolution_clock::now(); 2347 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2348 | evaluator.add_inplace(y_encrypted, Result_tmp); 2349 | time_end = chrono::high_resolution_clock::now(); 2350 | time_diff = chrono::duration_cast(time_end - time_start); 2351 | Mul_latency[5] += time_diff.count(); 2352 | } 2353 | Rot_latency[5] = Rot_latency[5] / run_times; 2354 | Mul_latency[5] = Mul_latency[5] / run_times; 2355 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 2356 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 2357 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 2358 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2359 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2360 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2361 | 2362 | // cout << "#### The Expand2 Done [" << Mul_Cost_list[5] + Rot_Cost_list[5] << " ms]" << endl; 2363 | 2364 | evaluator.square_inplace(y_encrypted); // 30^2=60 2365 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2366 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2367 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2368 | time_end = chrono::high_resolution_clock::now(); 2369 | time_diff = chrono::duration_cast(time_end - time_start); 2370 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 2371 | 2372 | y1_encrypted = y_encrypted; 2373 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2374 | 2375 | for (int i = 1; i < run_times; i++) 2376 | { 2377 | time_start = chrono::high_resolution_clock::now(); 2378 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2379 | time_end = chrono::high_resolution_clock::now(); 2380 | time_diff = chrono::duration_cast(time_end - time_start); 2381 | Rot_latency[6] += time_diff.count(); 2382 | 2383 | time_start = chrono::high_resolution_clock::now(); 2384 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2385 | evaluator.add_inplace(y_encrypted, Result_tmp); 2386 | time_end = chrono::high_resolution_clock::now(); 2387 | time_diff = chrono::duration_cast(time_end - time_start); 2388 | Mul_latency[6] += time_diff.count(); 2389 | } 2390 | Rot_latency[6] = Rot_latency[6] / run_times; 2391 | Mul_latency[6] = Mul_latency[6] / run_times; 2392 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 2393 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 2394 | 2395 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 75+15=90, y_encrypted has 2 entries. 2396 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2397 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2398 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2399 | y1_encrypted = y_encrypted; 2400 | 2401 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+15=45, y_encrypted has 3 entries. 2402 | 2403 | for (int i = 1; i < run_times; i++) 2404 | { 2405 | time_start = chrono::high_resolution_clock::now(); 2406 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2407 | time_end = chrono::high_resolution_clock::now(); 2408 | time_diff = chrono::duration_cast(time_end - time_start); 2409 | Rot_latency[7] += time_diff.count(); 2410 | 2411 | time_start = chrono::high_resolution_clock::now(); 2412 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+15=45, Result_tmp has 3 entries. 2413 | evaluator.add_inplace(y_encrypted, Result_tmp); 2414 | time_end = chrono::high_resolution_clock::now(); 2415 | time_diff = chrono::duration_cast(time_end - time_start); 2416 | Mul_latency[7] += time_diff.count(); 2417 | } 2418 | Rot_latency[7] = Rot_latency[7] / run_times; 2419 | Mul_latency[7] = Mul_latency[7] / run_times; 2420 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 2421 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 2422 | 2423 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 45, y_encrypted has 2 entries. 2424 | 2425 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 2426 | 2427 | evaluator.square_inplace(y_encrypted); // 45^2=90 2428 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2429 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2430 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2431 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2432 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 30+15=45 2433 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2434 | // cout << "#### The ReLU6 Done [" << time_diff.count() << " microseconds]" << endl; 2435 | 2436 | y1_encrypted = y_encrypted; 2437 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 45+15=60, y_encrypted has 3 entries. 2438 | for (int i = 1; i < run_times; i++) 2439 | { 2440 | time_start = chrono::high_resolution_clock::now(); 2441 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2442 | time_end = chrono::high_resolution_clock::now(); 2443 | time_diff = chrono::duration_cast(time_end - time_start); 2444 | Rot_latency[9] += time_diff.count(); 2445 | 2446 | time_start = chrono::high_resolution_clock::now(); 2447 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 45+15=60, Result_tmp has 3 entries. 2448 | evaluator.add_inplace(y_encrypted, Result_tmp); 2449 | time_end = chrono::high_resolution_clock::now(); 2450 | time_diff = chrono::duration_cast(time_end - time_start); 2451 | Mul_latency[9] += time_diff.count(); 2452 | } 2453 | Rot_latency[9] = Rot_latency[9] / run_times; 2454 | Mul_latency[9] = Mul_latency[9] / run_times; 2455 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 2456 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 2457 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2458 | 2459 | 2460 | // cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 2461 | 2462 | evaluator.square_inplace(y_encrypted); // 60^2=120 2463 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2464 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 2465 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2466 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2467 | 2468 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2469 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2470 | 2471 | // cout << "#### The ReLU8 Done [" << time_diff.count() << " microseconds]" << endl; 2472 | 2473 | y1_encrypted = y_encrypted; 2474 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2475 | for (int i = 1; i < run_times; i++) 2476 | { 2477 | time_start = chrono::high_resolution_clock::now(); 2478 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2479 | time_end = chrono::high_resolution_clock::now(); 2480 | time_diff = chrono::duration_cast(time_end - time_start); 2481 | Rot_latency[11] += time_diff.count(); 2482 | 2483 | time_start = chrono::high_resolution_clock::now(); 2484 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2485 | evaluator.add_inplace(y_encrypted, Result_tmp); 2486 | time_end = chrono::high_resolution_clock::now(); 2487 | time_diff = chrono::duration_cast(time_end - time_start); 2488 | Mul_latency[11] += time_diff.count(); 2489 | } 2490 | Rot_latency[11] = Rot_latency[11] / run_times; 2491 | Mul_latency[11] = Mul_latency[11] / run_times; 2492 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 2493 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 2494 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 2495 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2496 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2497 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2498 | // cout << "#### The Conv2 Done [" << Rot_Cost_list[11] + Mul_Cost_list[11] << " ms]" << endl; 2499 | 2500 | y1_encrypted = y_encrypted; 2501 | evaluator.multiply_plain(y1_encrypted, plain_coeff0, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 2502 | for (int i = 1; i < run_times; i++) 2503 | { 2504 | time_start = chrono::high_resolution_clock::now(); 2505 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2506 | time_end = chrono::high_resolution_clock::now(); 2507 | time_diff = chrono::duration_cast(time_end - time_start); 2508 | Rot_latency[12] += time_diff.count(); 2509 | 2510 | time_start = chrono::high_resolution_clock::now(); 2511 | evaluator.multiply_plain(Rotated_tmp, plain_coeff0, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 2512 | evaluator.add_inplace(y_encrypted, Result_tmp); 2513 | time_end = chrono::high_resolution_clock::now(); 2514 | time_diff = chrono::duration_cast(time_end - time_start); 2515 | Mul_latency[12] += time_diff.count(); 2516 | } 2517 | Rot_latency[12] = Rot_latency[12] / run_times; 2518 | Mul_latency[12] = Mul_latency[12] / run_times; 2519 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 2520 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 2521 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2522 | 2523 | time_end = chrono::high_resolution_clock::now(); 2524 | time_diff = chrono::duration_cast(time_end - time_start); 2525 | 2526 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 2527 | 2528 | for (int i = 0; i < 13; i++) 2529 | { 2530 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 2531 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 2532 | } 2533 | 2534 | double Rot_latency_total = 0.0; 2535 | double Mult_latency_total = 0.0; 2536 | for (int i = 0; i < 13; i++) 2537 | { 2538 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 2539 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 2540 | Rot_latency_total += Rot_Cost[i]; 2541 | Mult_latency_total += Mul_Cost[i]; 2542 | } 2543 | 2544 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 2545 | << " Mult latency is " << +Mult_latency_total << " ms]" 2546 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 2547 | } 2548 | 2549 | 2550 | 2551 | 2552 | void remove_fire34_merge_eager() 2553 | { 2554 | chrono::high_resolution_clock::time_point time_start, time_end; 2555 | chrono::microseconds time_diff; 2556 | EncryptionParameters parms(scheme_type::CKKS); 2557 | 2558 | size_t poly_modulus_degree = 8192; 2559 | parms.set_poly_modulus_degree(poly_modulus_degree); 2560 | parms.set_coeff_modulus( 2561 | CoeffModulus::Create(poly_modulus_degree, {60, 60, 60, 60, 60, 60, 30, 60, 60, 60, 60, 60 })); 2562 | 2563 | double input_scale = pow(2.0, 25); 2564 | double weight_scale = pow(2.0, 15); 2565 | double scalar_scale = pow(2.0, 15); 2566 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 2567 | print_parameters(context); 2568 | cout << endl; 2569 | 2570 | KeyGenerator keygen(context); 2571 | auto public_key = keygen.public_key(); 2572 | auto secret_key = keygen.secret_key(); 2573 | auto relin_keys = keygen.relin_keys_local(); 2574 | GaloisKeys gal_keys = keygen.galois_keys_local(); 2575 | Encryptor encryptor(context, public_key); 2576 | Evaluator evaluator(context); 2577 | Decryptor decryptor(context, secret_key); 2578 | 2579 | CKKSEncoder encoder(context); 2580 | size_t slot_count = encoder.slot_count(); 2581 | cout << "Number of slots: " << slot_count << endl; 2582 | 2583 | vector input; 2584 | input.reserve(slot_count); 2585 | double curr_point = 0; 2586 | double step_size = 1.0 / (static_cast(slot_count) - 1); 2587 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 2588 | { 2589 | input.push_back(curr_point); 2590 | } 2591 | cout << "Input vector: " << endl; 2592 | print_vector(input, 3, 7); 2593 | 2594 | Plaintext plain_coeff3, plain_coeff0; 2595 | // encoder.encode(3.14159265, scale, plain_coeff3); 2596 | encoder.encode(0.4, weight_scale, plain_coeff3); 2597 | encoder.encode(1.0, scalar_scale, plain_coeff0); 2598 | 2599 | Plaintext x_plain; 2600 | print_line(__LINE__); 2601 | cout << "Encode input vectors." << endl; 2602 | encoder.encode(input, input_scale, x_plain); 2603 | Ciphertext x1_encrypted; 2604 | encryptor.encrypt(x_plain, x1_encrypted); 2605 | 2606 | Ciphertext y_encrypted; 2607 | print_line(__LINE__); 2608 | 2609 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 2.048, 20.470, 0.256, 73, 0, 90, 0, 2.560, 1.280 }; 2610 | double Rot_number[13] = { 0.027, 0.256, 0.064, 0.320, 0.064, 0.320, 0.256, 0.576, 0, 0.8, 0, 0.256, 0.128 }; 2611 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2612 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2613 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2614 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2615 | 2616 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+15=40, y_encrypted has 3 entries. 2617 | Ciphertext Rotated_tmp, Result_tmp; 2618 | int run_times = 10; 2619 | for (int i = 1; i < run_times; i++) 2620 | { 2621 | time_start = chrono::high_resolution_clock::now(); 2622 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 2623 | time_end = chrono::high_resolution_clock::now(); 2624 | time_diff = chrono::duration_cast(time_end - time_start); 2625 | Rot_latency[0] += time_diff.count(); 2626 | 2627 | time_start = chrono::high_resolution_clock::now(); 2628 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+15=40, Result_tmp has 3 entries. 2629 | evaluator.add_inplace(y_encrypted, Result_tmp); 2630 | time_end = chrono::high_resolution_clock::now(); 2631 | time_diff = chrono::duration_cast(time_end - time_start); 2632 | Mul_latency[0] += time_diff.count(); 2633 | } 2634 | Rot_latency[0] = Rot_latency[0] / run_times; 2635 | Mul_latency[0] = Mul_latency[0] / run_times; 2636 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 2637 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 2638 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+15=40, y_encrypted has 2 entries. 2639 | // cout << "#### The conv1 Done [" << Mul_Cost[0] + Rot_Cost[0] << " ms]" << endl; 2640 | 2641 | evaluator.square_inplace(y_encrypted); // 40^2=80 2642 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2643 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+15=95 2644 | evaluator.rescale_to_next_inplace(y_encrypted); // 95-60=35 2645 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 2646 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2647 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2648 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2649 | 2650 | // cout << " + Scale of x1_encrypted after ReLU1: " << log2(y_encrypted.scale()) << " bits" << endl; 2651 | // cout << "#### The ReLU1 Done [" << time_diff.count() << " microseconds]" << endl; 2652 | 2653 | Ciphertext y1_encrypted = y_encrypted; 2654 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 35+15=50, y_encrypted has 3 entries. 2655 | for (int i = 1; i < run_times; i++) 2656 | { 2657 | time_start = chrono::high_resolution_clock::now(); 2658 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2659 | time_end = chrono::high_resolution_clock::now(); 2660 | time_diff = chrono::duration_cast(time_end - time_start); 2661 | Rot_latency[1] += time_diff.count(); 2662 | 2663 | time_start = chrono::high_resolution_clock::now(); 2664 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 35+15=50, Result_tmp has 3 entries. 2665 | evaluator.add_inplace(y_encrypted, Result_tmp); 2666 | time_end = chrono::high_resolution_clock::now(); 2667 | time_diff = chrono::duration_cast(time_end - time_start); 2668 | Mul_latency[1] += time_diff.count(); 2669 | } 2670 | Rot_latency[1] = Rot_latency[1] / run_times; 2671 | Mul_latency[1] = Mul_latency[1] / run_times; 2672 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 2673 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 2674 | 2675 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 35+15=50, y_encrypted has 2 entries. 2676 | 2677 | // cout << " + Scale of y_encrypted after pool: " << log2(y_encrypted.scale()) << " bits (30)" << endl; 2678 | // cout << "#### The Pool Done [" << Mul_Cost_list[1] + Rot_Cost_list[1] << " ms]" << endl; 2679 | 2680 | y1_encrypted = y_encrypted; 2681 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 50+15=65, y_encrypted has 3 entries. 2682 | for (int i = 1; i < run_times; i++) 2683 | { 2684 | time_start = chrono::high_resolution_clock::now(); 2685 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2686 | time_end = chrono::high_resolution_clock::now(); 2687 | time_diff = chrono::duration_cast(time_end - time_start); 2688 | Rot_latency[2] += time_diff.count(); 2689 | 2690 | time_start = chrono::high_resolution_clock::now(); 2691 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 50+15=65, Result_tmp has 3 entries. 2692 | evaluator.add_inplace(y_encrypted, Result_tmp); 2693 | time_end = chrono::high_resolution_clock::now(); 2694 | time_diff = chrono::duration_cast(time_end - time_start); 2695 | Mul_latency[2] += time_diff.count(); 2696 | } 2697 | Rot_latency[2] = Rot_latency[2] / run_times; 2698 | Mul_latency[2] = Mul_latency[2] / run_times; 2699 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 2700 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 2701 | 2702 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 65, y_encrypted has 2 entries. 2703 | 2704 | cout << "#### The Squeeze1 Done [" 2705 | << " ms]" << endl; 2706 | 2707 | evaluator.square_inplace(y_encrypted); // 65^2=130 2708 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2709 | evaluator.rescale_to_next_inplace(y_encrypted); // 130-60=70, y_encrypted has 2 entries. 2710 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2711 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2712 | 2713 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 70+15=85 2714 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2715 | // cout << "#### The ReLU2 Done [" << time_diff.count() << " microseconds]" << endl; 2716 | 2717 | y1_encrypted = y_encrypted; 2718 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 85+15=105, y_encrypted has 3 entries. 2719 | for (int i = 1; i < run_times; i++) 2720 | { 2721 | time_start = chrono::high_resolution_clock::now(); 2722 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2723 | time_end = chrono::high_resolution_clock::now(); 2724 | time_diff = chrono::duration_cast(time_end - time_start); 2725 | Rot_latency[3] += time_diff.count(); 2726 | 2727 | time_start = chrono::high_resolution_clock::now(); 2728 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 85+15=105, Result_tmp has 3 entries. 2729 | evaluator.add_inplace(y_encrypted, Result_tmp); 2730 | time_end = chrono::high_resolution_clock::now(); 2731 | time_diff = chrono::duration_cast(time_end - time_start); 2732 | Mul_latency[3] += time_diff.count(); 2733 | } 2734 | Rot_latency[3] = Rot_latency[3] / run_times; 2735 | Mul_latency[3] = Mul_latency[3] / run_times; 2736 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 2737 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 2738 | 2739 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 105, y_encrypted has 2 entries. 2740 | evaluator.rescale_to_next_inplace(y_encrypted); // 105-60=45 2741 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2742 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2743 | 2744 | // cout << "#### The Expand1 Done [" << Mul_Cost_list[3] + Rot_Cost_list[3] << " ms]" << endl; 2745 | 2746 | evaluator.square_inplace(y_encrypted); // 45^2=90 2747 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2748 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2749 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2750 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2751 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2752 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 30+15=45 2753 | 2754 | // cout << "#### The ReLU3 Done [" << time_diff.count() << " microseconds]" << endl; 2755 | 2756 | y1_encrypted = y_encrypted; 2757 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 45+15=60, y_encrypted has 3 entries. 2758 | 2759 | for (int i = 1; i < run_times; i++) 2760 | { 2761 | time_start = chrono::high_resolution_clock::now(); 2762 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2763 | time_end = chrono::high_resolution_clock::now(); 2764 | time_diff = chrono::duration_cast(time_end - time_start); 2765 | Rot_latency[4] += time_diff.count(); 2766 | 2767 | time_start = chrono::high_resolution_clock::now(); 2768 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 45+15=60, Result_tmp has 3 entries. 2769 | evaluator.add_inplace(y_encrypted, Result_tmp); 2770 | time_end = chrono::high_resolution_clock::now(); 2771 | time_diff = chrono::duration_cast(time_end - time_start); 2772 | Mul_latency[4] += time_diff.count(); 2773 | } 2774 | 2775 | Rot_latency[4] = Rot_latency[4] / run_times; 2776 | Mul_latency[4] = Mul_latency[4] / run_times; 2777 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 2778 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 2779 | 2780 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2781 | // cout << "#### The Squeeze2 Done [" << Mul_Cost_list[4] + Rot_Cost_list[4] << " ms]" << endl; 2782 | 2783 | evaluator.rescale_to_next_inplace(y_encrypted); // 60-30=30 2784 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2785 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2786 | evaluator.square_inplace(y_encrypted); // 30^2=60 2787 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2788 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2789 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2790 | // cout << "#### The ReLU4 Done [" << time_diff.count() << " microseconds]" << endl; 2791 | 2792 | y1_encrypted = y_encrypted; 2793 | 2794 | // evaluator.mod_switch_to_next_inplace(plain_coeff0); 2795 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2796 | for (int i = 1; i < run_times; i++) 2797 | { 2798 | time_start = chrono::high_resolution_clock::now(); 2799 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2800 | time_end = chrono::high_resolution_clock::now(); 2801 | time_diff = chrono::duration_cast(time_end - time_start); 2802 | Rot_latency[5] += time_diff.count(); 2803 | 2804 | time_start = chrono::high_resolution_clock::now(); 2805 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2806 | evaluator.add_inplace(y_encrypted, Result_tmp); 2807 | time_end = chrono::high_resolution_clock::now(); 2808 | time_diff = chrono::duration_cast(time_end - time_start); 2809 | Mul_latency[5] += time_diff.count(); 2810 | } 2811 | Rot_latency[5] = Rot_latency[5] / run_times; 2812 | Mul_latency[5] = Mul_latency[5] / run_times; 2813 | Rot_Cost[5] = Rot_latency[5] * Rot_number[5]; 2814 | Mul_Cost[5] = Mul_latency[5] * Mul_number[5]; 2815 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 2816 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2817 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2818 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2819 | 2820 | // cout << "#### The Expand2 Done [" << Mul_Cost_list[5] + Rot_Cost_list[5] << " ms]" << endl; 2821 | 2822 | evaluator.square_inplace(y_encrypted); // 30^2=60 2823 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2824 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2825 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2826 | time_end = chrono::high_resolution_clock::now(); 2827 | time_diff = chrono::duration_cast(time_end - time_start); 2828 | cout << "#### The ReLU5 Done [" << time_diff.count() << " microseconds]" << endl; 2829 | 2830 | y1_encrypted = y_encrypted; 2831 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2832 | 2833 | for (int i = 1; i < run_times; i++) 2834 | { 2835 | time_start = chrono::high_resolution_clock::now(); 2836 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2837 | time_end = chrono::high_resolution_clock::now(); 2838 | time_diff = chrono::duration_cast(time_end - time_start); 2839 | Rot_latency[6] += time_diff.count(); 2840 | 2841 | time_start = chrono::high_resolution_clock::now(); 2842 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2843 | evaluator.add_inplace(y_encrypted, Result_tmp); 2844 | time_end = chrono::high_resolution_clock::now(); 2845 | time_diff = chrono::duration_cast(time_end - time_start); 2846 | Mul_latency[6] += time_diff.count(); 2847 | } 2848 | Rot_latency[6] = Rot_latency[6] / run_times; 2849 | Mul_latency[6] = Mul_latency[6] / run_times; 2850 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 2851 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 2852 | 2853 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 75+15=90, y_encrypted has 2 entries. 2854 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2855 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2856 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2857 | y1_encrypted = y_encrypted; 2858 | 2859 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+15=45, y_encrypted has 3 entries. 2860 | 2861 | for (int i = 1; i < run_times; i++) 2862 | { 2863 | time_start = chrono::high_resolution_clock::now(); 2864 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2865 | time_end = chrono::high_resolution_clock::now(); 2866 | time_diff = chrono::duration_cast(time_end - time_start); 2867 | Rot_latency[7] += time_diff.count(); 2868 | 2869 | time_start = chrono::high_resolution_clock::now(); 2870 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+15=45, Result_tmp has 3 entries. 2871 | evaluator.add_inplace(y_encrypted, Result_tmp); 2872 | time_end = chrono::high_resolution_clock::now(); 2873 | time_diff = chrono::duration_cast(time_end - time_start); 2874 | Mul_latency[7] += time_diff.count(); 2875 | } 2876 | Rot_latency[7] = Rot_latency[7] / run_times; 2877 | Mul_latency[7] = Mul_latency[7] / run_times; 2878 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 2879 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 2880 | 2881 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 45, y_encrypted has 2 entries. 2882 | 2883 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 2884 | 2885 | evaluator.square_inplace(y_encrypted); // 45^2=90 2886 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2887 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2888 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2889 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2890 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 30+15=45 2891 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2892 | // cout << "#### The ReLU6 Done [" << time_diff.count() << " microseconds]" << endl; 2893 | 2894 | y1_encrypted = y_encrypted; 2895 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 45+15=60, y_encrypted has 3 entries. 2896 | for (int i = 1; i < run_times; i++) 2897 | { 2898 | time_start = chrono::high_resolution_clock::now(); 2899 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2900 | time_end = chrono::high_resolution_clock::now(); 2901 | time_diff = chrono::duration_cast(time_end - time_start); 2902 | Rot_latency[9] += time_diff.count(); 2903 | 2904 | time_start = chrono::high_resolution_clock::now(); 2905 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 45+15=60, Result_tmp has 3 entries. 2906 | evaluator.add_inplace(y_encrypted, Result_tmp); 2907 | time_end = chrono::high_resolution_clock::now(); 2908 | time_diff = chrono::duration_cast(time_end - time_start); 2909 | Mul_latency[9] += time_diff.count(); 2910 | } 2911 | Rot_latency[9] = Rot_latency[9] / run_times; 2912 | Mul_latency[9] = Mul_latency[9] / run_times; 2913 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 2914 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 2915 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2916 | 2917 | // cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 2918 | 2919 | evaluator.square_inplace(y_encrypted); // 60^2=120 2920 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 2921 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 2922 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2923 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2924 | 2925 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+15=75 2926 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 2927 | 2928 | // cout << "#### The ReLU8 Done [" << time_diff.count() << " microseconds]" << endl; 2929 | 2930 | y1_encrypted = y_encrypted; 2931 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 75+15=90, y_encrypted has 3 entries. 2932 | for (int i = 1; i < run_times; i++) 2933 | { 2934 | time_start = chrono::high_resolution_clock::now(); 2935 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2936 | time_end = chrono::high_resolution_clock::now(); 2937 | time_diff = chrono::duration_cast(time_end - time_start); 2938 | Rot_latency[11] += time_diff.count(); 2939 | 2940 | time_start = chrono::high_resolution_clock::now(); 2941 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 75+15=90, Result_tmp has 3 entries. 2942 | evaluator.add_inplace(y_encrypted, Result_tmp); 2943 | time_end = chrono::high_resolution_clock::now(); 2944 | time_diff = chrono::duration_cast(time_end - time_start); 2945 | Mul_latency[11] += time_diff.count(); 2946 | } 2947 | Rot_latency[11] = Rot_latency[11] / run_times; 2948 | Mul_latency[11] = Mul_latency[11] / run_times; 2949 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 2950 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 2951 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 2952 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 2953 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 2954 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 2955 | // cout << "#### The Conv2 Done [" << Rot_Cost_list[11] + Mul_Cost_list[11] << " ms]" << endl; 2956 | 2957 | y1_encrypted = y_encrypted; 2958 | evaluator.multiply_plain(y1_encrypted, plain_coeff0, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 2959 | for (int i = 1; i < run_times; i++) 2960 | { 2961 | time_start = chrono::high_resolution_clock::now(); 2962 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 2963 | time_end = chrono::high_resolution_clock::now(); 2964 | time_diff = chrono::duration_cast(time_end - time_start); 2965 | Rot_latency[12] += time_diff.count(); 2966 | 2967 | time_start = chrono::high_resolution_clock::now(); 2968 | evaluator.multiply_plain(Rotated_tmp, plain_coeff0, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 2969 | evaluator.add_inplace(y_encrypted, Result_tmp); 2970 | time_end = chrono::high_resolution_clock::now(); 2971 | time_diff = chrono::duration_cast(time_end - time_start); 2972 | Mul_latency[12] += time_diff.count(); 2973 | } 2974 | Rot_latency[12] = Rot_latency[12] / run_times; 2975 | Mul_latency[12] = Mul_latency[12] / run_times; 2976 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 2977 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 2978 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 2979 | 2980 | time_end = chrono::high_resolution_clock::now(); 2981 | time_diff = chrono::duration_cast(time_end - time_start); 2982 | 2983 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 2984 | 2985 | for (int i = 0; i < 13; i++) 2986 | { 2987 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 2988 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 2989 | } 2990 | 2991 | double Rot_latency_total = 0.0; 2992 | double Mult_latency_total = 0.0; 2993 | for (int i = 0; i < 13; i++) 2994 | { 2995 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 2996 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 2997 | Rot_latency_total += Rot_Cost[i]; 2998 | Mult_latency_total += Mul_Cost[i]; 2999 | } 3000 | 3001 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 3002 | << " Mult latency is " << +Mult_latency_total << " ms]" 3003 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 3004 | } 3005 | 3006 | 3007 | 3008 | void remove_fire234() 3009 | { 3010 | chrono::high_resolution_clock::time_point time_start, time_end; 3011 | chrono::microseconds time_diff; 3012 | EncryptionParameters parms(scheme_type::CKKS); 3013 | 3014 | size_t poly_modulus_degree = 8192*4; 3015 | parms.set_poly_modulus_degree(poly_modulus_degree); 3016 | parms.set_coeff_modulus( 3017 | CoeffModulus::Create(poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 3018 | 3019 | double input_scale = pow(2.0, 25); 3020 | double weight_scale = pow(2.0, 30); 3021 | double scalar_scale = pow(2.0, 10); 3022 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 3023 | print_parameters(context); 3024 | cout << endl; 3025 | 3026 | KeyGenerator keygen(context); 3027 | auto public_key = keygen.public_key(); 3028 | auto secret_key = keygen.secret_key(); 3029 | auto relin_keys = keygen.relin_keys_local(); 3030 | GaloisKeys gal_keys = keygen.galois_keys_local(); 3031 | Encryptor encryptor(context, public_key); 3032 | Evaluator evaluator(context); 3033 | Decryptor decryptor(context, secret_key); 3034 | 3035 | CKKSEncoder encoder(context); 3036 | size_t slot_count = encoder.slot_count(); 3037 | cout << "Number of slots: " << slot_count << endl; 3038 | 3039 | vector input; 3040 | input.reserve(slot_count); 3041 | double curr_point = 0; 3042 | double step_size = 1.0 / (static_cast(slot_count) - 1); 3043 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 3044 | { 3045 | input.push_back(curr_point); 3046 | } 3047 | cout << "Input vector: " << endl; 3048 | print_vector(input, 3, 7); 3049 | 3050 | Plaintext plain_coeff3, plain_coeff0; 3051 | // encoder.encode(3.14159265, scale, plain_coeff3); 3052 | encoder.encode(0.4, weight_scale, plain_coeff3); 3053 | encoder.encode(1.0, scalar_scale, plain_coeff0); 3054 | 3055 | Plaintext x_plain; 3056 | print_line(__LINE__); 3057 | cout << "Encode input vectors." << endl; 3058 | encoder.encode(input, input_scale, x_plain); 3059 | Ciphertext x1_encrypted; 3060 | encryptor.encrypt(x_plain, x1_encrypted); 3061 | 3062 | Ciphertext y_encrypted; 3063 | print_line(__LINE__); 3064 | 3065 | double Mul_number[13] = { 1.728, 0.256, 2.048, 20.470, 36.864, 0, 0.256, 73, 0, 90, 0, 2.560, 1.280 }; 3066 | double Rot_number[13] = { 0.027, 0.256, 0.064, 0.320, 0.576, 0, 0.256, 0.576, 0, 0.8, 0, 0.256, 0.128 }; 3067 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3068 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3069 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3070 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3071 | 3072 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+30=55, y_encrypted has 3 entries. 3073 | Ciphertext Rotated_tmp, Result_tmp; 3074 | int run_times = 10; 3075 | for (int i = 1; i < run_times; i++) 3076 | { 3077 | time_start = chrono::high_resolution_clock::now(); 3078 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 3079 | time_end = chrono::high_resolution_clock::now(); 3080 | time_diff = chrono::duration_cast(time_end - time_start); 3081 | Rot_latency[0] += time_diff.count(); 3082 | 3083 | time_start = chrono::high_resolution_clock::now(); 3084 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+30=55, Result_tmp has 3 entries. 3085 | evaluator.add_inplace(y_encrypted, Result_tmp); 3086 | time_end = chrono::high_resolution_clock::now(); 3087 | time_diff = chrono::duration_cast(time_end - time_start); 3088 | Mul_latency[0] += time_diff.count(); 3089 | } 3090 | Rot_latency[0] = Rot_latency[0] / run_times; 3091 | Mul_latency[0] = Mul_latency[0] / run_times; 3092 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 3093 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 3094 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+30=55, y_encrypted has 2 entries. 3095 | // cout << "#### The conv1 Done [" << Mul_Cost[0] + Rot_Cost[0] << " ms]" << endl; 3096 | 3097 | evaluator.square_inplace(y_encrypted); // 55^2=110 3098 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3099 | evaluator.rescale_to_next_inplace(y_encrypted); // 110-60=50 3100 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 3101 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3102 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3103 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 50+10=60 3104 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3105 | 3106 | // cout << " + Scale of x1_encrypted after ReLU1: " << log2(y_encrypted.scale()) << " bits" << endl; 3107 | // cout << "#### The ReLU1 Done [" << time_diff.count() << " microseconds]" << endl; 3108 | 3109 | Ciphertext y1_encrypted = y_encrypted; 3110 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 3111 | for (int i = 1; i < run_times; i++) 3112 | { 3113 | time_start = chrono::high_resolution_clock::now(); 3114 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3115 | time_end = chrono::high_resolution_clock::now(); 3116 | time_diff = chrono::duration_cast(time_end - time_start); 3117 | Rot_latency[1] += time_diff.count(); 3118 | 3119 | time_start = chrono::high_resolution_clock::now(); 3120 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3121 | evaluator.add_inplace(y_encrypted, Result_tmp); 3122 | time_end = chrono::high_resolution_clock::now(); 3123 | time_diff = chrono::duration_cast(time_end - time_start); 3124 | Mul_latency[1] += time_diff.count(); 3125 | } 3126 | Rot_latency[1] = Rot_latency[1] / run_times; 3127 | Mul_latency[1] = Mul_latency[1] / run_times; 3128 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 3129 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 3130 | 3131 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 3132 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 3133 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3134 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3135 | // cout << " + Scale of y_encrypted after pool: " << log2(y_encrypted.scale()) << " bits (30)" << endl; 3136 | // cout << "#### The Pool Done [" << Mul_Cost_list[1] + Rot_Cost_list[1] << " ms]" << endl; 3137 | 3138 | y1_encrypted = y_encrypted; 3139 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3140 | for (int i = 1; i < run_times; i++) 3141 | { 3142 | time_start = chrono::high_resolution_clock::now(); 3143 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3144 | time_end = chrono::high_resolution_clock::now(); 3145 | time_diff = chrono::duration_cast(time_end - time_start); 3146 | Rot_latency[2] += time_diff.count(); 3147 | 3148 | time_start = chrono::high_resolution_clock::now(); 3149 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 3150 | evaluator.add_inplace(y_encrypted, Result_tmp); 3151 | time_end = chrono::high_resolution_clock::now(); 3152 | time_diff = chrono::duration_cast(time_end - time_start); 3153 | Mul_latency[2] += time_diff.count(); 3154 | } 3155 | Rot_latency[2] = Rot_latency[2] / run_times; 3156 | Mul_latency[2] = Mul_latency[2] / run_times; 3157 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 3158 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 3159 | 3160 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3161 | cout << "#### The Squeeze1 Done [" 3162 | << " ms]" << endl; 3163 | 3164 | evaluator.square_inplace(y_encrypted); // 60^2=120 3165 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3166 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3167 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3168 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3169 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3170 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3171 | // cout << "#### The ReLU2 Done [" << time_diff.count() << " microseconds]" << endl; 3172 | 3173 | y1_encrypted = y_encrypted; 3174 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 3175 | for (int i = 1; i < run_times; i++) 3176 | { 3177 | time_start = chrono::high_resolution_clock::now(); 3178 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3179 | time_end = chrono::high_resolution_clock::now(); 3180 | time_diff = chrono::duration_cast(time_end - time_start); 3181 | Rot_latency[3] += time_diff.count(); 3182 | 3183 | time_start = chrono::high_resolution_clock::now(); 3184 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 3185 | evaluator.add_inplace(y_encrypted, Result_tmp); 3186 | time_end = chrono::high_resolution_clock::now(); 3187 | time_diff = chrono::duration_cast(time_end - time_start); 3188 | Mul_latency[3] += time_diff.count(); 3189 | } 3190 | Rot_latency[3] = Rot_latency[3] / run_times; 3191 | Mul_latency[3] = Mul_latency[3] / run_times; 3192 | Rot_Cost[3] = Rot_latency[3] * Rot_number[3]; 3193 | Mul_Cost[3] = Mul_latency[3] * Mul_number[3]; 3194 | 3195 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 3196 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 3197 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3198 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3199 | 3200 | // cout << "#### The Expand1 Done [" << Mul_Cost_list[3] + Rot_Cost_list[3] << " ms]" << endl; 3201 | 3202 | evaluator.square_inplace(y_encrypted); // 40^2=80 3203 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3204 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 3205 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3206 | evaluator.rescale_to_next_inplace(y_encrypted); 3207 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3208 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3209 | 3210 | // cout << "#### The ReLU3 Done [" << time_diff.count() << " microseconds]" << endl; 3211 | 3212 | y1_encrypted = y_encrypted; 3213 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3214 | 3215 | for (int i = 1; i < run_times; i++) 3216 | { 3217 | time_start = chrono::high_resolution_clock::now(); 3218 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3219 | time_end = chrono::high_resolution_clock::now(); 3220 | time_diff = chrono::duration_cast(time_end - time_start); 3221 | Rot_latency[4] += time_diff.count(); 3222 | 3223 | time_start = chrono::high_resolution_clock::now(); 3224 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 3225 | evaluator.add_inplace(y_encrypted, Result_tmp); 3226 | time_end = chrono::high_resolution_clock::now(); 3227 | time_diff = chrono::duration_cast(time_end - time_start); 3228 | Mul_latency[4] += time_diff.count(); 3229 | } 3230 | 3231 | Rot_latency[4] = Rot_latency[4] / run_times; 3232 | Mul_latency[4] = Mul_latency[4] / run_times; 3233 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 3234 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 3235 | 3236 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3237 | // cout << "#### The Squeeze2 Done [" << Mul_Cost_list[4] + Rot_Cost_list[4] << " ms]" << endl; 3238 | 3239 | evaluator.square_inplace(y_encrypted); // 60^2=120 3240 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3241 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3242 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3243 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3244 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3245 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3246 | // cout << "#### The ReLU4 Done [" << time_diff.count() << " microseconds]" << endl; 3247 | 3248 | 3249 | 3250 | y1_encrypted = y_encrypted; 3251 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 3252 | 3253 | for (int i = 1; i < run_times; i++) 3254 | { 3255 | time_start = chrono::high_resolution_clock::now(); 3256 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3257 | time_end = chrono::high_resolution_clock::now(); 3258 | time_diff = chrono::duration_cast(time_end - time_start); 3259 | Rot_latency[6] += time_diff.count(); 3260 | 3261 | time_start = chrono::high_resolution_clock::now(); 3262 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 3263 | evaluator.add_inplace(y_encrypted, Result_tmp); 3264 | time_end = chrono::high_resolution_clock::now(); 3265 | time_diff = chrono::duration_cast(time_end - time_start); 3266 | Mul_latency[6] += time_diff.count(); 3267 | } 3268 | Rot_latency[6] = Rot_latency[6] / run_times; 3269 | Mul_latency[6] = Mul_latency[6] / run_times; 3270 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 3271 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 3272 | 3273 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 70+30=100, y_encrypted has 2 entries. 3274 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 3275 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3276 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3277 | 3278 | y1_encrypted = y_encrypted; 3279 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 40+30=70, y_encrypted has 3 entries. 3280 | 3281 | for (int i = 1; i < run_times; i++) 3282 | { 3283 | time_start = chrono::high_resolution_clock::now(); 3284 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3285 | time_end = chrono::high_resolution_clock::now(); 3286 | time_diff = chrono::duration_cast(time_end - time_start); 3287 | Rot_latency[7] += time_diff.count(); 3288 | 3289 | time_start = chrono::high_resolution_clock::now(); 3290 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 40+30=70, Result_tmp has 3 entries. 3291 | evaluator.add_inplace(y_encrypted, Result_tmp); 3292 | time_end = chrono::high_resolution_clock::now(); 3293 | time_diff = chrono::duration_cast(time_end - time_start); 3294 | Mul_latency[7] += time_diff.count(); 3295 | } 3296 | Rot_latency[7] = Rot_latency[7] / run_times; 3297 | Mul_latency[7] = Mul_latency[7] / run_times; 3298 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 3299 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 3300 | 3301 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 70, y_encrypted has 2 entries. 3302 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 3303 | 3304 | evaluator.square_inplace(y_encrypted); // 70^2=140 3305 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3306 | evaluator.rescale_to_next_inplace(y_encrypted); // 140-60=80 3307 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3308 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3309 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 80+10=90 3310 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3311 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 3312 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3313 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3314 | // cout << "#### The ReLU6 Done [" << time_diff.count() << " microseconds]" << endl; 3315 | 3316 | y1_encrypted = y_encrypted; 3317 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3318 | for (int i = 1; i < run_times; i++) 3319 | { 3320 | time_start = chrono::high_resolution_clock::now(); 3321 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3322 | time_end = chrono::high_resolution_clock::now(); 3323 | time_diff = chrono::duration_cast(time_end - time_start); 3324 | Rot_latency[9] += time_diff.count(); 3325 | 3326 | time_start = chrono::high_resolution_clock::now(); 3327 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 3328 | evaluator.add_inplace(y_encrypted, Result_tmp); 3329 | time_end = chrono::high_resolution_clock::now(); 3330 | time_diff = chrono::duration_cast(time_end - time_start); 3331 | Mul_latency[9] += time_diff.count(); 3332 | } 3333 | Rot_latency[9] = Rot_latency[9] / run_times; 3334 | Mul_latency[9] = Mul_latency[9] / run_times; 3335 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 3336 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 3337 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3338 | 3339 | 3340 | // cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 3341 | 3342 | evaluator.square_inplace(y_encrypted); // 60^2=120 3343 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3344 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3345 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3346 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3347 | 3348 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3349 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3350 | 3351 | // cout << "#### The ReLU8 Done [" << time_diff.count() << " microseconds]" << endl; 3352 | 3353 | y1_encrypted = y_encrypted; 3354 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 70+30=100, y_encrypted has 3 entries. 3355 | for (int i = 1; i < run_times; i++) 3356 | { 3357 | time_start = chrono::high_resolution_clock::now(); 3358 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3359 | time_end = chrono::high_resolution_clock::now(); 3360 | time_diff = chrono::duration_cast(time_end - time_start); 3361 | Rot_latency[11] += time_diff.count(); 3362 | 3363 | time_start = chrono::high_resolution_clock::now(); 3364 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 70+30=100, Result_tmp has 3 entries. 3365 | evaluator.add_inplace(y_encrypted, Result_tmp); 3366 | time_end = chrono::high_resolution_clock::now(); 3367 | time_diff = chrono::duration_cast(time_end - time_start); 3368 | Mul_latency[11] += time_diff.count(); 3369 | } 3370 | Rot_latency[11] = Rot_latency[11] / run_times; 3371 | Mul_latency[11] = Mul_latency[11] / run_times; 3372 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 3373 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 3374 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 100, y_encrypted has 2 entries. 3375 | evaluator.rescale_to_next_inplace(y_encrypted); // 100-60=40 3376 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3377 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3378 | // cout << "#### The Conv2 Done [" << Rot_Cost_list[11] + Mul_Cost_list[11] << " ms]" << endl; 3379 | 3380 | y1_encrypted = y_encrypted; 3381 | evaluator.multiply_plain(y1_encrypted, plain_coeff0, y_encrypted); // 40+10=50, y_encrypted has 3 entries. 3382 | for (int i = 1; i < run_times; i++) 3383 | { 3384 | time_start = chrono::high_resolution_clock::now(); 3385 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3386 | time_end = chrono::high_resolution_clock::now(); 3387 | time_diff = chrono::duration_cast(time_end - time_start); 3388 | Rot_latency[12] += time_diff.count(); 3389 | 3390 | time_start = chrono::high_resolution_clock::now(); 3391 | evaluator.multiply_plain(Rotated_tmp, plain_coeff0, Result_tmp); // 40+10=50, Result_tmp has 3 entries. 3392 | evaluator.add_inplace(y_encrypted, Result_tmp); 3393 | time_end = chrono::high_resolution_clock::now(); 3394 | time_diff = chrono::duration_cast(time_end - time_start); 3395 | Mul_latency[12] += time_diff.count(); 3396 | } 3397 | Rot_latency[12] = Rot_latency[12] / run_times; 3398 | Mul_latency[12] = Mul_latency[12] / run_times; 3399 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 3400 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 3401 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 50, y_encrypted has 2 entries. 3402 | 3403 | time_end = chrono::high_resolution_clock::now(); 3404 | time_diff = chrono::duration_cast(time_end - time_start); 3405 | 3406 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 3407 | 3408 | for (int i = 0; i < 13; i++) 3409 | { 3410 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] << " ms]" 3411 | << " Mult latency is " << +Mul_latency[i] << " ms]" << endl; 3412 | } 3413 | 3414 | double Rot_latency_total = 0.0; 3415 | double Mult_latency_total = 0.0; 3416 | for (int i = 0; i < 13; i++) 3417 | { 3418 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 3419 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 3420 | Rot_latency_total += Rot_Cost[i]; 3421 | Mult_latency_total += Mul_Cost[i]; 3422 | } 3423 | 3424 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 3425 | << " Mult latency is " << +Mult_latency_total << " ms]" 3426 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 3427 | } 3428 | 3429 | 3430 | void remove_fire1234() 3431 | { 3432 | chrono::high_resolution_clock::time_point time_start, time_end; 3433 | chrono::microseconds time_diff; 3434 | EncryptionParameters parms(scheme_type::CKKS); 3435 | 3436 | size_t poly_modulus_degree = 8192; 3437 | parms.set_poly_modulus_degree(poly_modulus_degree); 3438 | 3439 | 3440 | parms.set_coeff_modulus( 3441 | CoeffModulus::Create(poly_modulus_degree, {60, 60, 40, 60, 40, 60, 40, 60, 40, 60, 60, 60, 60 })); 3442 | //parms.set_coeff_modulus( 3443 | // CoeffModulus::Create(poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 40, 60, 60, 60, 60 })); 3444 | // parms.set_coeff_modulus(CoeffModulus::Create( 3445 | // poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 })); 3446 | 3447 | double input_scale = pow(2.0, 25); 3448 | double weight_scale = pow(2.0, 30); 3449 | double scalar_scale = pow(2.0, 10); 3450 | auto context = SEALContext::Create(parms, true, sec_level_type::none); 3451 | print_parameters(context); 3452 | cout << endl; 3453 | 3454 | KeyGenerator keygen(context); 3455 | auto public_key = keygen.public_key(); 3456 | auto secret_key = keygen.secret_key(); 3457 | auto relin_keys = keygen.relin_keys_local(); 3458 | GaloisKeys gal_keys = keygen.galois_keys_local(); 3459 | Encryptor encryptor(context, public_key); 3460 | Evaluator evaluator(context); 3461 | Decryptor decryptor(context, secret_key); 3462 | 3463 | CKKSEncoder encoder(context); 3464 | size_t slot_count = encoder.slot_count(); 3465 | cout << "Number of slots: " << slot_count << endl; 3466 | 3467 | vector input; 3468 | input.reserve(slot_count); 3469 | double curr_point = 0; 3470 | double step_size = 1.0 / (static_cast(slot_count) - 1); 3471 | for (size_t i = 0; i < slot_count; i++, curr_point += step_size) 3472 | { 3473 | input.push_back(curr_point); 3474 | } 3475 | cout << "Input vector: " << endl; 3476 | print_vector(input, 3, 7); 3477 | 3478 | Plaintext plain_coeff3, plain_coeff0; 3479 | // encoder.encode(3.14159265, scale, plain_coeff3); 3480 | encoder.encode(0.4, weight_scale, plain_coeff3); 3481 | encoder.encode(1.0, scalar_scale, plain_coeff0); 3482 | 3483 | Plaintext x_plain; 3484 | print_line(__LINE__); 3485 | cout << "Encode input vectors." << endl; 3486 | encoder.encode(input, input_scale, x_plain); 3487 | Ciphertext x1_encrypted; 3488 | encryptor.encrypt(x_plain, x1_encrypted); 3489 | 3490 | Ciphertext y_encrypted; 3491 | print_line(__LINE__); 3492 | 3493 | // double HE_Mul_list[12] = { 1.728, 0.256, 36.864, 0, 2.048, 20.470, 0.256, 2.048, 40.960, 4.096, 40.960, 2.560 }; 3494 | // double HE_Rot_list[12] = { 0.027, 0.256, 0.576, 0, 0.064, 0.320, 0.256, 0.064, 0.320, 0.128, 0.320, 0.256 }; 3495 | 3496 | //double HE_Mul_list[12] = { 1.728, 0.256, 2.048, 20.470, 36.864, 0, 0.256, 73.728, 0, 147.456, 0, 2.560 }; 3497 | //double HE_Rot_list[12] = { 0.027, 0.256, 0.064, 0.320, 0.576, 0, 0.256, 0.576, 0, 1.152, 0, 0.256 }; 3498 | 3499 | 3500 | double Mul_number[13] = { 1.728, 0.256, 36.864, 0, 36.864, 0, 0.256, 73.728, 0, 147.456, 0, 2.560, 1.280}; 3501 | double Rot_number[13] = { 0.027, 0.256, 0.576, 0, 0.576, 0, 0.256, 0.576, 0, 1.152, 0, 0.256, 0.128}; 3502 | double Rot_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3503 | double Mul_Cost[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3504 | double Rot_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3505 | double Mul_latency[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 3506 | 3507 | evaluator.multiply_plain(x1_encrypted, plain_coeff3, y_encrypted); // 25+30=55, y_encrypted has 3 entries. 3508 | Ciphertext Rotated_tmp, Result_tmp; 3509 | int run_times = 10; 3510 | for (int i = 1; i < run_times; i++) 3511 | { 3512 | time_start = chrono::high_resolution_clock::now(); 3513 | evaluator.rotate_vector(x1_encrypted, i, gal_keys, Rotated_tmp); 3514 | time_end = chrono::high_resolution_clock::now(); 3515 | time_diff = chrono::duration_cast(time_end - time_start); 3516 | Rot_latency[0] += time_diff.count(); 3517 | 3518 | time_start = chrono::high_resolution_clock::now(); 3519 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 25+30=55, Result_tmp has 3 entries. 3520 | evaluator.add_inplace(y_encrypted, Result_tmp); 3521 | time_end = chrono::high_resolution_clock::now(); 3522 | time_diff = chrono::duration_cast(time_end - time_start); 3523 | Mul_latency[0] += time_diff.count(); 3524 | } 3525 | Rot_latency[0] = Rot_latency[0] / run_times; 3526 | Mul_latency[0] = Mul_latency[0] / run_times; 3527 | Rot_Cost[0] = Rot_latency[0] * Rot_number[0]; 3528 | Mul_Cost[0] = Mul_latency[0] * Mul_number[0]; 3529 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 25+30=55, y_encrypted has 2 entries. 3530 | cout << "#### The conv1 Done [" << " ms]" << endl; 3531 | 3532 | evaluator.square_inplace(y_encrypted); // 55^2=110 3533 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3534 | evaluator.rescale_to_next_inplace(y_encrypted); // 110-60=50 3535 | // cout << " + Scale of y_encrypted after square: " << log2(y_encrypted.scale()) << " bits (50)" << endl; 3536 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3537 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3538 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 50+10=60 3539 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3540 | 3541 | // cout << " + Scale of x1_encrypted after ReLU1: " << log2(y_encrypted.scale()) << " bits" << endl; 3542 | cout << "#### The ReLU1 Done [" << " microseconds]" << endl; 3543 | 3544 | Ciphertext y1_encrypted = y_encrypted; 3545 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 3546 | for (int i = 1; i < run_times; i++) 3547 | { 3548 | time_start = chrono::high_resolution_clock::now(); 3549 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3550 | time_end = chrono::high_resolution_clock::now(); 3551 | time_diff = chrono::duration_cast(time_end - time_start); 3552 | Rot_latency[1] += time_diff.count(); 3553 | 3554 | time_start = chrono::high_resolution_clock::now(); 3555 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3556 | evaluator.add_inplace(y_encrypted, Result_tmp); 3557 | time_end = chrono::high_resolution_clock::now(); 3558 | time_diff = chrono::duration_cast(time_end - time_start); 3559 | Mul_latency[1] += time_diff.count(); 3560 | } 3561 | Rot_latency[1] = Rot_latency[1] / run_times; 3562 | Mul_latency[1] = Mul_latency[1] / run_times; 3563 | Rot_Cost[1] = Rot_latency[1] * Rot_number[1]; 3564 | Mul_Cost[1] = Mul_latency[1] * Mul_number[1]; 3565 | 3566 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 3567 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30, y_encrypted has 2 entries. 3568 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3569 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3570 | // cout << " + Scale of y_encrypted after pool: " << log2(y_encrypted.scale()) << " bits (30)" << endl; 3571 | // cout << "#### The Pool Done [" << Mul_Cost_list[1] + Rot_Cost_list[1] << " ms]" << endl; 3572 | 3573 | y1_encrypted = y_encrypted; 3574 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3575 | for (int i = 1; i < run_times; i++) 3576 | { 3577 | time_start = chrono::high_resolution_clock::now(); 3578 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3579 | time_end = chrono::high_resolution_clock::now(); 3580 | time_diff = chrono::duration_cast(time_end - time_start); 3581 | Rot_latency[2] += time_diff.count(); 3582 | 3583 | time_start = chrono::high_resolution_clock::now(); 3584 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3585 | evaluator.add_inplace(y_encrypted, Result_tmp); 3586 | time_end = chrono::high_resolution_clock::now(); 3587 | time_diff = chrono::duration_cast(time_end - time_start); 3588 | Mul_latency[2] += time_diff.count(); 3589 | } 3590 | Rot_latency[2] = Rot_latency[2] / run_times; 3591 | Mul_latency[2] = Mul_latency[2] / run_times; 3592 | Rot_Cost[2] = Rot_latency[2] * Rot_number[2]; 3593 | Mul_Cost[2] = Mul_latency[2] * Mul_number[2]; 3594 | 3595 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3596 | // cout << "#### The Squeeze1 Done [" << Mul_Cost_list[2] + Rot_Cost_list[2] << " ms]" << endl; 3597 | 3598 | evaluator.square_inplace(y_encrypted); // 60^2=120 3599 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3600 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3601 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3602 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3603 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3604 | 3605 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3606 | evaluator.rescale_to_next_inplace(y_encrypted); // 70-40=30 3607 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3608 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3609 | 3610 | // cout << "#### The ReLU3 Done [" << time_diff.count() << " microseconds]" << endl; 3611 | 3612 | y1_encrypted = y_encrypted; 3613 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3614 | 3615 | for (int i = 1; i < run_times; i++) 3616 | { 3617 | time_start = chrono::high_resolution_clock::now(); 3618 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3619 | time_end = chrono::high_resolution_clock::now(); 3620 | time_diff = chrono::duration_cast(time_end - time_start); 3621 | Rot_latency[4] += time_diff.count(); 3622 | 3623 | time_start = chrono::high_resolution_clock::now(); 3624 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 30+30=60, Result_tmp has 3 entries. 3625 | evaluator.add_inplace(y_encrypted, Result_tmp); 3626 | time_end = chrono::high_resolution_clock::now(); 3627 | time_diff = chrono::duration_cast(time_end - time_start); 3628 | Mul_latency[4] += time_diff.count(); 3629 | } 3630 | 3631 | Rot_latency[4] = Rot_latency[4] / run_times; 3632 | Mul_latency[4] = Mul_latency[4] / run_times; 3633 | Rot_Cost[4] = Rot_latency[4] * Rot_number[4]; 3634 | Mul_Cost[4] = Mul_latency[4] * Mul_number[4]; 3635 | 3636 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3637 | // cout << "#### The Squeeze2 Done [" << Mul_Cost_list[4] + Rot_Cost_list[4] << " ms]" << endl; 3638 | 3639 | evaluator.square_inplace(y_encrypted); // 60^2=120 3640 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3641 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3642 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3643 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3644 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3645 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3646 | 3647 | evaluator.rescale_to_next_inplace(y_encrypted); // 70-40=30 3648 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3649 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3650 | 3651 | 3652 | 3653 | y1_encrypted = y_encrypted; 3654 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3655 | 3656 | for (int i = 1; i < run_times; i++) 3657 | { 3658 | time_start = chrono::high_resolution_clock::now(); 3659 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3660 | time_end = chrono::high_resolution_clock::now(); 3661 | time_diff = chrono::duration_cast(time_end - time_start); 3662 | Rot_latency[6] += time_diff.count(); 3663 | 3664 | time_start = chrono::high_resolution_clock::now(); 3665 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3666 | evaluator.add_inplace(y_encrypted, Result_tmp); 3667 | time_end = chrono::high_resolution_clock::now(); 3668 | time_diff = chrono::duration_cast(time_end - time_start); 3669 | Mul_latency[6] += time_diff.count(); 3670 | } 3671 | Rot_latency[6] = Rot_latency[6] / run_times; 3672 | Mul_latency[6] = Mul_latency[6] / run_times; 3673 | Rot_Cost[6] = Rot_latency[6] * Rot_number[6]; 3674 | Mul_Cost[6] = Mul_latency[6] * Mul_number[6]; 3675 | 3676 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60+30=90, y_encrypted has 2 entries. 3677 | y1_encrypted = y_encrypted; 3678 | 3679 | 3680 | 3681 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 3682 | for (int i = 1; i < run_times; i++) 3683 | { 3684 | time_start = chrono::high_resolution_clock::now(); 3685 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3686 | time_end = chrono::high_resolution_clock::now(); 3687 | time_diff = chrono::duration_cast(time_end - time_start); 3688 | Rot_latency[7] += time_diff.count(); 3689 | 3690 | time_start = chrono::high_resolution_clock::now(); 3691 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3692 | evaluator.add_inplace(y_encrypted, Result_tmp); 3693 | time_end = chrono::high_resolution_clock::now(); 3694 | time_diff = chrono::duration_cast(time_end - time_start); 3695 | Mul_latency[7] += time_diff.count(); 3696 | } 3697 | Rot_latency[7] = Rot_latency[7] / run_times; 3698 | Mul_latency[7] = Mul_latency[7] / run_times; 3699 | Rot_Cost[7] = Rot_latency[7] * Rot_number[7]; 3700 | Mul_Cost[7] = Mul_latency[7] * Mul_number[7]; 3701 | 3702 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 3703 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-60=30 3704 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3705 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3706 | // cout << "#### The Squeeze3 Done [" << Rot_Cost_list[7] + Mul_Cost_list[7] << " ms]" << endl; 3707 | 3708 | evaluator.square_inplace(y_encrypted); // 30^2=60 3709 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3710 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3711 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3712 | evaluator.rescale_to_next_inplace(y_encrypted); //70-40=30 3713 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3714 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3715 | cout << "#### The ReLU7 Done microseconds]" << endl; 3716 | 3717 | y1_encrypted = y_encrypted; 3718 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3719 | for (int i = 1; i < run_times; i++) 3720 | { 3721 | time_start = chrono::high_resolution_clock::now(); 3722 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3723 | time_end = chrono::high_resolution_clock::now(); 3724 | time_diff = chrono::duration_cast(time_end - time_start); 3725 | Rot_latency[9] += time_diff.count(); 3726 | 3727 | time_start = chrono::high_resolution_clock::now(); 3728 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3729 | evaluator.add_inplace(y_encrypted, Result_tmp); 3730 | time_end = chrono::high_resolution_clock::now(); 3731 | time_diff = chrono::duration_cast(time_end - time_start); 3732 | Mul_latency[9] += time_diff.count(); 3733 | } 3734 | Rot_latency[9] = Rot_latency[9] / run_times; 3735 | Mul_latency[9] = Mul_latency[9] / run_times; 3736 | Rot_Cost[9] = Rot_latency[9] * Rot_number[9]; 3737 | Mul_Cost[9] = Mul_latency[9] * Mul_number[9]; 3738 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3739 | // cout << "#### The Squeeze4 Done [" << Rot_Cost_list[9] + Mul_Cost_list[9] << " ms]" << endl; 3740 | 3741 | evaluator.square_inplace(y_encrypted); // 60^2=120 3742 | evaluator.relinearize_inplace(y_encrypted, relin_keys); 3743 | evaluator.rescale_to_next_inplace(y_encrypted); // 120-60=60 3744 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3745 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3746 | evaluator.multiply_plain_inplace(y_encrypted, plain_coeff0); // 60+10=70 3747 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 3748 | 3749 | evaluator.rescale_to_next_inplace(y_encrypted); // 70-40=30 3750 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3751 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3752 | cout << "#### The ReLU9 Done " << endl; 3753 | 3754 | y1_encrypted = y_encrypted; 3755 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 30+30=60, y_encrypted has 3 entries. 3756 | for (int i = 1; i < run_times; i++) 3757 | { 3758 | time_start = chrono::high_resolution_clock::now(); 3759 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3760 | time_end = chrono::high_resolution_clock::now(); 3761 | time_diff = chrono::duration_cast(time_end - time_start); 3762 | Rot_latency[11] += time_diff.count(); 3763 | 3764 | time_start = chrono::high_resolution_clock::now(); 3765 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3766 | evaluator.add_inplace(y_encrypted, Result_tmp); 3767 | time_end = chrono::high_resolution_clock::now(); 3768 | time_diff = chrono::duration_cast(time_end - time_start); 3769 | Mul_latency[11] += time_diff.count(); 3770 | } 3771 | Rot_latency[11] = Rot_latency[11] / run_times; 3772 | Mul_latency[11] = Mul_latency[11] / run_times; 3773 | Rot_Cost[11] = Rot_latency[11] * Rot_number[11]; 3774 | Mul_Cost[11] = Mul_latency[11] * Mul_number[11]; 3775 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 60, y_encrypted has 2 entries. 3776 | cout << "#### The Conv2 Done [" " ms]" << endl; 3777 | 3778 | y1_encrypted = y_encrypted; 3779 | evaluator.multiply_plain(y1_encrypted, plain_coeff3, y_encrypted); // 60+30=90, y_encrypted has 3 entries. 3780 | for (int i = 1; i < run_times; i++) 3781 | { 3782 | time_start = chrono::high_resolution_clock::now(); 3783 | evaluator.rotate_vector(y1_encrypted, i, gal_keys, Rotated_tmp); 3784 | time_end = chrono::high_resolution_clock::now(); 3785 | time_diff = chrono::duration_cast(time_end - time_start); 3786 | Rot_latency[12] += time_diff.count(); 3787 | 3788 | time_start = chrono::high_resolution_clock::now(); 3789 | evaluator.multiply_plain(Rotated_tmp, plain_coeff3, Result_tmp); // 60+30=90, Result_tmp has 3 entries. 3790 | evaluator.add_inplace(y_encrypted, Result_tmp); 3791 | time_end = chrono::high_resolution_clock::now(); 3792 | time_diff = chrono::duration_cast(time_end - time_start); 3793 | Mul_latency[12] += time_diff.count(); 3794 | } 3795 | Rot_latency[12] = Rot_latency[12] / run_times; 3796 | Mul_latency[12] = Mul_latency[12] / run_times; 3797 | Rot_Cost[12] = Rot_latency[12] * Rot_number[12]; 3798 | Mul_Cost[12] = Mul_latency[12] * Mul_number[12]; 3799 | evaluator.relinearize_inplace(y_encrypted, relin_keys); // 90, y_encrypted has 2 entries. 3800 | time_end = chrono::high_resolution_clock::now(); 3801 | time_diff = chrono::duration_cast(time_end - time_start); 3802 | evaluator.rescale_to_next_inplace(y_encrypted); // 90-30=60, Result_tmp has 2 entries. 3803 | evaluator.mod_switch_to_next_inplace(plain_coeff3); 3804 | evaluator.mod_switch_to_next_inplace(plain_coeff0); 3805 | cout << "#### The pool3 Done [" << time_diff.count() << " microseconds]" << endl; 3806 | 3807 | for (int i = 0; i < 13; i++) 3808 | { 3809 | cout << "The " << i << " layer Rot latency is [" << Rot_latency[i] / 1000 << " ms]" 3810 | << " Mult latency is " << +Mul_latency[i] / 1000 << " ms]" << endl; 3811 | } 3812 | 3813 | double Rot_latency_total = 0.0; 3814 | double Mult_latency_total = 0.0; 3815 | for (int i = 0; i < 13; i++) 3816 | { 3817 | cout << "The " << i << " layer **Total** Rot latency is [" << Rot_Cost[i] << " ms]" 3818 | << " **Total** Mult latency is " << +Mul_Cost[i] << " ms]" << endl; 3819 | Rot_latency_total += Rot_Cost[i]; 3820 | Mult_latency_total += Mul_Cost[i]; 3821 | } 3822 | 3823 | cout << "The Rot latency is [" << Rot_latency_total << " ms]" 3824 | << " Mult latency is " << +Mult_latency_total << " ms]" 3825 | << " Total latency is " << +(Rot_latency_total + Mult_latency_total) / 1000 << " s]" << endl; 3826 | } 3827 | 3828 | 3829 | void example_squeezenet() 3830 | { 3831 | squeeze(); 3832 | remove_fire4(); 3833 | remove_fire34(); 3834 | remove_fire234(); 3835 | remove_fire34_merge(); 3836 | } --------------------------------------------------------------------------------