1
+ #ifndef FHE_IMAGE_H
2
+ #define FHE_IMAGE_H
3
+
4
+ #include < iostream>
5
+ #include < iomanip>
6
+ #include < vector>
7
+ #include < string>
8
+ #include < chrono>
9
+ #include < random>
10
+ #include < thread>
11
+ #include < mutex>
12
+ #include < random>
13
+ #include < limits>
14
+ #include < fstream>
15
+ #include < cmath>
16
+
17
+
18
+ #include " seal/seal.h"
19
+ using namespace seal ;
20
+
21
+
22
+ const int BLOCK_SIZE = 8 ;
23
+ std::vector<std::vector<double >> split_image_eight_block (std::vector<double > im, int w, int h) {
24
+ std::vector<std::vector<double >> lst;
25
+ for (int i = 0 ; i < w; i += BLOCK_SIZE) {
26
+ for (int j = 0 ; j < h; j += BLOCK_SIZE) {
27
+ std::vector<double > new_lst;
28
+ for (int k = 0 ; k < BLOCK_SIZE; k++)
29
+ for (int l = 0 ; l < BLOCK_SIZE; l++) {
30
+ int index = (j+k)*w + i + l;
31
+ new_lst.push_back (im[index ]);
32
+ }
33
+ lst.push_back (new_lst);
34
+ }
35
+ }
36
+ return lst;
37
+ }
38
+
39
+ void print_image (std::vector<double > &im, int w, int h) {
40
+ std::cout << " Printing Image dim: (" << w << " ," << h << " )" << std::endl;
41
+ for (int i = 0 ; i < im.size (); i++) {
42
+ std::cout << std::setw (11 ) << im[i] << " " ;
43
+ if ((i + 1 ) % w == 0 ) std::cout << std::endl;
44
+ }
45
+ }
46
+
47
+
48
+ void print_blocks (std::vector<std::vector<double >> &blocks) {
49
+ for (int a = 0 ; a < blocks.size (); a++) {
50
+ std::cout << " Printing block " << a << std::endl;
51
+ for (int i = 0 ; i < blocks[a].size (); i++) {
52
+ std::cout << std::setw (11 ) << blocks[a][i] << " " ;
53
+ if ((i + 1 ) % BLOCK_SIZE == 0 ) std::cout << std::endl;
54
+ }
55
+ std::cout << " ---------------" << std::endl;
56
+ }
57
+ }
58
+
59
+ std::vector<double > read_image (std::string fname) {
60
+ int w, h;
61
+ std::vector<double > im;
62
+ std::ifstream myfile;
63
+
64
+ myfile.open (fname.c_str ());
65
+ myfile >> w;
66
+ myfile >> h;
67
+ std::cout << " Read in " << fname << " with dimensions: " << w << " x " << h << std::endl;
68
+
69
+ float tmp;
70
+ for (int i = 0 ; i < w*h; i++) {
71
+ myfile >> tmp;
72
+ im.push_back (tmp);
73
+ }
74
+ return im;
75
+ }
76
+
77
+
78
+ /* Recieves a 8x8 box of pixels, in ciphertext form.
79
+ * Data should be laid out in a 64 element vector with
80
+ * rows first then columns
81
+ */
82
+ void encrypted_dct (std::vector<Ciphertext> &data,
83
+ Evaluator &evaluator,
84
+ FractionalEncoder &encoder,
85
+ Encryptor &encryptor) {
86
+ Ciphertext z1, z2, z3, z4, z5;
87
+ Ciphertext tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp10, tmp11, tmp12, tmp13;
88
+ Ciphertext tmp14;
89
+ Ciphertext cons1;
90
+ int curr_index = 0 ;
91
+ for (int c = 0 ; c < BLOCK_SIZE; c++) {
92
+ Ciphertext boaz1 (data[curr_index+0 ]); evaluator.add (boaz1, data[curr_index+7 ]); tmp0 = boaz1;
93
+ Ciphertext boaz2 (data[curr_index+0 ]); evaluator.sub (boaz2, data[curr_index+7 ]); tmp7 = boaz2;
94
+ Ciphertext boaz3 (data[curr_index+1 ]); evaluator.add (boaz3, data[curr_index+6 ]); tmp1 = boaz3;
95
+ Ciphertext boaz4 (data[curr_index+1 ]); evaluator.sub (boaz4, data[curr_index+6 ]); tmp6 = boaz4;
96
+ Ciphertext boaz5 (data[curr_index+2 ]); evaluator.add (boaz5, data[curr_index+5 ]); tmp2 = boaz5;
97
+ Ciphertext boaz6 (data[curr_index+2 ]); evaluator.sub (boaz6, data[curr_index+5 ]); tmp5 = boaz6;
98
+ Ciphertext boaz7 (data[curr_index+3 ]); evaluator.add (boaz7, data[curr_index+4 ]); tmp3 = boaz7;
99
+ Ciphertext boaz8 (data[curr_index+3 ]); evaluator.sub (boaz8, data[curr_index+4 ]); tmp4 = boaz8;
100
+ Ciphertext boaz9 (tmp0); evaluator.add (boaz9, tmp3); tmp10 = boaz9;
101
+ Ciphertext boaz10 (tmp0); evaluator.sub (boaz10, tmp3); tmp13 = boaz10;
102
+ Ciphertext boaz11 (tmp1); evaluator.add (boaz11, tmp2); tmp11 = boaz11;
103
+ Ciphertext boaz12 (tmp1); evaluator.sub (boaz12, tmp2); tmp12 = boaz12;
104
+ Ciphertext boaz13 (tmp10); evaluator.add (boaz13, tmp11); data[curr_index+0 ] = boaz13;
105
+ Ciphertext boaz14 (tmp10); evaluator.sub (boaz14, tmp11); data[curr_index+4 ] = boaz14;
106
+ Ciphertext boaz15 (tmp12); evaluator.add (boaz15, tmp13); Ciphertext boaz16 (boaz15); evaluator.multiply_plain (boaz16, encoder.encode (0.541196100 )); z1 = boaz16;
107
+ Ciphertext boaz17 (tmp13); evaluator.multiply_plain (boaz17, encoder.encode (0.765366865 )); Ciphertext boaz18 (z1); evaluator.add (boaz18, boaz17); data[curr_index+2 ] = boaz18;
108
+ Ciphertext boaz19 (tmp12); evaluator.multiply_plain (boaz19, encoder.encode (-1.847759065 )); Ciphertext boaz20 (z1); evaluator.add (boaz20, boaz19); data[curr_index+6 ] = boaz20;
109
+ Ciphertext boaz21 (tmp4); evaluator.add (boaz21, tmp7); z1 = boaz21;
110
+ Ciphertext boaz22 (tmp5); evaluator.add (boaz22, tmp6); z2 = boaz22;
111
+ Ciphertext boaz23 (tmp4); evaluator.add (boaz23, tmp6); z3 = boaz23;
112
+ Ciphertext boaz24 (tmp5); evaluator.add (boaz24, tmp7); z4 = boaz24;
113
+ Ciphertext boaz25 (z3); evaluator.add (boaz25, z4); Ciphertext boaz26 (boaz25); evaluator.multiply_plain (boaz26, encoder.encode (1.175875602 )); z5 = boaz26;
114
+ Ciphertext boaz27 (tmp4); evaluator.multiply_plain (boaz27, encoder.encode (0.298631336 )); tmp4 = boaz27;
115
+ Ciphertext boaz28 (tmp5); evaluator.multiply_plain (boaz28, encoder.encode (2.053119869 )); tmp5 = boaz28;
116
+ Ciphertext boaz29 (tmp6); evaluator.multiply_plain (boaz29, encoder.encode (3.072711026 )); tmp6 = boaz29;
117
+ Ciphertext boaz30 (tmp7); evaluator.multiply_plain (boaz30, encoder.encode (1.501321110 )); tmp7 = boaz30;
118
+ Ciphertext boaz31 (z1); evaluator.multiply_plain (boaz31, encoder.encode (-0.899976223 )); z1 = boaz31;
119
+ Ciphertext boaz32 (z2); evaluator.multiply_plain (boaz32, encoder.encode (-2.562915447 )); z2 = boaz32;
120
+ Ciphertext boaz33 (z3); evaluator.multiply_plain (boaz33, encoder.encode (-1.961570560 )); z3 = boaz33;
121
+ Ciphertext boaz34 (z4); evaluator.multiply_plain (boaz34, encoder.encode (-0.390180644 )); z4 = boaz34;
122
+ Ciphertext boaz35 (z3); evaluator.add (boaz35, z5); z3 = boaz35;
123
+ Ciphertext boaz36 (z4); evaluator.add (boaz36, z5); z4 = boaz36;
124
+ Ciphertext boaz37 (tmp4); evaluator.add (boaz37, z1); Ciphertext boaz38 (boaz37); evaluator.add (boaz38, z3); data[curr_index+7 ] = boaz38;
125
+ Ciphertext boaz39 (tmp5); evaluator.add (boaz39, z2); Ciphertext boaz40 (boaz39); evaluator.add (boaz40, z4); data[curr_index+5 ] = boaz40;
126
+ Ciphertext boaz41 (tmp6); evaluator.add (boaz41, z2); Ciphertext boaz42 (boaz41); evaluator.add (boaz42, z3); data[curr_index+3 ] = boaz42;
127
+ Ciphertext boaz43 (tmp7); evaluator.add (boaz43, z1); Ciphertext boaz44 (boaz43); evaluator.add (boaz44, z4); data[curr_index+1 ] = boaz44;
128
+ curr_index += BLOCK_SIZE;
129
+ }
130
+ curr_index = 0 ;
131
+ for (int c = 0 ; c < BLOCK_SIZE; c++) {
132
+ Ciphertext boaz45 (data[curr_index+0 ]); evaluator.add (boaz45, data[curr_index+56 ]); tmp0 = boaz45;
133
+ Ciphertext boaz46 (data[curr_index+0 ]); evaluator.sub (boaz46, data[curr_index+56 ]); tmp7 = boaz46;
134
+ Ciphertext boaz47 (data[curr_index+8 ]); evaluator.add (boaz47, data[curr_index+48 ]); tmp1 = boaz47;
135
+ Ciphertext boaz48 (data[curr_index+8 ]); evaluator.sub (boaz48, data[curr_index+48 ]); tmp6 = boaz48;
136
+ Ciphertext boaz49 (data[curr_index+16 ]); evaluator.add (boaz49, data[curr_index+40 ]); tmp2 = boaz49;
137
+ Ciphertext boaz50 (data[curr_index+16 ]); evaluator.sub (boaz50, data[curr_index+40 ]); tmp5 = boaz50;
138
+ Ciphertext boaz51 (data[curr_index+24 ]); evaluator.add (boaz51, data[curr_index+32 ]); tmp3 = boaz51;
139
+ Ciphertext boaz52 (data[curr_index+24 ]); evaluator.sub (boaz52, data[curr_index+32 ]); tmp4 = boaz52;
140
+ Ciphertext boaz53 (tmp0); evaluator.add (boaz53, tmp3); tmp10 = boaz53;
141
+ Ciphertext boaz54 (tmp0); evaluator.sub (boaz54, tmp3); tmp13 = boaz54;
142
+ Ciphertext boaz55 (tmp1); evaluator.add (boaz55, tmp2); tmp11 = boaz55;
143
+ Ciphertext boaz56 (tmp1); evaluator.sub (boaz56, tmp2); tmp12 = boaz56;
144
+ Ciphertext boaz57 (tmp10); evaluator.add (boaz57, tmp11); Ciphertext boaz58 (boaz57); evaluator.multiply_plain (boaz58, encoder.encode (0.125 )); data[curr_index+0 ] = boaz58;
145
+ Ciphertext boaz59 (tmp10); evaluator.sub (boaz59, tmp11); Ciphertext boaz60 (boaz59); evaluator.multiply_plain (boaz60, encoder.encode (0.125 )); data[curr_index+32 ] = boaz60;
146
+ Ciphertext boaz61 (tmp12); evaluator.add (boaz61, tmp13); Ciphertext boaz62 (boaz61); evaluator.multiply_plain (boaz62, encoder.encode (0.541196100 )); z1 = boaz62;
147
+ Ciphertext boaz63 (tmp13); evaluator.multiply_plain (boaz63, encoder.encode (0.765366865 )); Ciphertext boaz64 (z1); evaluator.add (boaz64, boaz63); Ciphertext boaz65 (boaz64); evaluator.multiply_plain (boaz65, encoder.encode (0.125 )); data[curr_index+16 ] = boaz65;
148
+ Ciphertext boaz66 (tmp12); evaluator.multiply_plain (boaz66, encoder.encode (-1.847759065 )); Ciphertext boaz67 (z1); evaluator.add (boaz67, boaz66); Ciphertext boaz68 (boaz67); evaluator.multiply_plain (boaz68, encoder.encode (0.125 )); data[curr_index+48 ] = boaz68;
149
+ Ciphertext boaz69 (tmp4); evaluator.add (boaz69, tmp7); z1 = boaz69;
150
+ Ciphertext boaz70 (tmp5); evaluator.add (boaz70, tmp6); z2 = boaz70;
151
+ Ciphertext boaz71 (tmp4); evaluator.add (boaz71, tmp6); z3 = boaz71;
152
+ Ciphertext boaz72 (tmp5); evaluator.add (boaz72, tmp7); z4 = boaz72;
153
+ Ciphertext boaz73 (z3); evaluator.add (boaz73, z4); Ciphertext boaz74 (boaz73); evaluator.multiply_plain (boaz74, encoder.encode (1.175875602 )); z5 = boaz74;
154
+ Ciphertext boaz75 (tmp4); evaluator.multiply_plain (boaz75, encoder.encode (0.298631336 )); tmp4 = boaz75;
155
+ Ciphertext boaz76 (tmp5); evaluator.multiply_plain (boaz76, encoder.encode (2.053119869 )); tmp5 = boaz76;
156
+ Ciphertext boaz77 (tmp6); evaluator.multiply_plain (boaz77, encoder.encode (3.072711026 )); tmp6 = boaz77;
157
+ Ciphertext boaz78 (tmp7); evaluator.multiply_plain (boaz78, encoder.encode (1.501321110 )); tmp7 = boaz78;
158
+ Ciphertext boaz79 (z1); evaluator.multiply_plain (boaz79, encoder.encode (-0.899976223 )); z1 = boaz79;
159
+ Ciphertext boaz80 (z2); evaluator.multiply_plain (boaz80, encoder.encode (-2.562915447 )); z2 = boaz80;
160
+ Ciphertext boaz81 (z3); evaluator.multiply_plain (boaz81, encoder.encode (-1.961570560 )); z3 = boaz81;
161
+ Ciphertext boaz82 (z4); evaluator.multiply_plain (boaz82, encoder.encode (-0.390180644 )); z4 = boaz82;
162
+ Ciphertext boaz83 (z3); evaluator.add (boaz83, z5); z3 = boaz83;
163
+ Ciphertext boaz84 (z4); evaluator.add (boaz84, z5); z4 = boaz84;
164
+ Ciphertext boaz85 (tmp4); evaluator.add (boaz85, z1); Ciphertext boaz86 (boaz85); evaluator.add (boaz86, z3); Ciphertext boaz87 (boaz86); evaluator.multiply_plain (boaz87, encoder.encode (0.125 )); data[curr_index+56 ] = boaz87;
165
+ Ciphertext boaz88 (tmp5); evaluator.add (boaz88, z2); Ciphertext boaz89 (boaz88); evaluator.add (boaz89, z4); Ciphertext boaz90 (boaz89); evaluator.multiply_plain (boaz90, encoder.encode (0.125 )); data[curr_index+40 ] = boaz90;
166
+ Ciphertext boaz91 (tmp6); evaluator.add (boaz91, z2); Ciphertext boaz92 (boaz91); evaluator.add (boaz92, z3); Ciphertext boaz93 (boaz92); evaluator.multiply_plain (boaz93, encoder.encode (0.125 )); data[curr_index+24 ] = boaz93;
167
+ Ciphertext boaz94 (tmp7); evaluator.add (boaz94, z1); Ciphertext boaz95 (boaz94); evaluator.add (boaz95, z4); Ciphertext boaz96 (boaz95); evaluator.multiply_plain (boaz96, encoder.encode (0.125 )); data[curr_index+8 ]= boaz96;
168
+ curr_index++;
169
+ }
170
+ return ;
171
+ }
172
+
173
+ /* Recieves a 8x8 box of pixels, in ciphertext form.
174
+ * Data should be laid out in a 64 element vector with
175
+ * rows first then columns. Divides each element by quant
176
+ */
177
+ inline void quantize_fhe (std::vector<Ciphertext> &data,
178
+ const std::vector<double > &quant,
179
+ Evaluator &evaluator,
180
+ FractionalEncoder &encoder,
181
+ Encryptor &encryptor) {
182
+ for (int i = 0 ; i < 64 ; i++) {
183
+ evaluator.multiply_plain (data[i], encoder.encode (1 /quant[i]));
184
+ }
185
+ }
186
+
187
+
188
+
189
+
190
+
191
+ // Forward DCT, regular no encryption
192
+ inline void dct (double *data) {
193
+ double z1, z2, z3, z4, z5, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp10, tmp11, tmp12, tmp13, *data_ptr;
194
+ data_ptr = data;
195
+ for (int c=0 ; c < 8 ; c++) {
196
+ tmp0 = data_ptr[0 ] + data_ptr[7 ];
197
+ tmp7 = data_ptr[0 ] - data_ptr[7 ];
198
+ tmp1 = data_ptr[1 ] + data_ptr[6 ];
199
+ tmp6 = data_ptr[1 ] - data_ptr[6 ];
200
+ tmp2 = data_ptr[2 ] + data_ptr[5 ];
201
+ tmp5 = data_ptr[2 ] - data_ptr[5 ];
202
+ tmp3 = data_ptr[3 ] + data_ptr[4 ];
203
+ tmp4 = data_ptr[3 ] - data_ptr[4 ];
204
+ tmp10 = tmp0 + tmp3;
205
+ tmp13 = tmp0 - tmp3;
206
+ tmp11 = tmp1 + tmp2;
207
+ tmp12 = tmp1 - tmp2;
208
+ data_ptr[0 ] = tmp10 + tmp11;
209
+ data_ptr[4 ] = tmp10 - tmp11;
210
+ z1 = (tmp12 + tmp13) * 0.541196100 ;
211
+ data_ptr[2 ] = z1 + tmp13 * 0.765366865 ;
212
+ data_ptr[6 ] = z1 + tmp12 * - 1.847759065 ;
213
+ z1 = tmp4 + tmp7;
214
+ z2 = tmp5 + tmp6;
215
+ z3 = tmp4 + tmp6;
216
+ z4 = tmp5 + tmp7;
217
+ z5 = (z3 + z4) * 1.175875602 ;
218
+ tmp4 *= 0.298631336 ;
219
+ tmp5 *= 2.053119869 ;
220
+ tmp6 *= 3.072711026 ;
221
+ tmp7 *= 1.501321110 ;
222
+ z1 *= -0.899976223 ;
223
+ z2 *= -2.562915447 ;
224
+ z3 *= -1.961570560 ;
225
+ z4 *= -0.390180644 ;
226
+ z3 += z5;
227
+ z4 += z5;
228
+ data_ptr[7 ] = tmp4 + z1 + z3;
229
+ data_ptr[5 ] = tmp5 + z2 + z4;
230
+ data_ptr[3 ] = tmp6 + z2 + z3;
231
+ data_ptr[1 ] = tmp7 + z1 + z4;
232
+ data_ptr += 8 ;
233
+ }
234
+
235
+ data_ptr = data;
236
+
237
+ for (int c=0 ; c < 8 ; c++) {
238
+ tmp0 = data_ptr[8 *0 ] + data_ptr[8 *7 ];
239
+ tmp7 = data_ptr[8 *0 ] - data_ptr[8 *7 ];
240
+ tmp1 = data_ptr[8 *1 ] + data_ptr[8 *6 ];
241
+ tmp6 = data_ptr[8 *1 ] - data_ptr[8 *6 ];
242
+ tmp2 = data_ptr[8 *2 ] + data_ptr[8 *5 ];
243
+ tmp5 = data_ptr[8 *2 ] - data_ptr[8 *5 ];
244
+ tmp3 = data_ptr[8 *3 ] + data_ptr[8 *4 ];
245
+ tmp4 = data_ptr[8 *3 ] - data_ptr[8 *4 ];
246
+ tmp10 = tmp0 + tmp3;
247
+ tmp13 = tmp0 - tmp3;
248
+ tmp11 = tmp1 + tmp2;
249
+ tmp12 = tmp1 - tmp2;
250
+ data_ptr[8 *0 ] = (tmp10 + tmp11) / 8.0 ;
251
+ data_ptr[8 *4 ] = (tmp10 - tmp11) / 8.0 ;
252
+ z1 = (tmp12 + tmp13) * 0.541196100 ;
253
+ data_ptr[8 *2 ] = (z1 + tmp13 * 0.765366865 ) / 8.0 ;
254
+ data_ptr[8 *6 ] = (z1 + tmp12 * -1.847759065 ) / 8.0 ;
255
+ z1 = tmp4 + tmp7;
256
+ z2 = tmp5 + tmp6;
257
+ z3 = tmp4 + tmp6;
258
+ z4 = tmp5 + tmp7;
259
+ z5 = (z3 + z4) * 1.175875602 ;
260
+ tmp4 *= 0.298631336 ;
261
+ tmp5 *= 2.053119869 ;
262
+ tmp6 *= 3.072711026 ;
263
+ tmp7 *= 1.501321110 ;
264
+ z1 *= -0.899976223 ;
265
+ z2 *= -2.562915447 ;
266
+ z3 *= -1.961570560 ;
267
+ z4 *= -0.390180644 ;
268
+ z3 += z5;
269
+ z4 += z5;
270
+ data_ptr[8 *7 ] = (tmp4 + z1 + z3) / 8.0 ;
271
+ data_ptr[8 *5 ] = (tmp5 + z2 + z4) / 8.0 ;
272
+ data_ptr[8 *3 ] = (tmp6 + z2 + z3) / 8.0 ;
273
+ data_ptr[8 *1 ] = (tmp7 + z1 + z4) / 8.0 ;
274
+ data_ptr++;
275
+ }
276
+ }
277
+
278
+
279
+ void dct_blocks (std::vector<std::vector<double >> &blocks) {
280
+ for (int a = 0 ; a < blocks.size (); a++) {
281
+ dct (&blocks[a][0 ]);
282
+ }
283
+ }
284
+
285
+ #endif
0 commit comments