Botan 3.11.1
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 succeptible 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

Definition at line 32 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 349 of file zfec.cpp.

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

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
Parameters
sharesmap of share id to share contents
share_sizesize in bytes of each share
output_cbthe output callback

Definition at line 436 of file zfec.cpp.

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

Definition at line 393 of file zfec.cpp.

393 {
394 if(size % m_K != 0) {
395 throw Invalid_Argument("ZFEC::encode: input must be multiple of K uint8_ts");
396 }
397
398 const size_t share_size = size / m_K;
399
400 std::vector<const uint8_t*> shares;
401 for(size_t i = 0; i != m_K; ++i) {
402 shares.push_back(input + i * share_size);
403 }
404
405 this->encode_shares(shares, share_size, output_cb);
406}
void encode_shares(const std::vector< const uint8_t * > &shares, size_t share_size, const output_cb_t &output_cb) const
Definition zfec.cpp:408

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
Parameters
sharesexactly K shares of data to FEC
share_sizethe length in bytes of each share
output_cbthe output callback

Definition at line 408 of file zfec.cpp.

410 {
411 if(shares.size() != m_K) {
412 throw Invalid_Argument("ZFEC::encode_shares must provide K shares");
413 }
414
415 // The initial shares are just the original input shares
416 for(size_t i = 0; i != m_K; ++i) {
417 output_cb(i, shares[i], share_size);
418 }
419
420 std::vector<uint8_t> fec_buf(share_size);
421
422 for(size_t i = m_K; i != m_N; ++i) {
423 clear_mem(fec_buf.data(), fec_buf.size());
424
425 for(size_t j = 0; j != m_K; ++j) {
426 addmul(fec_buf.data(), shares[j], m_enc_matrix[i * m_K + j], share_size);
427 }
428
429 output_cb(i, fec_buf.data(), fec_buf.size());
430 }
431}
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118

References Botan::clear_mem().

Referenced by encode().

◆ generated_shares()

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

Definition at line 43 of file zfec.h.

43{ return m_N; }

◆ provider()

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

Definition at line 522 of file zfec.cpp.

522 {
523#if defined(BOTAN_HAS_ZFEC_VPERM)
524 if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
525 return *feat;
526 }
527#endif
528
529 return "base";
530}
static std::optional< std::string > check(CPUID::Feature feat)
Definition cpuid.h:67

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

◆ recovery_threshold()

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

Definition at line 41 of file zfec.h.

41{ return m_K; }

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