/src/cryptsetup/lib/verity/rs_decode_char.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: LGPL-2.1-or-later |
2 | | /* |
3 | | * Reed-Solomon decoder, based on libfec |
4 | | * |
5 | | * Copyright (C) 2002, Phil Karn, KA9Q |
6 | | * libcryptsetup modifications |
7 | | * Copyright (C) 2017-2025 Red Hat, Inc. All rights reserved. |
8 | | */ |
9 | | |
10 | | #include <string.h> |
11 | | #include <stdlib.h> |
12 | | |
13 | | #include "rs.h" |
14 | | |
15 | 0 | #define MAX_NR_BUF 256 |
16 | | |
17 | | int decode_rs_char(struct rs* rs, data_t* data) |
18 | 0 | { |
19 | 0 | int deg_lambda, el, deg_omega, syn_error, count; |
20 | 0 | int i, j, r, k; |
21 | 0 | data_t q, tmp, num1, num2, den, discr_r; |
22 | 0 | data_t lambda[MAX_NR_BUF], s[MAX_NR_BUF]; /* Err+Eras Locator poly and syndrome poly */ |
23 | 0 | data_t b[MAX_NR_BUF], t[MAX_NR_BUF], omega[MAX_NR_BUF]; |
24 | 0 | data_t root[MAX_NR_BUF], reg[MAX_NR_BUF], loc[MAX_NR_BUF]; |
25 | |
|
26 | 0 | if (rs->nroots >= MAX_NR_BUF) |
27 | 0 | return -1; |
28 | | |
29 | 0 | memset(s, 0, rs->nroots * sizeof(data_t)); |
30 | 0 | memset(b, 0, (rs->nroots + 1) * sizeof(data_t)); |
31 | | |
32 | | /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ |
33 | 0 | for (i = 0; i < rs->nroots; i++) |
34 | 0 | s[i] = data[0]; |
35 | |
|
36 | 0 | for (j = 1; j < rs->nn - rs->pad; j++) { |
37 | 0 | for (i = 0; i < rs->nroots; i++) { |
38 | 0 | if (s[i] == 0) { |
39 | 0 | s[i] = data[j]; |
40 | 0 | } else { |
41 | 0 | s[i] = data[j] ^ rs->alpha_to[modnn(rs, rs->index_of[s[i]] + (rs->fcr + i) * rs->prim)]; |
42 | 0 | } |
43 | 0 | } |
44 | 0 | } |
45 | | |
46 | | /* Convert syndromes to index form, checking for nonzero condition */ |
47 | 0 | syn_error = 0; |
48 | 0 | for (i = 0; i < rs->nroots; i++) { |
49 | 0 | syn_error |= s[i]; |
50 | 0 | s[i] = rs->index_of[s[i]]; |
51 | 0 | } |
52 | | |
53 | | /* |
54 | | * if syndrome is zero, data[] is a codeword and there are no |
55 | | * errors to correct. So return data[] unmodified |
56 | | */ |
57 | 0 | if (!syn_error) |
58 | 0 | return 0; |
59 | | |
60 | 0 | memset(&lambda[1], 0, rs->nroots * sizeof(lambda[0])); |
61 | 0 | lambda[0] = 1; |
62 | |
|
63 | 0 | for (i = 0; i < rs->nroots + 1; i++) |
64 | 0 | b[i] = rs->index_of[lambda[i]]; |
65 | | |
66 | | /* |
67 | | * Begin Berlekamp-Massey algorithm to determine error+erasure |
68 | | * locator polynomial |
69 | | */ |
70 | 0 | r = 0; |
71 | 0 | el = 0; |
72 | 0 | while (++r <= rs->nroots) { /* r is the step number */ |
73 | | /* Compute discrepancy at the r-th step in poly-form */ |
74 | 0 | discr_r = 0; |
75 | 0 | for (i = 0; i < r; i++) { |
76 | 0 | if ((lambda[i] != 0) && (s[r - i - 1] != A0)) { |
77 | 0 | discr_r ^= rs->alpha_to[modnn(rs, rs->index_of[lambda[i]] + s[r - i - 1])]; |
78 | 0 | } |
79 | 0 | } |
80 | 0 | discr_r = rs->index_of[discr_r]; /* Index form */ |
81 | 0 | if (discr_r == A0) { |
82 | | /* 2 lines below: B(x) <-- x*B(x) */ |
83 | 0 | memmove(&b[1], b, rs->nroots * sizeof(b[0])); |
84 | 0 | b[0] = A0; |
85 | 0 | } else { |
86 | | /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ |
87 | 0 | t[0] = lambda[0]; |
88 | 0 | for (i = 0; i < rs->nroots; i++) { |
89 | 0 | if (b[i] != A0) |
90 | 0 | t[i + 1] = lambda[i + 1] ^ rs->alpha_to[modnn(rs, discr_r + b[i])]; |
91 | 0 | else |
92 | 0 | t[i + 1] = lambda[i + 1]; |
93 | 0 | } |
94 | 0 | if (2 * el <= r - 1) { |
95 | 0 | el = r - el; |
96 | | /* |
97 | | * 2 lines below: B(x) <-- inv(discr_r) * |
98 | | * lambda(x) |
99 | | */ |
100 | 0 | for (i = 0; i <= rs->nroots; i++) |
101 | 0 | b[i] = (lambda[i] == 0) ? A0 : modnn(rs, rs->index_of[lambda[i]] - discr_r + rs->nn); |
102 | 0 | } else { |
103 | | /* 2 lines below: B(x) <-- x*B(x) */ |
104 | 0 | memmove(&b[1], b, rs->nroots * sizeof(b[0])); |
105 | 0 | b[0] = A0; |
106 | 0 | } |
107 | 0 | memcpy(lambda, t, (rs->nroots + 1) * sizeof(t[0])); |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | /* Convert lambda to index form and compute deg(lambda(x)) */ |
112 | 0 | deg_lambda = 0; |
113 | 0 | for (i = 0; i < rs->nroots + 1; i++) { |
114 | 0 | lambda[i] = rs->index_of[lambda[i]]; |
115 | 0 | if (lambda[i] != A0) |
116 | 0 | deg_lambda = i; |
117 | 0 | } |
118 | | /* Find roots of the error+erasure locator polynomial by Chien search */ |
119 | 0 | memcpy(®[1], &lambda[1], rs->nroots * sizeof(reg[0])); |
120 | 0 | count = 0; /* Number of roots of lambda(x) */ |
121 | 0 | for (i = 1, k = rs->iprim - 1; i <= rs->nn; i++, k = modnn(rs, k + rs->iprim)) { |
122 | 0 | q = 1; /* lambda[0] is always 0 */ |
123 | 0 | for (j = deg_lambda; j > 0; j--) { |
124 | 0 | if (reg[j] != A0) { |
125 | 0 | reg[j] = modnn(rs, reg[j] + j); |
126 | 0 | q ^= rs->alpha_to[reg[j]]; |
127 | 0 | } |
128 | 0 | } |
129 | 0 | if (q != 0) |
130 | 0 | continue; /* Not a root */ |
131 | | |
132 | | /* store root (index-form) and error location number */ |
133 | 0 | root[count] = i; |
134 | 0 | loc[count] = k; |
135 | | /* If we've already found max possible roots, abort the search to save time */ |
136 | 0 | if (++count == deg_lambda) |
137 | 0 | break; |
138 | 0 | } |
139 | | |
140 | | /* |
141 | | * deg(lambda) unequal to number of roots => uncorrectable |
142 | | * error detected |
143 | | */ |
144 | 0 | if (deg_lambda != count) |
145 | 0 | return -1; |
146 | | |
147 | | /* |
148 | | * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo |
149 | | * x**rs->nroots). in index form. Also find deg(omega). |
150 | | */ |
151 | 0 | deg_omega = deg_lambda - 1; |
152 | 0 | for (i = 0; i <= deg_omega; i++) { |
153 | 0 | tmp = 0; |
154 | 0 | for (j = i; j >= 0; j--) { |
155 | 0 | if ((s[i - j] != A0) && (lambda[j] != A0)) |
156 | 0 | tmp ^= rs->alpha_to[modnn(rs, s[i - j] + lambda[j])]; |
157 | 0 | } |
158 | 0 | omega[i] = rs->index_of[tmp]; |
159 | 0 | } |
160 | | |
161 | | /* |
162 | | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = |
163 | | * inv(X(l))**(rs->fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form |
164 | | */ |
165 | 0 | for (j = count - 1; j >= 0; j--) { |
166 | 0 | num1 = 0; |
167 | 0 | for (i = deg_omega; i >= 0; i--) { |
168 | 0 | if (omega[i] != A0) |
169 | 0 | num1 ^= rs->alpha_to[modnn(rs, omega[i] + i * root[j])]; |
170 | 0 | } |
171 | 0 | num2 = rs->alpha_to[modnn(rs, root[j] * (rs->fcr - 1) + rs->nn)]; |
172 | 0 | den = 0; |
173 | | |
174 | | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ |
175 | 0 | for (i = RS_MIN(deg_lambda, rs->nroots - 1) & ~1; i >= 0; i -= 2) { |
176 | 0 | if (lambda[i + 1] != A0) |
177 | 0 | den ^= rs->alpha_to[modnn(rs, lambda[i + 1] + i * root[j])]; |
178 | 0 | } |
179 | | |
180 | | /* Apply error to data */ |
181 | 0 | if (num1 != 0 && loc[j] >= rs->pad) { |
182 | 0 | data[loc[j] - rs->pad] ^= rs->alpha_to[modnn(rs, rs->index_of[num1] + |
183 | 0 | rs->index_of[num2] + rs->nn - rs->index_of[den])]; |
184 | 0 | } |
185 | 0 | } |
186 | |
|
187 | 0 | return count; |
188 | 0 | } |