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 combinations = generate_combinations(n - 1, k - 1);
77
78 for (col, combo) in combinations.into_iter().enumerate() {
79 s0[(0, col)] = 1;
81
82 for &participant in &combo {
84 s0[(participant + 1, col)] = 1;
85 }
86 }
87
88 let mut s1 = DMatrix::zeros(n, m);
90 for row in 0..n {
91 for col in 0..m {
92 s1[(row, col)] = 1 - s0[(row, col)];
93 }
94 }
95
96 Ok((s0, s1))
97}
98
99pub fn generate_xor_matrices(n: usize) -> Result<XorMatrices> {
101 let m = 2_usize.pow((n - 1) as u32); let mut white_matrix = DMatrix::zeros(n, m);
104 let mut black_matrix = DMatrix::zeros(n, m);
105
106 for col in 0..m {
108 let first_bit = rand::rng().random_range(0..2);
110 white_matrix[(0, col)] = first_bit;
111 black_matrix[(0, col)] = first_bit;
112
113 let mut xor_sum = first_bit;
114
115 for row in 1..n {
117 let bit = (col >> (row - 1)) & 1;
118 white_matrix[(row, col)] = bit as u8;
119 black_matrix[(row, col)] = bit as u8;
120 xor_sum ^= bit as u8;
121 }
122
123 if n > 1 {
125 if xor_sum == 1 {
127 white_matrix[(n - 1, col)] = 1 - white_matrix[(n - 1, col)];
128 }
129
130 if xor_sum == 0 {
132 black_matrix[(n - 1, col)] = 1 - black_matrix[(n - 1, col)];
133 }
134 }
135 }
136
137 Ok(XorMatrices {
138 white_pixel: white_matrix,
139 black_pixel: black_matrix,
140 })
141}
142
143pub fn generate_color_mixing_matrices() -> ColorMixingMatrices {
145 let mut basis_matrices = Vec::new();
147 let mut complement_matrices = Vec::new();
148
149 (0..8).for_each(|_| {
151 let mut matrix = DMatrix::zeros(3, 8);
152 let mut complement = DMatrix::zeros(3, 8);
153
154 for col in 0..8 {
155 for row in 0..3 {
156 let bit = (col >> row) & 1;
158 matrix[(row, col)] = bit as u8;
159 complement[(row, col)] = 1 - (bit as u8);
160 }
161 }
162
163 basis_matrices.push(matrix);
164 complement_matrices.push(complement);
165 });
166
167 ColorMixingMatrices {
168 basis_matrices,
169 complement_matrices,
170 }
171}
172
173pub fn generate_dispatching_matrices(n: usize, i: usize) -> Result<DispatchingMatrices> {
175 if i < 2 || i > n {
176 return Err(VCError::InvalidConfiguration(format!(
177 "i must be between 2 and {}, got {}",
178 n, i
179 )));
180 }
181
182 let elem = generate_elementary_matrices(n);
183 let total_rows = i + n;
184
185 let c2_prime = generate_c2_prime(i, n);
187 let c3_prime = DMatrix::from_element(i, n, 1);
188
189 let mut m0 = DMatrix::zeros(total_rows, n);
191 for row in 0..i {
192 for col in 0..n {
193 m0[(row, col)] = c2_prime[(row, col)];
194 }
195 }
196 for row in 0..n {
197 for col in 0..n {
198 m0[(i + row, col)] = elem.c0[(row, col)];
199 }
200 }
201
202 let mut m1 = DMatrix::zeros(total_rows, n);
204 for row in 0..i {
205 for col in 0..n {
206 m1[(row, col)] = c3_prime[(row, col)];
207 }
208 }
209 for row in 0..n {
210 for col in 0..n {
211 m1[(i + row, col)] = elem.c0[(row, col)];
212 }
213 }
214
215 let mut m2 = DMatrix::zeros(total_rows, n);
217 for row in 0..i {
218 for col in 0..n {
219 m2[(row, col)] = c2_prime[(row, col)];
220 }
221 }
222 for row in 0..n {
223 for col in 0..n {
224 m2[(i + row, col)] = elem.c1[(row, col)];
225 }
226 }
227
228 let mut m3 = DMatrix::zeros(total_rows, n);
230 for row in 0..i {
231 for col in 0..n {
232 m3[(row, col)] = c3_prime[(row, col)];
233 }
234 }
235 for row in 0..n {
236 for col in 0..n {
237 m3[(i + row, col)] = elem.c1[(row, col)];
238 }
239 }
240
241 Ok(DispatchingMatrices { m0, m1, m2, m3 })
242}
243
244fn generate_c2_prime(i: usize, n: usize) -> ShareMatrix {
246 let mut matrix = DMatrix::zeros(i, n);
247 let group_size = n / i;
248 let remainder = n % i;
249
250 let mut col = 0;
251 for row in 0..i {
252 let current_group_size = if row < remainder {
253 group_size + 1
254 } else {
255 group_size
256 };
257
258 for _ in 0..current_group_size {
259 if col < n {
260 matrix[(row, col)] = 1;
261 col += 1;
262 }
263 }
264 }
265
266 matrix
267}
268
269pub fn generate_basic_matrices(k: usize, n: usize, block_size: usize) -> Result<Vec<ShareMatrix>> {
271 if k > n {
272 return Err(VCError::InvalidConfiguration(
273 "k cannot be greater than n".to_string(),
274 ));
275 }
276
277 if block_size == 1 && k <= n {
279 let (s0, s1) = generate_proper_sharing_matrices(k, n)?;
280 return Ok(vec![s0, s1]);
281 }
282
283 let mut matrices = Vec::new();
284 let matrix_size = block_size * block_size;
285
286 let white_matrix = generate_white_pixel_matrix(k, n, matrix_size);
288 matrices.push(white_matrix);
289
290 let black_matrix = generate_black_pixel_matrix(n, matrix_size);
292 matrices.push(black_matrix);
293
294 Ok(matrices)
295}
296
297fn generate_white_pixel_matrix(k: usize, n: usize, size: usize) -> ShareMatrix {
299 let mut matrix = DMatrix::zeros(n, size);
300 let mut rng = rand::rng();
301
302 for col in 0..size {
304 let mut indices: Vec<usize> = (0..n).collect();
306 indices.sort_by_key(|_| rng.random::<u32>());
307
308 let k_minus_1 = k.saturating_sub(1);
309 for &row_idx in indices.iter().take(k_minus_1) {
310 matrix[(row_idx, col)] = 1;
311 }
312 }
313
314 matrix
315}
316
317fn generate_black_pixel_matrix(n: usize, size: usize) -> ShareMatrix {
319 DMatrix::from_element(n, size, 1)
321}
322
323pub fn select_dispatching_row(
325 matrices: &DispatchingMatrices,
326 secret_pixel: bool,
327 cover_pixel: bool,
328) -> Vec<u8> {
329 let matrix = match (secret_pixel, cover_pixel) {
330 (false, false) => &matrices.m0,
331 (false, true) => &matrices.m1,
332 (true, false) => &matrices.m2,
333 (true, true) => &matrices.m3,
334 };
335
336 let mut rng = rand::rng();
337 let row_index = rng.random_range(0..matrix.nrows());
338
339 matrix.row(row_index).iter().cloned().collect()
340}
341
342fn binomial_coefficient(n: usize, k: usize) -> usize {
344 if k > n {
345 return 0;
346 }
347 if k == 0 || k == n {
348 return 1;
349 }
350
351 let k = if k > n - k { n - k } else { k };
352 let mut result = 1;
353
354 for i in 0..k {
355 result = result * (n - i) / (i + 1);
356 }
357
358 result
359}
360
361fn generate_combinations(n: usize, k: usize) -> Vec<Vec<usize>> {
363 let mut combinations = Vec::new();
364 let mut current = Vec::new();
365 generate_combinations_recursive(0, n, k, &mut current, &mut combinations);
366 combinations
367}
368
369fn generate_combinations_recursive(
370 start: usize,
371 n: usize,
372 k: usize,
373 current: &mut Vec<usize>,
374 combinations: &mut Vec<Vec<usize>>,
375) {
376 if current.len() == k {
377 combinations.push(current.clone());
378 return;
379 }
380
381 for i in start..n {
382 current.push(i);
383 generate_combinations_recursive(i + 1, n, k, current, combinations);
384 current.pop();
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 #[test]
393 fn test_elementary_matrices() {
394 let elem = generate_elementary_matrices(4);
395
396 let first_row_sum: u8 = elem.c0.row(0).iter().sum();
398 assert_eq!(first_row_sum, 4);
399
400 let mut other_rows_sum = 0u8;
402 for row in 1..4 {
403 other_rows_sum += elem.c0.row(row).iter().sum::<u8>();
404 }
405 assert_eq!(other_rows_sum, 0);
406
407 assert_eq!(elem.c1, DMatrix::identity(4, 4));
409
410 let c3_sum: u8 = elem.c3.iter().sum();
412 assert_eq!(c3_sum, 16);
413 }
414
415 #[test]
416 fn test_dispatching_matrices() {
417 let matrices = generate_dispatching_matrices(4, 2).unwrap();
418
419 assert_eq!(matrices.m0.nrows(), 6); assert_eq!(matrices.m0.ncols(), 4);
422 }
423
424 #[test]
425 fn test_proper_sharing_matrices() {
426 let (s0, s1) = generate_proper_sharing_matrices(2, 3).unwrap();
427
428 assert_eq!(s0.nrows(), 3);
430 assert_eq!(s1.nrows(), 3);
431
432 for row in 0..s0.nrows() {
434 for col in 0..s0.ncols() {
435 assert_eq!(s0[(row, col)] + s1[(row, col)], 1);
436 }
437 }
438 }
439
440 #[test]
441 fn test_xor_matrices() {
442 let xor_matrices = generate_xor_matrices(3).unwrap();
443
444 assert_eq!(xor_matrices.white_pixel.nrows(), 3);
446 assert_eq!(xor_matrices.white_pixel.ncols(), 4);
447 }
448
449 #[test]
450 fn test_binomial_coefficient() {
451 assert_eq!(binomial_coefficient(5, 2), 10);
452 assert_eq!(binomial_coefficient(4, 0), 1);
453 assert_eq!(binomial_coefficient(4, 4), 1);
454 assert_eq!(binomial_coefficient(6, 3), 20);
455 }
456}