/src/cryptsetup/lib/verity/rs_encode_char.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: LGPL-2.1-or-later |
2 | | /* |
3 | | * Reed-Solomon encoder, 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 | | /* Initialize a Reed-Solomon codec |
16 | | * symsize = symbol size, bits |
17 | | * gfpoly = Field generator polynomial coefficients |
18 | | * fcr = first root of RS code generator polynomial, index form |
19 | | * prim = primitive element to generate polynomial roots |
20 | | * nroots = RS code generator polynomial degree (number of roots) |
21 | | * pad = padding bytes at front of shortened block |
22 | | */ |
23 | | struct rs *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) |
24 | 0 | { |
25 | 0 | struct rs *rs; |
26 | 0 | int i, j, sr, root, iprim; |
27 | | |
28 | | /* Check parameter ranges */ |
29 | 0 | if (symsize < 0 || symsize > 8 * (int)sizeof(data_t)) |
30 | 0 | return NULL; |
31 | 0 | if (fcr < 0 || fcr >= (1<<symsize)) |
32 | 0 | return NULL; |
33 | 0 | if (prim <= 0 || prim >= (1<<symsize)) |
34 | 0 | return NULL; |
35 | 0 | if (nroots < 0 || nroots >= (1<<symsize)) |
36 | 0 | return NULL; /* Can't have more roots than symbol values! */ |
37 | | |
38 | 0 | if (pad < 0 || pad >= ((1<<symsize) - 1 - nroots)) |
39 | 0 | return NULL; /* Too much padding */ |
40 | | |
41 | 0 | rs = calloc(1, sizeof(struct rs)); |
42 | 0 | if (rs == NULL) |
43 | 0 | return NULL; |
44 | | |
45 | 0 | rs->mm = symsize; |
46 | 0 | rs->nn = (1<<symsize) - 1; |
47 | 0 | rs->pad = pad; |
48 | |
|
49 | 0 | rs->alpha_to = malloc(sizeof(data_t) * (rs->nn + 1)); |
50 | 0 | if (rs->alpha_to == NULL) { |
51 | 0 | free(rs); |
52 | 0 | return NULL; |
53 | 0 | } |
54 | 0 | rs->index_of = malloc(sizeof(data_t) * (rs->nn + 1)); |
55 | 0 | if (rs->index_of == NULL) { |
56 | 0 | free(rs->alpha_to); |
57 | 0 | free(rs); |
58 | 0 | return NULL; |
59 | 0 | } |
60 | 0 | memset(rs->index_of, 0, sizeof(data_t) * (rs->nn + 1)); |
61 | | |
62 | | /* Generate Galois field lookup tables */ |
63 | 0 | rs->index_of[0] = A0; /* log(zero) = -inf */ |
64 | 0 | rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ |
65 | 0 | sr = 1; |
66 | 0 | for (i = 0; i < rs->nn; i++) { |
67 | 0 | rs->index_of[sr] = i; |
68 | 0 | rs->alpha_to[i] = sr; |
69 | 0 | sr <<= 1; |
70 | 0 | if(sr & (1<<symsize)) |
71 | 0 | sr ^= gfpoly; |
72 | 0 | sr &= rs->nn; |
73 | 0 | } |
74 | 0 | if (sr != 1) { |
75 | | /* field generator polynomial is not primitive! */ |
76 | 0 | free(rs->alpha_to); |
77 | 0 | free(rs->index_of); |
78 | 0 | free(rs); |
79 | 0 | return NULL; |
80 | 0 | } |
81 | | |
82 | | /* Form RS code generator polynomial from its roots */ |
83 | 0 | rs->genpoly = malloc(sizeof(data_t) * (nroots + 1)); |
84 | 0 | if (rs->genpoly == NULL) { |
85 | 0 | free(rs->alpha_to); |
86 | 0 | free(rs->index_of); |
87 | 0 | free(rs); |
88 | 0 | return NULL; |
89 | 0 | } |
90 | | |
91 | 0 | rs->fcr = fcr; |
92 | 0 | rs->prim = prim; |
93 | 0 | rs->nroots = nroots; |
94 | | |
95 | | /* Find prim-th root of 1, used in decoding */ |
96 | 0 | for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn) |
97 | 0 | ; |
98 | 0 | rs->iprim = iprim / prim; |
99 | |
|
100 | 0 | rs->genpoly[0] = 1; |
101 | 0 | for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) { |
102 | 0 | rs->genpoly[i + 1] = 1; |
103 | | |
104 | | /* Multiply rs->genpoly[] by @**(root + x) */ |
105 | 0 | for (j = i; j > 0; j--){ |
106 | 0 | if (rs->genpoly[j] != 0) |
107 | 0 | rs->genpoly[j] = rs->genpoly[j - 1] ^ rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; |
108 | 0 | else |
109 | 0 | rs->genpoly[j] = rs->genpoly[j - 1]; |
110 | 0 | } |
111 | | /* rs->genpoly[0] can never be zero */ |
112 | 0 | rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; |
113 | 0 | } |
114 | | /* convert rs->genpoly[] to index form for quicker encoding */ |
115 | 0 | for (i = 0; i <= nroots; i++) |
116 | 0 | rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; |
117 | |
|
118 | 0 | return rs; |
119 | 0 | } |
120 | | |
121 | | void free_rs_char(struct rs *rs) |
122 | 0 | { |
123 | 0 | if (!rs) |
124 | 0 | return; |
125 | | |
126 | 0 | free(rs->alpha_to); |
127 | 0 | free(rs->index_of); |
128 | 0 | free(rs->genpoly); |
129 | 0 | free(rs); |
130 | 0 | } |
131 | | |
132 | | void encode_rs_char(struct rs *rs, data_t *data, data_t *parity) |
133 | 0 | { |
134 | 0 | int i, j; |
135 | 0 | data_t feedback; |
136 | |
|
137 | 0 | memset(parity, 0, rs->nroots * sizeof(data_t)); |
138 | |
|
139 | 0 | for (i = 0; i < rs->nn - rs->nroots - rs->pad; i++) { |
140 | 0 | feedback = rs->index_of[data[i] ^ parity[0]]; |
141 | 0 | if (feedback != A0) { |
142 | | /* feedback term is non-zero */ |
143 | | #ifdef UNNORMALIZED |
144 | | /* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must |
145 | | * always be for the polynomials constructed by init_rs() */ |
146 | | feedback = modnn(rs, rs->nn - rs->genpoly[rs->nroots] + feedback); |
147 | | #endif |
148 | 0 | for (j = 1; j < rs->nroots; j++) |
149 | 0 | parity[j] ^= rs->alpha_to[modnn(rs, feedback + rs->genpoly[rs->nroots - j])]; |
150 | 0 | } |
151 | | |
152 | | /* Shift */ |
153 | 0 | memmove(&parity[0], &parity[1], sizeof(data_t) * (rs->nroots - 1)); |
154 | |
|
155 | 0 | if (feedback != A0) |
156 | 0 | parity[rs->nroots - 1] = rs->alpha_to[modnn(rs, feedback + rs->genpoly[0])]; |
157 | 0 | else |
158 | 0 | parity[rs->nroots - 1] = 0; |
159 | 0 | } |
160 | 0 | } |