1use crate::error::{Result, VCError};
4use nalgebra::DMatrix;
5use rand::Rng;
6
7pub type ShareMatrix = DMatrix<u8>;
9
10#[derive(Debug, Clone)]
12pub struct ElementaryMatrices {
13 pub c0: ShareMatrix,
14 pub c1: ShareMatrix,
15 pub c2: ShareMatrix,
16 pub c3: ShareMatrix,
17}
18
19#[derive(Debug, Clone)]
21pub struct DispatchingMatrices {
22 pub m0: ShareMatrix, pub m1: ShareMatrix, pub m2: ShareMatrix, pub m3: ShareMatrix, }
27
28#[derive(Debug, Clone)]
30pub struct XorMatrices {
31 pub white_pixel: ShareMatrix,
32 pub black_pixel: ShareMatrix,
33}
34
35#[derive(Debug, Clone)]
37pub struct ColorMixingMatrices {
38 pub basis_matrices: Vec<ShareMatrix>,
39 pub complement_matrices: Vec<ShareMatrix>,
40}
41
42pub fn generate_elementary_matrices(n: usize) -> ElementaryMatrices {
44 let mut c0 = DMatrix::zeros(n, n);
46 for j in 0..n {
47 c0[(0, j)] = 1;
48 }
49
50 let c1 = DMatrix::identity(n, n);
52
53 let c2 = c1.clone();
55
56 let c3 = DMatrix::from_element(n, n, 1);
58
59 ElementaryMatrices { c0, c1, c2, c3 }
60}
61
62pub fn generate_proper_sharing_matrices(k: usize, n: usize) -> Result<(ShareMatrix, ShareMatrix)> {
64 if k > n {
65 return Err(VCError::InvalidConfiguration(
66 "k cannot be greater than n".to_string(),
67 ));
68 }
69
70 let m = binomial_coefficient(n - 1, k - 1);
72
73 let mut s0 = DMatrix::zeros(n, m);
75 let mut col = 0;
76
77 let combinations = generate_combinations(n - 1, k - 1);
79
80 for combo in combinations {
81 s0[(0, col)] = 1;
83
84 for &participant in &combo {
86 s0[(participant + 1, col)] = 1;
87 }
88 col += 1;
89 }
90
91 let mut s1 = DMatrix::zeros(n, m);
93 for row in 0..n {
94 for col in 0..m {
95 s1[(row, col)] = 1 - s0[(row, col)];
96 }
97 }
98
99 Ok((s0, s1))
100}
101
102pub fn generate_xor_matrices(n: usize) -> Result<XorMatrices> {
104 let m = 2_usize.pow((n - 1) as u32); let mut white_matrix = DMatrix::zeros(n, m);
107 let mut black_matrix = DMatrix::zeros(n, m);
108
109 for col in 0..m {
111 let first_bit = rand::thread_rng().gen_range(0..2);
113 white_matrix[(0, col)] = first_bit;
114 black_matrix[(0, col)] = first_bit;
115
116 let mut xor_sum = first_bit;
117
118 for row in 1..n {
120 let bit = (col >> (row - 1)) & 1;
121 white_matrix[(row, col)] = bit as u8;
122 black_matrix[(row, col)] = bit as u8;
123 xor_sum ^= bit as u8;
124 }
125
126 if n > 1 {
128 if xor_sum == 1 {
130 white_matrix[(n - 1, col)] = 1 - white_matrix[(n - 1, col)];
131 }
132
133 if xor_sum == 0 {
135 black_matrix[(n - 1, col)] = 1 - black_matrix[(n - 1, col)];
136 }
137 }
138 }
139
140 Ok(XorMatrices {
141 white_pixel: white_matrix,
142 black_pixel: black_matrix,
143 })
144}
145
146pub fn generate_color_mixing_matrices() -> ColorMixingMatrices {
148 let mut basis_matrices = Vec::new();
150 let mut complement_matrices = Vec::new();
151
152 for i in 0..8 {
154 let mut matrix = DMatrix::zeros(3, 8);
155 let mut complement = DMatrix::zeros(3, 8);
156
157 for col in 0..8 {
158 for row in 0..3 {
159 let bit = (col >> row) & 1;
161 matrix[(row, col)] = bit as u8;
162 complement[(row, col)] = 1 - (bit as u8);
163 }
164 }
165
166 basis_matrices.push(matrix);
167 complement_matrices.push(complement);
168 }
169
170 ColorMixingMatrices {
171 basis_matrices,
172 complement_matrices,
173 }
174}
175
176pub fn generate_dispatching_matrices(n: usize, i: usize) -> Result<DispatchingMatrices> {
178 if i < 2 || i > n {
179 return Err(VCError::InvalidConfiguration(format!(
180 "i must be between 2 and {}, got {}",
181 n, i
182 )));
183 }
184
185 let elem = generate_elementary_matrices(n);
186 let total_rows = i + n;
187
188 let c2_prime = generate_c2_prime(i, n);
190 let c3_prime = DMatrix::from_element(i, n, 1);
191
192 let mut m0 = DMatrix::zeros(total_rows, n);
194 for row in 0..i {
195 for col in 0..n {
196 m0[(row, col)] = c2_prime[(row, col)];
197 }
198 }
199 for row in 0..n {
200 for col in 0..n {
201 m0[(i + row, col)] = elem.c0[(row, col)];
202 }
203 }
204
205 let mut m1 = DMatrix::zeros(total_rows, n);
207 for row in 0..i {
208 for col in 0..n {
209 m1[(row, col)] = c3_prime[(row, col)];
210 }
211 }
212 for row in 0..n {
213 for col in 0..n {
214 m1[(i + row, col)] = elem.c0[(row, col)];
215 }
216 }
217
218 let mut m2 = DMatrix::zeros(total_rows, n);
220 for row in 0..i {
221 for col in 0..n {
222 m2[(row, col)] = c2_prime[(row, col)];
223 }
224 }
225 for row in 0..n {
226 for col in 0..n {
227 m2[(i + row, col)] = elem.c1[(row, col)];
228 }
229 }
230
231 let mut m3 = DMatrix::zeros(total_rows, n);
233 for row in 0..i {
234 for col in 0..n {
235 m3[(row, col)] = c3_prime[(row, col)];
236 }
237 }
238 for row in 0..n {
239 for col in 0..n {
240 m3[(i + row, col)] = elem.c1[(row, col)];
241 }
242 }
243
244 Ok(DispatchingMatrices { m0, m1, m2, m3 })
245}
246
247fn generate_c2_prime(i: usize, n: usize) -> ShareMatrix {
249 let mut matrix = DMatrix::zeros(i, n);
250 let group_size = n / i;
251 let remainder = n % i;
252
253 let mut col = 0;
254 for row in 0..i {
255 let current_group_size = if row < remainder {
256 group_size + 1
257 } else {
258 group_size
259 };
260
261 for _ in 0..current_group_size {
262 if col < n {
263 matrix[(row, col)] = 1;
264 col += 1;
265 }
266 }
267 }
268
269 matrix
270}
271
272pub fn generate_basic_matrices(k: usize, n: usize, block_size: usize) -> Result<Vec<ShareMatrix>> {
274 if k > n {
275 return Err(VCError::InvalidConfiguration(
276 "k cannot be greater than n".to_string(),
277 ));
278 }
279
280 if block_size == 1 && k <= n {
282 let (s0, s1) = generate_proper_sharing_matrices(k, n)?;
283 return Ok(vec![s0, s1]);
284 }
285
286 let mut matrices = Vec::new();
287 let matrix_size = block_size * block_size;
288
289 let white_matrix = generate_white_pixel_matrix(k, n, matrix_size);
291 matrices.push(white_matrix);
292
293 let black_matrix = generate_black_pixel_matrix(k, n, matrix_size);
295 matrices.push(black_matrix);
296
297 Ok(matrices)
298}
299
300fn generate_white_pixel_matrix(k: usize, n: usize, size: usize) -> ShareMatrix {
302 let mut matrix = DMatrix::zeros(n, size);
303 let mut rng = rand::thread_rng();
304
305 for col in 0..size {
307 let mut indices: Vec<usize> = (0..n).collect();
309 indices.sort_by_key(|_| rng.gen::<u32>());
310
311 let k_minus_1 = k.saturating_sub(1);
312 for i in 0..k_minus_1 {
313 let row_idx = indices[i];
314 matrix[(row_idx, col)] = 1;
315 }
316 }
317
318 matrix
319}
320
321fn generate_black_pixel_matrix(k: usize, n: usize, size: usize) -> ShareMatrix {
323 let mut matrix = DMatrix::zeros(n, size);
324
325 for row in 0..n {
327 for col in 0..size {
328 matrix[(row, col)] = 1;
329 }
330 }
331
332 matrix
333}
334
335pub fn select_dispatching_row(
337 matrices: &DispatchingMatrices,
338 secret_pixel: bool,
339 cover_pixel: bool,
340) -> Vec<u8> {
341 let matrix = match (secret_pixel, cover_pixel) {
342 (false, false) => &matrices.m0,
343 (false, true) => &matrices.m1,
344 (true, false) => &matrices.m2,
345 (true, true) => &matrices.m3,
346 };
347
348 let mut rng = rand::thread_rng();
349 let row_index = rng.gen_range(0..matrix.nrows());
350
351 matrix.row(row_index).iter().cloned().collect()
352}
353
354fn binomial_coefficient(n: usize, k: usize) -> usize {
356 if k > n {
357 return 0;
358 }
359 if k == 0 || k == n {
360 return 1;
361 }
362
363 let k = if k > n - k { n - k } else { k };
364 let mut result = 1;
365
366 for i in 0..k {
367 result = result * (n - i) / (i + 1);
368 }
369
370 result
371}
372
373fn generate_combinations(n: usize, k: usize) -> Vec<Vec<usize>> {
375 let mut combinations = Vec::new();
376 let mut current = Vec::new();
377 generate_combinations_recursive(0, n, k, &mut current, &mut combinations);
378 combinations
379}
380
381fn generate_combinations_recursive(
382 start: usize,
383 n: usize,
384 k: usize,
385 current: &mut Vec<usize>,
386 combinations: &mut Vec<Vec<usize>>,
387) {
388 if current.len() == k {
389 combinations.push(current.clone());
390 return;
391 }
392
393 for i in start..n {
394 current.push(i);
395 generate_combinations_recursive(i + 1, n, k, current, combinations);
396 current.pop();
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403
404 #[test]
405 fn test_elementary_matrices() {
406 let elem = generate_elementary_matrices(4);
407
408 let first_row_sum: u8 = elem.c0.row(0).iter().sum();
410 assert_eq!(first_row_sum, 4);
411
412 let mut other_rows_sum = 0u8;
414 for row in 1..4 {
415 other_rows_sum += elem.c0.row(row).iter().sum::<u8>();
416 }
417 assert_eq!(other_rows_sum, 0);
418
419 assert_eq!(elem.c1, DMatrix::identity(4, 4));
421
422 let c3_sum: u8 = elem.c3.iter().sum();
424 assert_eq!(c3_sum, 16);
425 }
426
427 #[test]
428 fn test_dispatching_matrices() {
429 let matrices = generate_dispatching_matrices(4, 2).unwrap();
430
431 assert_eq!(matrices.m0.nrows(), 6); assert_eq!(matrices.m0.ncols(), 4);
434 }
435
436 #[test]
437 fn test_proper_sharing_matrices() {
438 let (s0, s1) = generate_proper_sharing_matrices(2, 3).unwrap();
439
440 assert_eq!(s0.nrows(), 3);
442 assert_eq!(s1.nrows(), 3);
443
444 for row in 0..s0.nrows() {
446 for col in 0..s0.ncols() {
447 assert_eq!(s0[(row, col)] + s1[(row, col)], 1);
448 }
449 }
450 }
451
452 #[test]
453 fn test_xor_matrices() {
454 let xor_matrices = generate_xor_matrices(3).unwrap();
455
456 assert_eq!(xor_matrices.white_pixel.nrows(), 3);
458 assert_eq!(xor_matrices.white_pixel.ncols(), 4);
459 }
460
461 #[test]
462 fn test_binomial_coefficient() {
463 assert_eq!(binomial_coefficient(5, 2), 10);
464 assert_eq!(binomial_coefficient(4, 0), 1);
465 assert_eq!(binomial_coefficient(4, 4), 1);
466 assert_eq!(binomial_coefficient(6, 3), 20);
467 }
468}