Botan 3.6.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

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 355 of file zfec.cpp.

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

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 442 of file zfec.cpp.

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

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 399 of file zfec.cpp.

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

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 414 of file zfec.cpp.

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

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 528 of file zfec.cpp.

528 {
529#if defined(BOTAN_HAS_ZFEC_VPERM)
530 if(CPUID::has_vperm()) {
531 return "vperm";
532 }
533#endif
534
535#if defined(BOTAN_HAS_ZFEC_SSE2)
536 if(CPUID::has_sse2()) {
537 return "sse2";
538 }
539#endif
540
541 return "base";
542}
static bool has_vperm()
Definition cpuid.h:335

References Botan::CPUID::has_vperm().

◆ 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: