60 const uint16_t N =
K + M;
61 uint8_t *V = calloc((
size_t)N *
K,
sizeof(uint8_t));
64 for(uint16_t i = 0; i < N; i++)
67 for(uint16_t j = 0; j <
K; j++)
69 V[(size_t)i *
K + j] = val;
87 uint8_t *work = malloc((
size_t)
K *
K);
89 memcpy(work, mat, (
size_t)
K *
K);
92 memset(inv, 0, (
size_t)
K *
K);
93 for(uint16_t i = 0; i <
K; i++)
94 inv[(
size_t)i *
K + i] = 1;
97 for(uint16_t col = 0; col <
K; col++)
100 uint16_t pivot = col;
101 while(pivot <
K && work[(
size_t)pivot *
K + col] == 0)
103 if(pivot ==
K) { free(work);
return -1; }
108 for(uint16_t j = 0; j <
K; j++)
110 uint8_t tmp = work[(size_t)col *
K + j];
111 work[(size_t)col *
K + j] = work[(
size_t)pivot *
K + j];
112 work[(size_t)pivot *
K + j] = tmp;
114 tmp = inv[(size_t)col *
K + j];
115 inv[(size_t)col *
K + j] = inv[(
size_t)pivot *
K + j];
116 inv[(size_t)pivot *
K + j] = tmp;
121 uint8_t diag = work[(size_t)col *
K + col];
125 for(uint16_t j = 0; j <
K; j++)
127 work[(size_t)col *
K + j] =
gf256_mul(work[(
size_t)col *
K + j], inv_diag);
128 inv[(size_t)col *
K + j] =
gf256_mul(inv[(
size_t)col *
K + j], inv_diag);
133 for(uint16_t row = 0; row <
K; row++)
135 if(row == col)
continue;
136 uint8_t factor = work[(size_t)row *
K + col];
137 if(factor == 0)
continue;
138 for(uint16_t j = 0; j <
K; j++)
140 work[(size_t)row *
K + j] ^=
gf256_mul(factor, work[(
size_t)col *
K + j]);
141 inv[(size_t)row *
K + j] ^=
gf256_mul(factor, inv[(
size_t)col *
K + j]);
152 if(
K == 0 || M == 0 || (uint32_t)
K + M > 255)
return NULL;
155 if(!ctx)
return NULL;
159 const uint16_t N =
K + M;
163 if(!V) { free(ctx);
return NULL; }
166 uint8_t *top_inv = malloc((
size_t)
K *
K);
167 if(!top_inv) { free(V); free(ctx);
return NULL; }
178 ctx->
coding = calloc((
size_t)N *
K,
sizeof(uint8_t));
179 if(!ctx->
coding) { free(top_inv); free(V); free(ctx);
return NULL; }
181 for(uint16_t i = 0; i < N; i++)
183 for(uint16_t j = 0; j <
K; j++)
186 for(uint16_t m = 0; m <
K; m++)
187 val ^=
gf256_mul(V[(
size_t)i *
K + m], top_inv[(
size_t)m *
K + j]);
188 ctx->
coding[(size_t)i *
K + j] = val;
210 return ctx->
gen[(size_t)m * ctx->
K + k];
220 const uint16_t
K = ctx->
K;
221 const uint16_t M = ctx->
M;
222 const uint16_t N =
K + M;
225 uint16_t num_erased = 0;
226 for(uint16_t i = 0; i < N; i++)
227 if(!present[i]) num_erased++;
229 if(num_erased == 0)
return 0;
230 if(num_erased > M)
return -1;
237 uint16_t *surviving = malloc((
size_t)
K *
sizeof(uint16_t));
238 if(!surviving)
return -2;
241 for(uint16_t i = 0; i < N && s <
K; i++)
243 if(present[i]) surviving[s++] = i;
246 if(s <
K) { free(surviving);
return -1; }
249 uint8_t *submat = malloc((
size_t)
K *
K);
250 if(!submat) { free(surviving);
return -2; }
252 for(uint16_t i = 0; i <
K; i++)
253 memcpy(submat + (
size_t)i *
K, ctx->
coding + (
size_t)surviving[i] *
K,
K);
256 uint8_t *submat_inv = malloc((
size_t)
K *
K);
257 if(!submat_inv) { free(submat); free(surviving);
return -2; }
277 for(uint16_t e = 0; e < N; e++)
279 if(present[e])
continue;
282 memset(shards[e], 0, shard_size);
284 for(uint16_t k = 0; k <
K; k++)
288 for(uint16_t j = 0; j <
K; j++)
289 coeff ^=
gf256_mul(ctx->
coding[(
size_t)e *
K + j], submat_inv[(
size_t)j *
K + k]);
uint8_t gf256_inv(uint8_t a)
Compute multiplicative inverse in GF(2^8).
void gf256_mul_region(uint8_t *dst, const uint8_t *src, uint8_t coeff, size_t len)
Multiply-accumulate a region: dst[i] ^= GF_mul(src[i], coeff) for all i.
uint8_t gf256_mul(uint8_t a, uint8_t b)
Multiply two elements in GF(2^8) with polynomial 0x11D.
static int invert_matrix(const uint8_t *mat, uint8_t *inv, uint16_t K)
Invert a K x K matrix in-place using Gaussian elimination over GF(2^8).
void rs_free(rs_context *ctx)
Free a Reed-Solomon codec context.
rs_context * rs_create(uint16_t K, uint16_t M)
Create a Reed-Solomon codec for RS(K, M) over GF(2^8).
void rs_encode_incremental(uint8_t coeff, const uint8_t *data, uint8_t *parity, size_t shard_size)
Incrementally accumulate one data shard's contribution to one parity shard.
static uint8_t * build_vandermonde(uint16_t K, uint16_t M)
Build a Vandermonde matrix (K+M) x K in GF(2^8).
uint8_t rs_get_coefficient(const rs_context *ctx, uint16_t m, uint16_t k)
Get the generator matrix coefficient for parity shard m, data shard k.
int rs_decode(const rs_context *ctx, uint8_t **shards, const uint8_t *present, size_t shard_size)
Decode (reconstruct) erased shards.
static const uint32_t K[64]
uint16_t K
Number of data shards.
uint8_t * gen
Generator matrix: M rows x K columns (row-major).
uint16_t M
Number of parity shards.
uint8_t * coding
Full coding matrix: (K+M) rows x K columns.