Botan 3.13.0
Crypto and TLS for C&
Botan::ZFEC Class Referencefinal

#include <zfec.h>

Public Types

typedef std::function< void(size_t, const uint8_t[], size_t)> output_cb_t

Public Member Functions

void decode_shares (const std::map< size_t, const uint8_t * > &shares, size_t share_size, const output_cb_t &output_cb) const
void encode (const uint8_t input[], size_t size, const output_cb_t &output_cb) const
void encode_shares (const std::vector< const uint8_t * > &shares, size_t share_size, const output_cb_t &output_cb) const
size_t generated_shares () const
std::string provider () const
size_t recovery_threshold () const
 ZFEC (size_t K, size_t N)

Detailed Description

A forward error correction code compatible with the zfec library (https://github.com/tahoe-lafs/zfec)

This algorithm is not constant time and is likely susceptible to side channels. Do not use this class to encode information that should be kept secret. (If nothing else, because the first K shares are simply the original input!)

Definition at line 30 of file zfec.h.

Member Typedef Documentation

◆ output_cb_t

typedef std::function<void(size_t, const uint8_t[], size_t)> Botan::ZFEC::output_cb_t

Callback invoked with each produced share

Receives the share index, a pointer to the share contents, and the length of the share in bytes.

Definition at line 38 of file zfec.h.

Constructor & Destructor Documentation

◆ ZFEC()

Botan::ZFEC::ZFEC ( size_t K,
size_t N )

FEC constructor

Parameters
Kthe number of shares needed for recovery
Nthe number of shares generated

Definition at line 359 of file zfec.cpp.

359 : m_K(K), m_N(N), m_enc_matrix(N * K) {
360 if(m_K == 0 || m_N == 0 || m_K >= 256 || m_N >= 256 || m_K > N) {
361 throw Invalid_Argument("ZFEC: violated 1 <= K <= N < 256");
362 }
363
364 std::vector<uint8_t> temp_matrix(m_N * m_K);
365
366 /*
367 * quick code to build systematic matrix: invert the top
368 * K*K Vandermonde matrix, multiply right the bottom n-K rows
369 * by the inverse, and construct the identity matrix at the top.
370 */
371 create_inverted_vdm(temp_matrix.data(), m_K);
372
373 for(size_t i = m_K * m_K; i != temp_matrix.size(); ++i) {
374 temp_matrix[i] = GF_EXP[((i / m_K) * (i % m_K)) % 255];
375 }
376
377 /*
378 * the upper part of the encoding matrix is I
379 */
380 for(size_t i = 0; i != m_K; ++i) {
381 m_enc_matrix[i * (m_K + 1)] = 1;
382 }
383
384 /*
385 * computes C = AB where A is n*K, B is K*m, C is n*m
386 */
387 for(size_t row = m_K; row != m_N; ++row) {
388 for(size_t col = 0; col != m_K; ++col) {
389 uint8_t acc = 0;
390 for(size_t i = 0; i != m_K; i++) {
391 const uint8_t row_v = temp_matrix[row * m_K + i];
392 const uint8_t row_c = temp_matrix[col + m_K * i];
393 acc ^= GF_MUL_TABLE(row_v)[row_c];
394 }
395 m_enc_matrix[row * m_K + col] = acc;
396 }
397 }
398}

Member Function Documentation

◆ decode_shares()

void Botan::ZFEC::decode_shares ( const std::map< size_t, const uint8_t * > & shares,
size_t share_size,
const output_cb_t & output_cb ) const

Recover the original data from K shares

Parameters
sharesmap of share id to share contents
share_sizesize in bytes of each share
output_cbthe output callback

Definition at line 441 of file zfec.cpp.

443 {
444 /*
445 Todo:
446 If shares.size() < K:
447 signal decoding error for missing shares < K
448 emit existing shares < K
449 (ie, partial recovery if possible)
450 Assert share_size % K == 0
451 */
452
453 if(shares.size() < m_K) {
454 throw Decoding_Error("ZFEC: could not decode, less than K surviving shares");
455 }
456
457 std::vector<uint8_t> decoding_matrix(m_K * m_K);
458 std::vector<size_t> indexes(m_K);
459 std::vector<const uint8_t*> sharesv(m_K);
460
461 auto shares_b_iter = shares.begin();
462 auto shares_e_iter = shares.rbegin();
463
464 bool missing_primary_share = false;
465
466 for(size_t i = 0; i != m_K; ++i) {
467 size_t share_id = 0;
468 const uint8_t* share_data = nullptr;
469
470 if(shares_b_iter->first == i) {
471 share_id = shares_b_iter->first;
472 share_data = shares_b_iter->second;
473 ++shares_b_iter;
474 } else {
475 // if share i not found, use the unused one closest to n
476 share_id = shares_e_iter->first;
477 share_data = shares_e_iter->second;
478 ++shares_e_iter;
479 missing_primary_share = true;
480 }
481
482 if(share_id >= m_N) {
483 throw Decoding_Error("ZFEC: invalid share id detected during decode");
484 }
485
486 /*
487 This is a systematic code (encoding matrix includes K*K identity
488 matrix), so shares less than K are copies of the input data,
489 can output_cb directly. Also we know the encoding matrix in those rows
490 contains I, so we can set the single bit directly without copying
491 the entire row
492 */
493 if(share_id < m_K) {
494 decoding_matrix[i * (m_K + 1)] = 1;
495 output_cb(share_id, share_data, share_size);
496 } else {
497 // will decode after inverting matrix
498 std::memcpy(&decoding_matrix[i * m_K], &m_enc_matrix[share_id * m_K], m_K);
499 }
500
501 sharesv[i] = share_data;
502 indexes[i] = share_id;
503 }
504
505 // If we had the original data shares then no need to perform
506 // a matrix inversion, return immediately.
507 if(!missing_primary_share) {
508 for(const size_t index : indexes) {
509 BOTAN_ASSERT_NOMSG(index < m_K);
510 }
511 return;
512 }
513
514 invert_matrix(decoding_matrix.data(), m_K);
515
516 for(size_t i = 0; i != indexes.size(); ++i) {
517 if(indexes[i] >= m_K) {
518 std::vector<uint8_t> buf(share_size);
519 linear_combination(buf.data(), sharesv.data(), &decoding_matrix[i * m_K], m_K, share_size);
520 output_cb(i, buf.data(), share_size);
521 }
522 }
523}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75

References BOTAN_ASSERT_NOMSG.

Referenced by botan_zfec_decode().

◆ encode()

void Botan::ZFEC::encode ( const uint8_t input[],
size_t size,
const output_cb_t & output_cb ) const

Encode the input into N shares

Parameters
inputthe data to FEC
sizethe length in bytes of input
output_cbthe output callback

Definition at line 403 of file zfec.cpp.

403 {
404 if(size % m_K != 0) {
405 throw Invalid_Argument("ZFEC::encode: input must be multiple of K uint8_ts");
406 }
407
408 const size_t share_size = size / m_K;
409
410 std::vector<const uint8_t*> shares;
411 for(size_t i = 0; i != m_K; ++i) {
412 shares.push_back(input + i * share_size);
413 }
414
415 this->encode_shares(shares, share_size, output_cb);
416}
void encode_shares(const std::vector< const uint8_t * > &shares, size_t share_size, const output_cb_t &output_cb) const
Definition zfec.cpp:418

References encode_shares().

Referenced by botan_zfec_encode().

◆ encode_shares()

void Botan::ZFEC::encode_shares ( const std::vector< const uint8_t * > & shares,
size_t share_size,
const output_cb_t & output_cb ) const

Encode K existing shares into N shares

Parameters
sharesexactly K shares of data to FEC
share_sizethe length in bytes of each share
output_cbthe output callback

Definition at line 418 of file zfec.cpp.

420 {
421 if(shares.size() != m_K) {
422 throw Invalid_Argument("ZFEC::encode_shares must provide K shares");
423 }
424
425 // The initial shares are just the original input shares
426 for(size_t i = 0; i != m_K; ++i) {
427 output_cb(i, shares[i], share_size);
428 }
429
430 std::vector<uint8_t> fec_buf(share_size);
431
432 for(size_t i = m_K; i != m_N; ++i) {
433 linear_combination(fec_buf.data(), shares.data(), &m_enc_matrix[i * m_K], m_K, share_size);
434 output_cb(i, fec_buf.data(), fec_buf.size());
435 }
436}

Referenced by encode().

◆ generated_shares()

size_t Botan::ZFEC::generated_shares ( ) const
inline

Return how many shares are generated

Returns
the value of N

Definition at line 57 of file zfec.h.

57{ return m_N; }

◆ provider()

std::string Botan::ZFEC::provider ( ) const

Return the name of the provider implementing this object

Returns
the provider name

Definition at line 525 of file zfec.cpp.

525 {
526#if defined(BOTAN_HAS_ZFEC_GFNI)
528 return *feat;
529 }
530#endif
531
532#if defined(BOTAN_HAS_ZFEC_VPERM)
533 if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
534 return *feat;
535 }
536#endif
537
538 return "base";
539}
static std::optional< std::string > check(CPUID::Feature feat)
Definition cpuid.h:67

References Botan::CPUFeature::AVX512, Botan::CPUID::check(), Botan::CPUFeature::GFNI, and Botan::CPUFeature::SIMD_4X32.

◆ recovery_threshold()

size_t Botan::ZFEC::recovery_threshold ( ) const
inline

Return how many shares are needed for recovery

Returns
the value of K

Definition at line 51 of file zfec.h.

51{ return m_K; }

The documentation for this class was generated from the following files: