rustiq_core/routines/
decoding.rs1use rand::seq::SliceRandom;
2use rand::thread_rng;
3
4pub fn syndrome_decoding(parities: &[Vec<bool>], input_target: &Vec<bool>) -> Option<Vec<bool>> {
5 let mut target = input_target.clone();
6 let mut solution = vec![false; parities.len()];
7 let mut hweight = target.iter().filter(|a| **a).count();
8 loop {
9 let mut best_reduction = 0;
10 let mut best_index: i32 = -1;
11 for (index, parity) in parities.iter().enumerate() {
12 let new_hweight = parity
13 .iter()
14 .zip(target.iter())
15 .map(|(a, b)| a ^ b)
16 .filter(|a| *a)
17 .count();
18 if (hweight as i32 - new_hweight as i32) > best_reduction {
19 best_reduction = hweight as i32 - new_hweight as i32;
20 best_index = index as i32;
21 }
22 }
23 if best_index == -1 {
24 break;
25 }
26 for (a, b) in target.iter_mut().zip(parities[best_index as usize].iter()) {
27 *a ^= b;
28 }
29 solution[best_index as usize] ^= true;
30 hweight = target.iter().filter(|a| **a).count();
31 }
32 let mut true_target = vec![false; target.len()];
33 for (i, b) in solution.iter().enumerate() {
34 if *b {
35 for (x, y) in parities[i].iter().zip(true_target.iter_mut()) {
36 *y ^= x;
37 }
38 }
39 }
40 if true_target != *input_target {
41 return None;
42 }
43 Some(solution)
44}
45
46fn colop(parities: &mut [Vec<bool>], i: usize, j: usize) {
47 for row in parities.iter_mut() {
48 row[j] ^= row[i];
49 }
50}
51
52fn shuffle_parities(
53 parities: &mut Vec<Vec<bool>>,
54 target: &mut [bool],
55 row_ech: bool,
56) -> Vec<usize> {
57 let n = parities.first().unwrap().len();
58 let mut row_permutation: Vec<usize> = (0..parities.len()).collect();
59 row_permutation.shuffle(&mut thread_rng());
60 let mut new_parities = Vec::new();
61 for j in row_permutation.iter() {
62 new_parities.push(parities[*j].clone());
63 }
64 if row_ech {
65 let mut rank = 0;
66 for i in 0..parities.len() {
67 let mut pivot = None;
68 for j in rank..n {
69 if new_parities[i][j] {
70 pivot = Some(j);
71 break;
72 }
73 }
74 if let Some(pivot) = pivot {
75 if pivot != rank {
76 colop(&mut new_parities, pivot, rank);
77 target[rank] ^= target[pivot];
78 }
79 for j in 0..n {
80 if new_parities[i][j] && j != rank {
81 colop(&mut new_parities, rank, j);
82 target[j] ^= target[rank];
83 }
84 }
85 rank += 1;
86 if rank == n {
87 break;
88 }
89 }
90 }
91 }
92 *parities = new_parities;
93
94 row_permutation
95}
96
97fn fix_permutation(solution: &[bool], permutation: &[usize]) -> Vec<bool> {
98 let mut new_solution = vec![false; solution.len()];
99 for (i, j) in permutation.iter().enumerate() {
100 new_solution[*j] = solution[i];
101 }
102 new_solution
103}
104
105pub fn information_set_decoding(
106 input_parities: &[Vec<bool>],
107 input_target: &Vec<bool>,
108 ntries: usize,
109 row_ech: bool,
110) -> Option<Vec<bool>> {
111 let mut best_solution = None;
112 let mut best_cost = None;
113 for _ in 0..ntries {
114 let mut parities = input_parities.to_owned();
115 let mut target = input_target.clone();
116 let permutation = shuffle_parities(&mut parities, &mut target, row_ech);
117 let solution = syndrome_decoding(&parities, &target);
118 if let Some(solution) = solution {
119 let solution = fix_permutation(&solution, &permutation);
120 let cost = solution.iter().filter(|a| **a).count();
121 if let Some(best_cost) = best_cost {
122 if best_cost < cost {
123 continue;
124 }
125 }
126 best_cost = Some(cost);
127 best_solution = Some(solution);
128 }
129 }
130 if let Some(solution) = best_solution {
131 let mut true_target = vec![false; input_target.len()];
132 for (i, b) in solution.iter().enumerate() {
133 if *b {
134 for (x, y) in input_parities[i].iter().zip(true_target.iter_mut()) {
135 *y ^= x;
136 }
137 }
138 }
139 assert_eq!(true_target, *input_target);
140 return Some(solution);
141 }
142 None
143}
144
145#[cfg(test)]
146mod decoding_tests {
147 use super::*;
148 #[test]
149 fn test_raw_decoding() {
150 let parities = vec![
151 vec![true, false, false],
152 vec![false, true, false],
153 vec![false, false, true],
154 vec![true, false, true],
155 ];
156 let target = vec![true, true, true];
157 let solution = syndrome_decoding(&parities, &target);
158 println!("{:?}", solution);
159 assert_eq!(solution, Some(vec![false, true, false, true]));
160 }
161 #[test]
162 fn test_isd() {
163 let parities = vec![
164 vec![true, false, false],
165 vec![false, true, false],
166 vec![false, false, true],
167 vec![true, false, true],
168 ];
169 let target = vec![true, true, true];
170 let solution = information_set_decoding(&parities, &target, 100, true);
171 println!("{:?}", solution);
172 }
173}