├── .gitignore ├── CMakeLists.txt ├── Makefile ├── cpuid.cpp ├── fec_hash.py ├── fecpp.cpp ├── fecpp.h ├── fecpp_python.cpp ├── fecpp_sse2.cpp ├── fecpp_ssse3.cpp ├── format.txt ├── license.txt ├── news.txt ├── readme.txt ├── test ├── benchmark.cpp ├── gen_test_vec.cpp ├── test_fec.cpp ├── test_recovery.cpp └── zfec.cpp └── test_decode.py /.gitignore: -------------------------------------------------------------------------------- 1 | benchmark 2 | zfec 3 | gen_test_vec 4 | test_fec 5 | test_recovery 6 | tests.txt 7 | *.o 8 | *.a 9 | *.so 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if ( NOT CMAKE_BUILD_TYPE ) 2 | set( CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type: release, debug, relwithdebinfo" FORCE ) 3 | endif() 4 | 5 | cmake_minimum_required( VERSION 3.2 ) 6 | project( fecpp ) 7 | 8 | option( HAS_SSE2 "Compile for SSE2" ON ) 9 | option( HAS_SSSE3 "Compile for SSSE3" ON ) 10 | 11 | set( FECPP_SOURCES fecpp.cpp cpuid.cpp ) 12 | if ( HAS_SSE2 ) 13 | add_definitions( -msse2 ) 14 | list( APPEND FECPP_SOURCES fecpp_sse2.cpp ) 15 | endif() 16 | if ( HAS_SSSE3 ) 17 | add_definitions( -mssse3 ) 18 | list( APPEND FECPP_SOURCES fecpp_ssse3.cpp ) 19 | endif() 20 | add_definitions( -Wall -Wextra -std=c++11 ) 21 | 22 | add_library( fecpp-object OBJECT ${FECPP_SOURCES} ) 23 | set_property( TARGET fecpp-object PROPERTY POSITION_INDEPENDENT_CODE ON ) 24 | add_library( fecpp-static STATIC $ ) 25 | add_library( fecpp SHARED $ ) 26 | set_target_properties( fecpp PROPERTIES PUBLIC_HEADER fecpp.h ) 27 | 28 | include( FindPkgConfig ) 29 | pkg_check_modules( PYTHON2 python2 ) 30 | if ( PYTHON2_FOUND ) 31 | find_package( Boost COMPONENTS python ) 32 | if ( Boost_FOUND ) 33 | add_library( pyfecpp SHARED fecpp_python.cpp ) 34 | target_include_directories( pyfecpp PUBLIC ${PYTHON2_INCLUDE_DIRS} ) 35 | target_link_libraries( pyfecpp fecpp-static ${Boost_LIBRARIES} ${PYTHON2_LIBRARIES} ) 36 | set_target_properties( pyfecpp PROPERTIES PREFIX "") 37 | else() 38 | message( WARN "boost_python library was not found. fecpp python library will not be built" ) 39 | endif() 40 | else() 41 | message( WARN "python2 configuration for pkg_config was not found. fecpp python library will not be built" ) 42 | endif() 43 | 44 | include_directories( ${CMAKE_SOURCE_DIR} ) 45 | add_executable( gen_test_vec test/gen_test_vec.cpp ) 46 | target_link_libraries( gen_test_vec fecpp-static ) 47 | 48 | add_executable( test_recovery test/test_recovery.cpp ) 49 | target_link_libraries( test_recovery fecpp-static ) 50 | 51 | add_executable( benchmark test/benchmark.cpp ) 52 | target_link_libraries( benchmark fecpp-static ) 53 | 54 | add_executable( zfec test/zfec.cpp ) 55 | target_link_libraries( zfec fecpp-static ) 56 | 57 | install( TARGETS fecpp fecpp-static gen_test_vec test_recovery benchmark zfec pyfecpp 58 | ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin 59 | PUBLIC_HEADER DESTINATION include ) 60 | install( FILES fec_hash.py test_decode.py 61 | PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ 62 | DESTINATION bin ) 63 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CXX=g++ 3 | WARNINGS=-Wall -Wextra 4 | OPTFLAGS=-std=c++11 -O2 -fPIC 5 | DEBUGFLAGS=-g 6 | 7 | CXXFLAGS=$(OPTFLAGS) $(DEBUGFLAGS) $(WARNINGS) 8 | 9 | PROGS = benchmark zfec test_recovery gen_test_vec 10 | 11 | all: fecpp.so pyfecpp.so $(PROGS) 12 | 13 | PYTHON_PKGCONFIG=python2 14 | 15 | OBJ=fecpp.o cpuid.o fecpp_sse2.o fecpp_ssse3.o 16 | 17 | libfecpp.a: $(OBJ) 18 | ar crs $@ $(OBJ) 19 | 20 | fecpp.o: fecpp.cpp fecpp.h 21 | $(CXX) $(CXXFLAGS) -I. -c $< -o $@ 22 | 23 | cpuid.o: cpuid.cpp fecpp.h 24 | $(CXX) $(CXXFLAGS) -I. -c $< -o $@ 25 | 26 | fecpp_sse2.o: fecpp_sse2.cpp fecpp.h 27 | $(CXX) $(CXXFLAGS) -msse2 -I. -c $< -o $@ 28 | 29 | fecpp_ssse3.o: fecpp_ssse3.cpp fecpp.h 30 | $(CXX) $(CXXFLAGS) -mssse3 -I. -c $< -o $@ 31 | 32 | test/%.o: test/%.cpp fecpp.h 33 | $(CXX) $(CXXFLAGS) -I. -c $< -o $@ 34 | 35 | zfec: test/zfec.o libfecpp.a 36 | $(CXX) $(CXXFLAGS) $< -L. -lfecpp -o $@ 37 | 38 | benchmark: test/benchmark.o libfecpp.a 39 | $(CXX) $(CXXFLAGS) $< -L. -lfecpp -o $@ 40 | 41 | test_fec: test/test_fec.o libfecpp.a 42 | $(CXX) $(CXXFLAGS) $< -L. -lfecpp -o $@ 43 | 44 | test_recovery: test/test_recovery.o libfecpp.a 45 | $(CXX) $(CXXFLAGS) $< -L. -lfecpp -o $@ 46 | 47 | gen_test_vec: test/gen_test_vec.o libfecpp.a 48 | $(CXX) $(CXXFLAGS) $< -L. -lfecpp -o $@ 49 | 50 | fecpp.so: $(OBJ) fecpp.h 51 | $(CXX) -shared -fPIC $(CXXFLAGS) $(OBJ) -o fecpp.so 52 | 53 | pyfecpp.so: fecpp_python.cpp fecpp.h fecpp.so 54 | $(CXX) -shared -fPIC $(CXXFLAGS) `pkg-config --cflags $(PYTHON_PKGCONFIG)` fecpp_python.cpp `pkg-config --libs $(PYTHON_PKGCONFIG)` -lboost_python fecpp.so -o pyfecpp.so 55 | 56 | clean: 57 | rm -f fecpp.so *.a *.o test/*.o 58 | rm -f $(PROGS) 59 | -------------------------------------------------------------------------------- /cpuid.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "fecpp.h" 3 | 4 | namespace fecpp { 5 | 6 | bool has_sse2() { return true; } 7 | 8 | bool has_ssse3() { return true; } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /fec_hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import pyfecpp as fec 4 | import md5 5 | 6 | k = 3 7 | n = 10 8 | 9 | code = fec.fec_code(k,n) 10 | 11 | f = open('testinput') 12 | 13 | hash_fns = [md5.new() for i in xrange(0, n)] 14 | 15 | chunk = 4 * 1024 16 | 17 | while True: 18 | block = f.read(chunk * k) 19 | 20 | if len(block) != chunk*k: 21 | break 22 | 23 | code_blocks = code.encode(block) 24 | 25 | for i in xrange(0, len(code_blocks)): 26 | hash_fns[i].update(code_blocks[i]) 27 | 28 | top_hash = md5.new() 29 | 30 | for hash_fn in hash_fns: 31 | print hash_fn.hexdigest() 32 | top_hash.update(hash_fn.digest()) 33 | 34 | print top_hash.hexdigest() 35 | 36 | -------------------------------------------------------------------------------- /fecpp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Forward error correction based on Vandermonde matrices 3 | * 4 | * (C) 1997-1998 Luigi Rizzo (luigi@iet.unipi.it) 5 | * (C) 2009-2010 Jack Lloyd (jack@randombit.net) 6 | * (C) 2011 Billy Brumley (billy.brumley@aalto.fi) 7 | * 8 | * Distributed under the terms given in license.txt (Simplified BSD) 9 | */ 10 | 11 | #include "fecpp.h" 12 | #include 13 | #include 14 | #include 15 | 16 | namespace fecpp { 17 | 18 | namespace { 19 | 20 | /* Tables for arithetic in GF(2^8) using 1+x^2+x^3+x^4+x^8 21 | * 22 | * See Lin & Costello, Appendix A, and Lee & Messerschmitt, p. 453. 23 | * 24 | * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] 25 | * Lookup tables: 26 | * index->polynomial form gf_exp[] contains j= \alpha^i; 27 | * polynomial form -> index form gf_log[ j = \alpha^i ] = i 28 | * \alpha=x is the primitive element of GF(2^m) 29 | * 30 | * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple 31 | * multiplication of two numbers can be resolved without calling mod 32 | */ 33 | const uint8_t GF_EXP[510] = { 34 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 35 | 0xE8, 0xCD, 0x87, 0x13, 0x26, 0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 36 | 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x9D, 37 | 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 38 | 0xEE, 0xC1, 0x9F, 0x23, 0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 39 | 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1, 0x5F, 0xBE, 40 | 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 41 | 0x3C, 0x78, 0xF0, 0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 42 | 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2, 0xD9, 0xAF, 0x43, 43 | 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 44 | 0x67, 0xCE, 0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 45 | 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC, 0x85, 0x17, 0x2E, 0x5C, 46 | 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 47 | 0x54, 0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 48 | 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73, 0xE6, 0xD1, 0xBF, 0x63, 0xC6, 49 | 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF, 50 | 0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 51 | 0xDC, 0xA5, 0x57, 0xAE, 0x41, 0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 52 | 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6, 0x51, 53 | 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 54 | 0xAC, 0x45, 0x8A, 0x09, 0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 55 | 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16, 0x2C, 0x58, 56 | 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 57 | 0x47, 0x8E, 58 | 59 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 60 | 0xE8, 0xCD, 0x87, 0x13, 0x26, 0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 61 | 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x9D, 62 | 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 63 | 0xEE, 0xC1, 0x9F, 0x23, 0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 64 | 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1, 0x5F, 0xBE, 65 | 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 66 | 0x3C, 0x78, 0xF0, 0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 67 | 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2, 0xD9, 0xAF, 0x43, 68 | 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 69 | 0x67, 0xCE, 0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 70 | 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC, 0x85, 0x17, 0x2E, 0x5C, 71 | 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 72 | 0x54, 0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 73 | 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73, 0xE6, 0xD1, 0xBF, 0x63, 0xC6, 74 | 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF, 75 | 0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 76 | 0xDC, 0xA5, 0x57, 0xAE, 0x41, 0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 77 | 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6, 0x51, 78 | 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 79 | 0xAC, 0x45, 0x8A, 0x09, 0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 80 | 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16, 0x2C, 0x58, 81 | 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 82 | 0x47, 0x8E }; 83 | 84 | const uint8_t GF_LOG[256] = { 85 | 0xFF, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1A, 0xC6, 0x03, 0xDF, 0x33, 86 | 0xEE, 0x1B, 0x68, 0xC7, 0x4B, 0x04, 0x64, 0xE0, 0x0E, 0x34, 0x8D, 87 | 0xEF, 0x81, 0x1C, 0xC1, 0x69, 0xF8, 0xC8, 0x08, 0x4C, 0x71, 0x05, 88 | 0x8A, 0x65, 0x2F, 0xE1, 0x24, 0x0F, 0x21, 0x35, 0x93, 0x8E, 0xDA, 89 | 0xF0, 0x12, 0x82, 0x45, 0x1D, 0xB5, 0xC2, 0x7D, 0x6A, 0x27, 0xF9, 90 | 0xB9, 0xC9, 0x9A, 0x09, 0x78, 0x4D, 0xE4, 0x72, 0xA6, 0x06, 0xBF, 91 | 0x8B, 0x62, 0x66, 0xDD, 0x30, 0xFD, 0xE2, 0x98, 0x25, 0xB3, 0x10, 92 | 0x91, 0x22, 0x88, 0x36, 0xD0, 0x94, 0xCE, 0x8F, 0x96, 0xDB, 0xBD, 93 | 0xF1, 0xD2, 0x13, 0x5C, 0x83, 0x38, 0x46, 0x40, 0x1E, 0x42, 0xB6, 94 | 0xA3, 0xC3, 0x48, 0x7E, 0x6E, 0x6B, 0x3A, 0x28, 0x54, 0xFA, 0x85, 95 | 0xBA, 0x3D, 0xCA, 0x5E, 0x9B, 0x9F, 0x0A, 0x15, 0x79, 0x2B, 0x4E, 96 | 0xD4, 0xE5, 0xAC, 0x73, 0xF3, 0xA7, 0x57, 0x07, 0x70, 0xC0, 0xF7, 97 | 0x8C, 0x80, 0x63, 0x0D, 0x67, 0x4A, 0xDE, 0xED, 0x31, 0xC5, 0xFE, 98 | 0x18, 0xE3, 0xA5, 0x99, 0x77, 0x26, 0xB8, 0xB4, 0x7C, 0x11, 0x44, 99 | 0x92, 0xD9, 0x23, 0x20, 0x89, 0x2E, 0x37, 0x3F, 0xD1, 0x5B, 0x95, 100 | 0xBC, 0xCF, 0xCD, 0x90, 0x87, 0x97, 0xB2, 0xDC, 0xFC, 0xBE, 0x61, 101 | 0xF2, 0x56, 0xD3, 0xAB, 0x14, 0x2A, 0x5D, 0x9E, 0x84, 0x3C, 0x39, 102 | 0x53, 0x47, 0x6D, 0x41, 0xA2, 0x1F, 0x2D, 0x43, 0xD8, 0xB7, 0x7B, 103 | 0xA4, 0x76, 0xC4, 0x17, 0x49, 0xEC, 0x7F, 0x0C, 0x6F, 0xF6, 0x6C, 104 | 0xA1, 0x3B, 0x52, 0x29, 0x9D, 0x55, 0xAA, 0xFB, 0x60, 0x86, 0xB1, 105 | 0xBB, 0xCC, 0x3E, 0x5A, 0xCB, 0x59, 0x5F, 0xB0, 0x9C, 0xA9, 0xA0, 106 | 0x51, 0x0B, 0xF5, 0x16, 0xEB, 0x7A, 0x75, 0x2C, 0xD7, 0x4F, 0xAE, 107 | 0xD5, 0xE9, 0xE6, 0xE7, 0xAD, 0xE8, 0x74, 0xD6, 0xF4, 0xEA, 0xA8, 108 | 0x50, 0x58, 0xAF }; 109 | 110 | const uint8_t GF_INVERSE[256] = { 111 | 0x00, 0x01, 0x8E, 0xF4, 0x47, 0xA7, 0x7A, 0xBA, 0xAD, 0x9D, 0xDD, 112 | 0x98, 0x3D, 0xAA, 0x5D, 0x96, 0xD8, 0x72, 0xC0, 0x58, 0xE0, 0x3E, 113 | 0x4C, 0x66, 0x90, 0xDE, 0x55, 0x80, 0xA0, 0x83, 0x4B, 0x2A, 0x6C, 114 | 0xED, 0x39, 0x51, 0x60, 0x56, 0x2C, 0x8A, 0x70, 0xD0, 0x1F, 0x4A, 115 | 0x26, 0x8B, 0x33, 0x6E, 0x48, 0x89, 0x6F, 0x2E, 0xA4, 0xC3, 0x40, 116 | 0x5E, 0x50, 0x22, 0xCF, 0xA9, 0xAB, 0x0C, 0x15, 0xE1, 0x36, 0x5F, 117 | 0xF8, 0xD5, 0x92, 0x4E, 0xA6, 0x04, 0x30, 0x88, 0x2B, 0x1E, 0x16, 118 | 0x67, 0x45, 0x93, 0x38, 0x23, 0x68, 0x8C, 0x81, 0x1A, 0x25, 0x61, 119 | 0x13, 0xC1, 0xCB, 0x63, 0x97, 0x0E, 0x37, 0x41, 0x24, 0x57, 0xCA, 120 | 0x5B, 0xB9, 0xC4, 0x17, 0x4D, 0x52, 0x8D, 0xEF, 0xB3, 0x20, 0xEC, 121 | 0x2F, 0x32, 0x28, 0xD1, 0x11, 0xD9, 0xE9, 0xFB, 0xDA, 0x79, 0xDB, 122 | 0x77, 0x06, 0xBB, 0x84, 0xCD, 0xFE, 0xFC, 0x1B, 0x54, 0xA1, 0x1D, 123 | 0x7C, 0xCC, 0xE4, 0xB0, 0x49, 0x31, 0x27, 0x2D, 0x53, 0x69, 0x02, 124 | 0xF5, 0x18, 0xDF, 0x44, 0x4F, 0x9B, 0xBC, 0x0F, 0x5C, 0x0B, 0xDC, 125 | 0xBD, 0x94, 0xAC, 0x09, 0xC7, 0xA2, 0x1C, 0x82, 0x9F, 0xC6, 0x34, 126 | 0xC2, 0x46, 0x05, 0xCE, 0x3B, 0x0D, 0x3C, 0x9C, 0x08, 0xBE, 0xB7, 127 | 0x87, 0xE5, 0xEE, 0x6B, 0xEB, 0xF2, 0xBF, 0xAF, 0xC5, 0x64, 0x07, 128 | 0x7B, 0x95, 0x9A, 0xAE, 0xB6, 0x12, 0x59, 0xA5, 0x35, 0x65, 0xB8, 129 | 0xA3, 0x9E, 0xD2, 0xF7, 0x62, 0x5A, 0x85, 0x7D, 0xA8, 0x3A, 0x29, 130 | 0x71, 0xC8, 0xF6, 0xF9, 0x43, 0xD7, 0xD6, 0x10, 0x73, 0x76, 0x78, 131 | 0x99, 0x0A, 0x19, 0x91, 0x14, 0x3F, 0xE6, 0xF0, 0x86, 0xB1, 0xE2, 132 | 0xF1, 0xFA, 0x74, 0xF3, 0xB4, 0x6D, 0x21, 0xB2, 0x6A, 0xE3, 0xE7, 133 | 0xB5, 0xEA, 0x03, 0x8F, 0xD3, 0xC9, 0x42, 0xD4, 0xE8, 0x75, 0x7F, 134 | 0xFF, 0x7E, 0xFD }; 135 | 136 | static uint8_t GF_MUL_TABLE[256][256]; 137 | 138 | void init_fec() 139 | { 140 | static bool fec_initialized = false; 141 | 142 | if(!fec_initialized) 143 | { 144 | fec_initialized = true; 145 | 146 | for(size_t i = 0; i != 256; ++i) 147 | for(size_t j = 0; j != 256; ++j) 148 | GF_MUL_TABLE[i][j] = GF_EXP[(GF_LOG[i] + GF_LOG[j]) % 255]; 149 | 150 | for(size_t i = 0; i != 256; ++i) 151 | GF_MUL_TABLE[0][i] = GF_MUL_TABLE[i][0] = 0; 152 | } 153 | } 154 | 155 | /* 156 | * addmul() computes z[] = z[] + x[] * y 157 | */ 158 | void addmul(uint8_t z[], const uint8_t x[], uint8_t y, size_t size) 159 | { 160 | if(y == 0) 161 | return; 162 | 163 | const uint8_t* GF_MUL_Y = GF_MUL_TABLE[y]; 164 | 165 | while(size && (uintptr_t)z % 16) // first align z to 16 bytes 166 | { 167 | z[0] ^= GF_MUL_Y[x[0]]; 168 | ++z; 169 | ++x; 170 | size--; 171 | } 172 | 173 | #if defined(FECPP_IS_X86) 174 | if(size >= 16 && has_ssse3()) 175 | { 176 | const size_t consumed = addmul_ssse3(z, x, y, size); 177 | z += consumed; 178 | x += consumed; 179 | y += consumed; 180 | size -= consumed; 181 | } 182 | 183 | if(size >= 64 && has_sse2()) 184 | { 185 | const size_t consumed = addmul_sse2(z, x, y, size); 186 | z += consumed; 187 | x += consumed; 188 | y += consumed; 189 | size -= consumed; 190 | } 191 | #endif 192 | 193 | while(size >= 16) 194 | { 195 | z[0] ^= GF_MUL_Y[x[0]]; 196 | z[1] ^= GF_MUL_Y[x[1]]; 197 | z[2] ^= GF_MUL_Y[x[2]]; 198 | z[3] ^= GF_MUL_Y[x[3]]; 199 | z[4] ^= GF_MUL_Y[x[4]]; 200 | z[5] ^= GF_MUL_Y[x[5]]; 201 | z[6] ^= GF_MUL_Y[x[6]]; 202 | z[7] ^= GF_MUL_Y[x[7]]; 203 | z[8] ^= GF_MUL_Y[x[8]]; 204 | z[9] ^= GF_MUL_Y[x[9]]; 205 | z[10] ^= GF_MUL_Y[x[10]]; 206 | z[11] ^= GF_MUL_Y[x[11]]; 207 | z[12] ^= GF_MUL_Y[x[12]]; 208 | z[13] ^= GF_MUL_Y[x[13]]; 209 | z[14] ^= GF_MUL_Y[x[14]]; 210 | z[15] ^= GF_MUL_Y[x[15]]; 211 | 212 | x += 16; 213 | z += 16; 214 | size -= 16; 215 | } 216 | 217 | // Clean up the trailing pieces 218 | for(size_t i = 0; i != size; ++i) 219 | z[i] ^= GF_MUL_Y[x[i]]; 220 | } 221 | 222 | /* 223 | * invert_matrix() takes a K*K matrix and produces its inverse 224 | * (Gauss-Jordan algorithm, adapted from Numerical Recipes in C) 225 | */ 226 | void invert_matrix(uint8_t matrix[], size_t K) 227 | { 228 | class pivot_searcher 229 | { 230 | public: 231 | pivot_searcher(size_t K) : ipiv(K) {} 232 | 233 | std::pair operator()(size_t col, const uint8_t* matrix) 234 | { 235 | const size_t K = ipiv.size(); 236 | 237 | if(ipiv[col] == false && matrix[col*K + col] != 0) 238 | { 239 | ipiv[col] = true; 240 | return std::make_pair(col, col); 241 | } 242 | 243 | for(size_t row = 0; row != K; ++row) 244 | { 245 | if(ipiv[row]) 246 | continue; 247 | 248 | for(size_t i = 0; i != K; ++i) 249 | { 250 | if(ipiv[i] == false && matrix[row*K + i] != 0) 251 | { 252 | ipiv[i] = true; 253 | return std::make_pair(row, i); 254 | } 255 | } 256 | } 257 | 258 | throw std::invalid_argument("pivot not found in invert_matrix"); 259 | } 260 | 261 | private: 262 | // Marks elements already used as pivots 263 | std::vector ipiv; 264 | }; 265 | 266 | pivot_searcher pivot_search(K); 267 | std::vector indxc(K); 268 | std::vector indxr(K); 269 | std::vector id_row(K); 270 | 271 | for(size_t col = 0; col != K; ++col) 272 | { 273 | /* 274 | * Zeroing column 'col', look for a non-zero element. 275 | * First try on the diagonal, if it fails, look elsewhere. 276 | */ 277 | 278 | std::pair icolrow = pivot_search(col, matrix); 279 | 280 | size_t icol = icolrow.first; 281 | size_t irow = icolrow.second; 282 | 283 | /* 284 | * swap rows irow and icol, so afterwards the diagonal 285 | * element will be correct. Rarely done, not worth 286 | * optimizing. 287 | */ 288 | if(irow != icol) 289 | { 290 | for(size_t i = 0; i != K; ++i) 291 | std::swap(matrix[irow*K + i], matrix[icol*K + i]); 292 | } 293 | 294 | indxr[col] = irow; 295 | indxc[col] = icol; 296 | uint8_t* pivot_row = &matrix[icol*K]; 297 | uint8_t c = pivot_row[icol]; 298 | 299 | if(c == 0) 300 | throw std::invalid_argument("singlar matrix"); 301 | 302 | if(c != 1) 303 | { /* otherwhise this is a NOP */ 304 | /* 305 | * this is done often, but optimizing is not so 306 | * fruitful, at least in the obvious ways (unrolling) 307 | */ 308 | c = GF_INVERSE[c]; 309 | pivot_row[icol] = 1; 310 | 311 | const uint8_t* mul_c = GF_MUL_TABLE[c]; 312 | 313 | for(size_t i = 0; i != K; ++i) 314 | pivot_row[i] = mul_c[pivot_row[i]]; 315 | } 316 | 317 | /* 318 | * from all rows, remove multiples of the selected row 319 | * to zero the relevant entry (in fact, the entry is not zero 320 | * because we know it must be zero). 321 | * (Here, if we know that the pivot_row is the identity, 322 | * we can optimize the addmul). 323 | */ 324 | id_row[icol] = 1; 325 | if(memcmp(pivot_row, &id_row[0], K) != 0) 326 | { 327 | uint8_t* p = matrix; 328 | 329 | for(size_t i = 0; i != K; ++i) 330 | { 331 | if(i != icol) 332 | { 333 | c = p[icol]; 334 | p[icol] = 0; 335 | addmul(p, pivot_row, c, K); 336 | } 337 | p += K; 338 | } 339 | } 340 | id_row[icol] = 0; 341 | } /* done all columns */ 342 | 343 | for(size_t i = 0; i != K; ++i) 344 | { 345 | if(indxr[i] != indxc[i]) 346 | { 347 | for(size_t row = 0; row != K; ++row) 348 | std::swap(matrix[row*K + indxr[i]], matrix[row*K + indxc[i]]); 349 | } 350 | } 351 | } 352 | 353 | /* 354 | * Generate and invert a Vandermonde matrix. 355 | * 356 | * Only uses the second column of the matrix, containing the p_i's 357 | * (contents - 0, GF_EXP[0...n]) 358 | * 359 | * Algorithm borrowed from "Numerical recipes in C", section 2.8, but 360 | * largely revised for my purposes. 361 | * 362 | * p = coefficients of the matrix (p_i) 363 | * q = values of the polynomial (known) 364 | */ 365 | void create_inverted_vdm(uint8_t vdm[], size_t K) 366 | { 367 | if(K == 1) /* degenerate case, matrix must be p^0 = 1 */ 368 | { 369 | vdm[0] = 1; 370 | return; 371 | } 372 | 373 | /* 374 | * c holds the coefficient of P(x) = Prod (x - p_i), i=0..K-1 375 | * b holds the coefficient for the matrix inversion 376 | */ 377 | std::vector b(K), c(K); 378 | 379 | /* 380 | * construct coeffs. recursively. We know c[K] = 1 (implicit) 381 | * and start P_0 = x - p_0, then at each stage multiply by 382 | * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1} 383 | * After K steps we are done. 384 | */ 385 | c[K-1] = 0; /* really -p(0), but x = -x in GF(2^m) */ 386 | for(size_t i = 1; i < K; ++i) 387 | { 388 | const uint8_t* mul_p_i = GF_MUL_TABLE[GF_EXP[i]]; 389 | 390 | for(size_t j = K-1 - (i - 1); j < K-1; ++j) 391 | c[j] ^= mul_p_i[c[j+1]]; 392 | c[K-1] ^= GF_EXP[i]; 393 | } 394 | 395 | for(size_t row = 0; row < K; ++row) 396 | { 397 | // synthetic division etc. 398 | const uint8_t* mul_p_row = GF_MUL_TABLE[row == 0 ? 0 : GF_EXP[row]]; 399 | 400 | uint8_t t = 1; 401 | b[K-1] = 1; /* this is in fact c[K] */ 402 | for(int i = K-2; i >= 0; i--) 403 | { 404 | b[i] = c[i+1] ^ mul_p_row[b[i+1]]; 405 | t = b[i] ^ mul_p_row[t]; 406 | } 407 | 408 | const uint8_t* mul_t_inv = GF_MUL_TABLE[GF_INVERSE[t]]; 409 | for(size_t col = 0; col != K; ++col) 410 | vdm[col*K + row] = mul_t_inv[b[col]]; 411 | } 412 | } 413 | 414 | } 415 | 416 | /* 417 | * This section contains the proper FEC encoding/decoding routines. 418 | * The encoding matrix is computed starting with a Vandermonde matrix, 419 | * and then transforming it into a systematic matrix. 420 | */ 421 | 422 | /* 423 | * fec_code constructor 424 | */ 425 | fec_code::fec_code(size_t K_arg, size_t N_arg) : 426 | K(K_arg), N(N_arg), enc_matrix(N * K) 427 | { 428 | init_fec(); 429 | 430 | if(K == 0 || N == 0 || K > 256 || N > 256 || K > N) 431 | throw std::invalid_argument("fec_code: violated 1 <= K <= N <= 256"); 432 | 433 | std::vector temp_matrix(N * K); 434 | 435 | /* 436 | * quick code to build systematic matrix: invert the top 437 | * K*K vandermonde matrix, multiply right the bottom n-K rows 438 | * by the inverse, and construct the identity matrix at the top. 439 | */ 440 | create_inverted_vdm(&temp_matrix[0], K); 441 | 442 | for(size_t i = K*K; i != temp_matrix.size(); ++i) 443 | temp_matrix[i] = GF_EXP[((i / K) * (i % K)) % 255]; 444 | 445 | /* 446 | * the upper part of the encoding matrix is I 447 | */ 448 | for(size_t i = 0; i != K; ++i) 449 | enc_matrix[i*(K+1)] = 1; 450 | 451 | /* 452 | * computes C = AB where A is n*K, B is K*m, C is n*m 453 | */ 454 | for(size_t row = K*K; row != N*K; row += K) 455 | { 456 | for(size_t col = 0; col != K; ++col) 457 | { 458 | const uint8_t* pa = &temp_matrix[row]; 459 | const uint8_t* pb = &temp_matrix[col]; 460 | uint8_t acc = 0; 461 | for(size_t i = 0; i < K; i++, pa++, pb += K) 462 | acc ^= GF_MUL_TABLE[*pa][*pb]; 463 | enc_matrix[row + col] = acc; 464 | } 465 | } 466 | } 467 | 468 | /* 469 | * FEC encoding routine 470 | */ 471 | void fec_code::encode( 472 | const uint8_t input[], size_t size, 473 | std::function output) 474 | const 475 | { 476 | if(size % K != 0) 477 | throw std::invalid_argument("encode: input must be multiple of K bytes"); 478 | 479 | size_t block_size = size / K; 480 | 481 | #if 1 482 | for(size_t i = 0; i != K; ++i) 483 | output(i, N, input + i*block_size, block_size); 484 | 485 | for(size_t i = K; i != N; ++i) 486 | { 487 | std::vector fec_buf(block_size); 488 | 489 | for(size_t j = 0; j != K; ++j) 490 | addmul(&fec_buf[0], input + j*block_size, 491 | enc_matrix[i*K+j], block_size); 492 | 493 | output(i, N, &fec_buf[0], fec_buf.size()); 494 | } 495 | #else 496 | for(size_t i = 0; i != K; ++i) 497 | output(i, N, input + i*block_size, block_size); 498 | 499 | // align?? 500 | std::vector > fec_buf(N - K); 501 | 502 | for(size_t i = 0; i != fec_buf.size(); ++i) 503 | fec_buf[i].resize(block_size); 504 | 505 | size_t stride = block_size; 506 | 507 | while(stride % 2 == 0 && stride > 64*1024) 508 | stride >>= 1; 509 | 510 | for(size_t i = 0; i != size; i += stride) 511 | { 512 | for(size_t j = K; j != N; ++j) 513 | addmul(&fec_buf[j-K][0], input + i, 514 | enc_matrix[j*K+i/block_size], stride); 515 | } 516 | 517 | for(size_t i = 0; i != fec_buf.size(); ++i) 518 | output(i+K, N, &fec_buf[i][0], fec_buf[i].size()); 519 | #endif 520 | } 521 | 522 | /* 523 | * FEC decoding routine 524 | */ 525 | void fec_code::decode( 526 | const std::map& shares, 527 | size_t share_size, 528 | std::function output) const 529 | { 530 | /* 531 | Todo: 532 | If shares.size() < K: 533 | signal decoding error for missing shares < K 534 | emit existing shares < K 535 | (ie, partial recovery if possible) 536 | Assert share_size % K == 0 537 | */ 538 | 539 | if(shares.size() < K) 540 | throw std::logic_error("Could not decode, less than K surviving shares"); 541 | 542 | std::vector m_dec(K * K); 543 | std::vector indexes(K); 544 | std::vector sharesv(K); 545 | 546 | std::map::const_iterator shares_b_iter = 547 | shares.begin(); 548 | std::map::const_reverse_iterator shares_e_iter = 549 | shares.rbegin(); 550 | 551 | for(size_t i = 0; i != K; ++i) 552 | { 553 | size_t share_id = 0; 554 | const uint8_t* share_data = 0; 555 | 556 | if(shares_b_iter->first == i) 557 | { 558 | share_id = shares_b_iter->first; 559 | share_data = shares_b_iter->second; 560 | ++shares_b_iter; 561 | } 562 | else 563 | { 564 | // if share i not found, use the unused one closest to n 565 | share_id = shares_e_iter->first; 566 | share_data = shares_e_iter->second; 567 | ++shares_e_iter; 568 | } 569 | 570 | if(share_id >= N) 571 | throw std::logic_error("Invalid share id detected during decode"); 572 | 573 | /* 574 | This is a systematic code (encoding matrix includes K*K identity 575 | matrix), so shares less than K are copies of the input data, 576 | can output directly. Also we know the encoding matrix in those rows 577 | contains I, so we can set the single bit directly without copying 578 | */ 579 | if(share_id < K) 580 | { 581 | m_dec[i*(K+1)] = 1; 582 | output(share_id, K, share_data, share_size); 583 | } 584 | else // will decode after inverting matrix 585 | std::memcpy(&m_dec[i*K], &(enc_matrix[share_id*K]), K); 586 | 587 | sharesv[i] = share_data; 588 | indexes[i] = share_id; 589 | } 590 | 591 | /* 592 | TODO: if all primary shares were recovered, don't invert the matrix 593 | and return immediately 594 | */ 595 | invert_matrix(&m_dec[0], K); 596 | 597 | for(size_t i = 0; i != indexes.size(); ++i) 598 | { 599 | if(indexes[i] >= K) 600 | { 601 | std::vector buf(share_size); 602 | for(size_t col = 0; col != K; ++col) 603 | addmul(&buf[0], sharesv[col], m_dec[i*K + col], share_size); 604 | output(i, K, &buf[0], share_size); 605 | } 606 | } 607 | } 608 | 609 | } 610 | -------------------------------------------------------------------------------- /fecpp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Forward error correction based on Vandermonde matrices 3 | * 4 | * (C) 1997-1998 Luigi Rizzo (luigi@iet.unipi.it) 5 | * (C) 2009 Jack Lloyd (jack@randombit.net) 6 | * 7 | * Distributed under the terms given in license.txt 8 | */ 9 | 10 | #ifndef FECPP_H_ 11 | #define FECPP_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fecpp { 19 | 20 | using std::uint8_t; 21 | using std::size_t; 22 | 23 | using byte = std::uint8_t; 24 | 25 | #if defined(__i386__) || defined(__x86_64__) 26 | #define FECPP_IS_X86 27 | #endif 28 | 29 | /** 30 | * Forward error correction code 31 | */ 32 | class fec_code 33 | { 34 | public: 35 | /** 36 | * fec_code constructor 37 | * @param K the number of shares needed for recovery 38 | * @param N the number of shares generated 39 | */ 40 | fec_code(size_t K, size_t n); 41 | 42 | size_t get_K() const { return K; } 43 | size_t get_N() const { return N; } 44 | 45 | /** 46 | * @param input the data to FEC 47 | * @param size the length in bytes of input 48 | * @param out the output callback 49 | */ 50 | void encode( 51 | const uint8_t input[], size_t size, 52 | std::function out) 53 | const; 54 | 55 | /** 56 | * @param shares map of share id to share contents 57 | * @param share_size size in bytes of each share 58 | * @param out the output callback 59 | */ 60 | void decode( 61 | const std::map& shares, size_t share_size, 62 | std::function out) 63 | const; 64 | 65 | private: 66 | size_t K, N; 67 | std::vector enc_matrix; 68 | }; 69 | 70 | #if defined(FECPP_IS_X86) 71 | 72 | /** 73 | * CPU runtime detection 74 | */ 75 | bool has_sse2(); 76 | bool has_ssse3(); 77 | 78 | size_t addmul_sse2(uint8_t z[], const uint8_t x[], uint8_t y, size_t size); 79 | size_t addmul_ssse3(uint8_t z[], const uint8_t x[], uint8_t y, size_t size); 80 | 81 | #endif 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /fecpp_python.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fecpp.h" 4 | 5 | using namespace fecpp; 6 | 7 | class save_results 8 | { 9 | public: 10 | save_results(size_t n) : results(n) {} 11 | 12 | void operator()(size_t i, size_t, const byte fec[], size_t fec_len) 13 | { 14 | results[i].append(reinterpret_cast(fec), fec_len); 15 | } 16 | 17 | boost::python::list get_results() const 18 | { 19 | boost::python::list list; 20 | for(size_t i = 0; i != results.size(); ++i) 21 | list.append(boost::python::str(results[i].c_str(), 22 | results[i].length())); 23 | return list; 24 | } 25 | 26 | private: 27 | std::vector results; 28 | }; 29 | 30 | boost::python::list fec_encode(fec_code* code, 31 | const std::string& input) 32 | { 33 | save_results fec_saver(code->get_N()); 34 | 35 | code->encode(reinterpret_cast(input.c_str()), 36 | input.size(), 37 | std::ref(fec_saver)); 38 | 39 | return fec_saver.get_results(); 40 | } 41 | 42 | boost::python::list fec_decode(fec_code* code, 43 | boost::python::dict dict) 44 | { 45 | size_t share_size = 0; 46 | std::map shares; 47 | 48 | std::vector share_data(code->get_N()); 49 | 50 | for(size_t i = 0; i != code->get_N(); ++i) 51 | { 52 | if(!dict.has_key(i)) 53 | continue; 54 | 55 | share_data[i] = boost::python::extract(dict.get(i)); 56 | 57 | if(share_size == 0) 58 | share_size = share_data[i].length(); 59 | else if(share_size != share_data[i].length()) 60 | throw std::invalid_argument("FEC shares of unusual size"); 61 | 62 | shares[i] = reinterpret_cast(share_data[i].c_str()); 63 | } 64 | 65 | if(shares.size() < code->get_K()) 66 | throw std::invalid_argument("Could not decode, insufficient shares"); 67 | 68 | save_results fec_saver(code->get_K()); 69 | 70 | code->decode(shares, share_size, std::ref(fec_saver)); 71 | 72 | return fec_saver.get_results(); 73 | } 74 | 75 | BOOST_PYTHON_MODULE(pyfecpp) 76 | { 77 | boost::python::class_ 78 | ("fec_code", boost::python::init()) 79 | .def("encode", fec_encode) 80 | .def("decode", fec_decode) 81 | .add_property("K", &fec_code::get_K) 82 | .add_property("N", &fec_code::get_N); 83 | } 84 | -------------------------------------------------------------------------------- /fecpp_sse2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2009-2010 Jack Lloyd (jack@randombit.net) 3 | * 4 | * Distributed under the terms given in license.txt (Simplified BSD) 5 | */ 6 | 7 | #include "fecpp.h" 8 | #include 9 | 10 | namespace fecpp { 11 | 12 | size_t addmul_sse2(uint8_t z[], const uint8_t x[], uint8_t y, size_t size) 13 | { 14 | const __m128i polynomial = _mm_set1_epi8(0x1D); 15 | 16 | const size_t y_bits = 32 - __builtin_clz(y); 17 | 18 | const size_t consumed = size - (size % 64); 19 | 20 | // unrolled out to cache line size 21 | while(size >= 64) 22 | { 23 | __m128i x_1 = _mm_loadu_si128((const __m128i*)(x)); 24 | __m128i x_2 = _mm_loadu_si128((const __m128i*)(x + 16)); 25 | __m128i x_3 = _mm_loadu_si128((const __m128i*)(x + 32)); 26 | __m128i x_4 = _mm_loadu_si128((const __m128i*)(x + 48)); 27 | 28 | __m128i z_1 = _mm_load_si128((const __m128i*)(z)); 29 | __m128i z_2 = _mm_load_si128((const __m128i*)(z + 16)); 30 | __m128i z_3 = _mm_load_si128((const __m128i*)(z + 32)); 31 | __m128i z_4 = _mm_load_si128((const __m128i*)(z + 48)); 32 | 33 | // prefetch next two x and z blocks 34 | _mm_prefetch(x + 64, _MM_HINT_T0); 35 | _mm_prefetch(z + 64, _MM_HINT_T0); 36 | _mm_prefetch(x + 128, _MM_HINT_T1); 37 | _mm_prefetch(z + 128, _MM_HINT_T1); 38 | 39 | if(y & 0x01) 40 | { 41 | z_1 = _mm_xor_si128(z_1, x_1); 42 | z_2 = _mm_xor_si128(z_2, x_2); 43 | z_3 = _mm_xor_si128(z_3, x_3); 44 | z_4 = _mm_xor_si128(z_4, x_4); 45 | } 46 | 47 | for(size_t j = 1; j != y_bits; ++j) 48 | { 49 | /* 50 | * Each byte of each mask is either 0 or the polynomial 0x1D, 51 | * depending on if the high bit of x_i is set or not. 52 | */ 53 | 54 | __m128i mask_1 = _mm_setzero_si128(); 55 | __m128i mask_2 = _mm_setzero_si128(); 56 | __m128i mask_3 = _mm_setzero_si128(); 57 | __m128i mask_4 = _mm_setzero_si128(); 58 | 59 | // flip operation? 60 | mask_1 = _mm_cmpgt_epi8(mask_1, x_1); 61 | mask_2 = _mm_cmpgt_epi8(mask_2, x_2); 62 | mask_3 = _mm_cmpgt_epi8(mask_3, x_3); 63 | mask_4 = _mm_cmpgt_epi8(mask_4, x_4); 64 | 65 | x_1 = _mm_add_epi8(x_1, x_1); 66 | x_2 = _mm_add_epi8(x_2, x_2); 67 | x_3 = _mm_add_epi8(x_3, x_3); 68 | x_4 = _mm_add_epi8(x_4, x_4); 69 | 70 | mask_1 = _mm_and_si128(mask_1, polynomial); 71 | mask_2 = _mm_and_si128(mask_2, polynomial); 72 | mask_3 = _mm_and_si128(mask_3, polynomial); 73 | mask_4 = _mm_and_si128(mask_4, polynomial); 74 | 75 | x_1 = _mm_xor_si128(x_1, mask_1); 76 | x_2 = _mm_xor_si128(x_2, mask_2); 77 | x_3 = _mm_xor_si128(x_3, mask_3); 78 | x_4 = _mm_xor_si128(x_4, mask_4); 79 | 80 | if((y >> j) & 1) 81 | { 82 | z_1 = _mm_xor_si128(z_1, x_1); 83 | z_2 = _mm_xor_si128(z_2, x_2); 84 | z_3 = _mm_xor_si128(z_3, x_3); 85 | z_4 = _mm_xor_si128(z_4, x_4); 86 | } 87 | } 88 | 89 | _mm_store_si128((__m128i*)(z ), z_1); 90 | _mm_store_si128((__m128i*)(z + 16), z_2); 91 | _mm_store_si128((__m128i*)(z + 32), z_3); 92 | _mm_store_si128((__m128i*)(z + 48), z_4); 93 | 94 | x += 64; 95 | z += 64; 96 | size -= 64; 97 | } 98 | 99 | return consumed; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /fecpp_ssse3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2011 Billy Brumley (billy.brumley@aalto.fi) 3 | * 4 | * Distributed under the terms given in license.txt (Simplified BSD) 5 | */ 6 | 7 | #include "fecpp.h" 8 | #include 9 | 10 | namespace fecpp { 11 | 12 | namespace { 13 | 14 | /* 15 | * these tables are for the linear map bx^4 + a -> y(bx^4 + a) 16 | * implemented as two maps: 17 | * a -> y(a) 18 | * b -> y(bx^4) 19 | * and the final output is the sum of these two outputs. 20 | */ 21 | alignas(64) const uint8_t GFTBL[] = { 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 25 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 26 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 27 | 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1d, 0x3d, 0x5d, 0x7d, 0x9d, 0xbd, 0xdd, 0xfd, 28 | 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 29 | 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90, 0x9d, 0xad, 0xfd, 0xcd, 0x5d, 0x6d, 0x3d, 0x0d, 30 | 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c, 31 | 0x00, 0x40, 0x80, 0xc0, 0x1d, 0x5d, 0x9d, 0xdd, 0x3a, 0x7a, 0xba, 0xfa, 0x27, 0x67, 0xa7, 0xe7, 32 | 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x11, 0x1e, 0x1b, 0x28, 0x2d, 0x22, 0x27, 0x3c, 0x39, 0x36, 0x33, 33 | 0x00, 0x50, 0xa0, 0xf0, 0x5d, 0x0d, 0xfd, 0xad, 0xba, 0xea, 0x1a, 0x4a, 0xe7, 0xb7, 0x47, 0x17, 34 | 0x00, 0x06, 0x0c, 0x0a, 0x18, 0x1e, 0x14, 0x12, 0x30, 0x36, 0x3c, 0x3a, 0x28, 0x2e, 0x24, 0x22, 35 | 0x00, 0x60, 0xc0, 0xa0, 0x9d, 0xfd, 0x5d, 0x3d, 0x27, 0x47, 0xe7, 0x87, 0xba, 0xda, 0x7a, 0x1a, 36 | 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 37 | 0x00, 0x70, 0xe0, 0x90, 0xdd, 0xad, 0x3d, 0x4d, 0xa7, 0xd7, 0x47, 0x37, 0x7a, 0x0a, 0x9a, 0xea, 38 | 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 39 | 0x00, 0x80, 0x1d, 0x9d, 0x3a, 0xba, 0x27, 0xa7, 0x74, 0xf4, 0x69, 0xe9, 0x4e, 0xce, 0x53, 0xd3, 40 | 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 41 | 0x00, 0x90, 0x3d, 0xad, 0x7a, 0xea, 0x47, 0xd7, 0xf4, 0x64, 0xc9, 0x59, 0x8e, 0x1e, 0xb3, 0x23, 42 | 0x00, 0x0a, 0x14, 0x1e, 0x28, 0x22, 0x3c, 0x36, 0x50, 0x5a, 0x44, 0x4e, 0x78, 0x72, 0x6c, 0x66, 43 | 0x00, 0xa0, 0x5d, 0xfd, 0xba, 0x1a, 0xe7, 0x47, 0x69, 0xc9, 0x34, 0x94, 0xd3, 0x73, 0x8e, 0x2e, 44 | 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 45 | 0x00, 0xb0, 0x7d, 0xcd, 0xfa, 0x4a, 0x87, 0x37, 0xe9, 0x59, 0x94, 0x24, 0x13, 0xa3, 0x6e, 0xde, 46 | 0x00, 0x0c, 0x18, 0x14, 0x30, 0x3c, 0x28, 0x24, 0x60, 0x6c, 0x78, 0x74, 0x50, 0x5c, 0x48, 0x44, 47 | 0x00, 0xc0, 0x9d, 0x5d, 0x27, 0xe7, 0xba, 0x7a, 0x4e, 0x8e, 0xd3, 0x13, 0x69, 0xa9, 0xf4, 0x34, 48 | 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 49 | 0x00, 0xd0, 0xbd, 0x6d, 0x67, 0xb7, 0xda, 0x0a, 0xce, 0x1e, 0x73, 0xa3, 0xa9, 0x79, 0x14, 0xc4, 50 | 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 51 | 0x00, 0xe0, 0xdd, 0x3d, 0xa7, 0x47, 0x7a, 0x9a, 0x53, 0xb3, 0x8e, 0x6e, 0xf4, 0x14, 0x29, 0xc9, 52 | 0x00, 0x0f, 0x1e, 0x11, 0x3c, 0x33, 0x22, 0x2d, 0x78, 0x77, 0x66, 0x69, 0x44, 0x4b, 0x5a, 0x55, 53 | 0x00, 0xf0, 0xfd, 0x0d, 0xe7, 0x17, 0x1a, 0xea, 0xd3, 0x23, 0x2e, 0xde, 0x34, 0xc4, 0xc9, 0x39, 54 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 55 | 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, 56 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 57 | 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 58 | 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, 59 | 0x00, 0x3d, 0x7a, 0x47, 0xf4, 0xc9, 0x8e, 0xb3, 0xf5, 0xc8, 0x8f, 0xb2, 0x01, 0x3c, 0x7b, 0x46, 60 | 0x00, 0x13, 0x26, 0x35, 0x4c, 0x5f, 0x6a, 0x79, 0x98, 0x8b, 0xbe, 0xad, 0xd4, 0xc7, 0xf2, 0xe1, 61 | 0x00, 0x2d, 0x5a, 0x77, 0xb4, 0x99, 0xee, 0xc3, 0x75, 0x58, 0x2f, 0x02, 0xc1, 0xec, 0x9b, 0xb6, 62 | 0x00, 0x14, 0x28, 0x3c, 0x50, 0x44, 0x78, 0x6c, 0xa0, 0xb4, 0x88, 0x9c, 0xf0, 0xe4, 0xd8, 0xcc, 63 | 0x00, 0x5d, 0xba, 0xe7, 0x69, 0x34, 0xd3, 0x8e, 0xd2, 0x8f, 0x68, 0x35, 0xbb, 0xe6, 0x01, 0x5c, 64 | 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x41, 0x7e, 0x6b, 0xa8, 0xbd, 0x82, 0x97, 0xfc, 0xe9, 0xd6, 0xc3, 65 | 0x00, 0x4d, 0x9a, 0xd7, 0x29, 0x64, 0xb3, 0xfe, 0x52, 0x1f, 0xc8, 0x85, 0x7b, 0x36, 0xe1, 0xac, 66 | 0x00, 0x16, 0x2c, 0x3a, 0x58, 0x4e, 0x74, 0x62, 0xb0, 0xa6, 0x9c, 0x8a, 0xe8, 0xfe, 0xc4, 0xd2, 67 | 0x00, 0x7d, 0xfa, 0x87, 0xe9, 0x94, 0x13, 0x6e, 0xcf, 0xb2, 0x35, 0x48, 0x26, 0x5b, 0xdc, 0xa1, 68 | 0x00, 0x17, 0x2e, 0x39, 0x5c, 0x4b, 0x72, 0x65, 0xb8, 0xaf, 0x96, 0x81, 0xe4, 0xf3, 0xca, 0xdd, 69 | 0x00, 0x6d, 0xda, 0xb7, 0xa9, 0xc4, 0x73, 0x1e, 0x4f, 0x22, 0x95, 0xf8, 0xe6, 0x8b, 0x3c, 0x51, 70 | 0x00, 0x18, 0x30, 0x28, 0x60, 0x78, 0x50, 0x48, 0xc0, 0xd8, 0xf0, 0xe8, 0xa0, 0xb8, 0x90, 0x88, 71 | 0x00, 0x9d, 0x27, 0xba, 0x4e, 0xd3, 0x69, 0xf4, 0x9c, 0x01, 0xbb, 0x26, 0xd2, 0x4f, 0xf5, 0x68, 72 | 0x00, 0x19, 0x32, 0x2b, 0x64, 0x7d, 0x56, 0x4f, 0xc8, 0xd1, 0xfa, 0xe3, 0xac, 0xb5, 0x9e, 0x87, 73 | 0x00, 0x8d, 0x07, 0x8a, 0x0e, 0x83, 0x09, 0x84, 0x1c, 0x91, 0x1b, 0x96, 0x12, 0x9f, 0x15, 0x98, 74 | 0x00, 0x1a, 0x34, 0x2e, 0x68, 0x72, 0x5c, 0x46, 0xd0, 0xca, 0xe4, 0xfe, 0xb8, 0xa2, 0x8c, 0x96, 75 | 0x00, 0xbd, 0x67, 0xda, 0xce, 0x73, 0xa9, 0x14, 0x81, 0x3c, 0xe6, 0x5b, 0x4f, 0xf2, 0x28, 0x95, 76 | 0x00, 0x1b, 0x36, 0x2d, 0x6c, 0x77, 0x5a, 0x41, 0xd8, 0xc3, 0xee, 0xf5, 0xb4, 0xaf, 0x82, 0x99, 77 | 0x00, 0xad, 0x47, 0xea, 0x8e, 0x23, 0xc9, 0x64, 0x01, 0xac, 0x46, 0xeb, 0x8f, 0x22, 0xc8, 0x65, 78 | 0x00, 0x1c, 0x38, 0x24, 0x70, 0x6c, 0x48, 0x54, 0xe0, 0xfc, 0xd8, 0xc4, 0x90, 0x8c, 0xa8, 0xb4, 79 | 0x00, 0xdd, 0xa7, 0x7a, 0x53, 0x8e, 0xf4, 0x29, 0xa6, 0x7b, 0x01, 0xdc, 0xf5, 0x28, 0x52, 0x8f, 80 | 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, 81 | 0x00, 0xcd, 0x87, 0x4a, 0x13, 0xde, 0x94, 0x59, 0x26, 0xeb, 0xa1, 0x6c, 0x35, 0xf8, 0xb2, 0x7f, 82 | 0x00, 0x1e, 0x3c, 0x22, 0x78, 0x66, 0x44, 0x5a, 0xf0, 0xee, 0xcc, 0xd2, 0x88, 0x96, 0xb4, 0xaa, 83 | 0x00, 0xfd, 0xe7, 0x1a, 0xd3, 0x2e, 0x34, 0xc9, 0xbb, 0x46, 0x5c, 0xa1, 0x68, 0x95, 0x8f, 0x72, 84 | 0x00, 0x1f, 0x3e, 0x21, 0x7c, 0x63, 0x42, 0x5d, 0xf8, 0xe7, 0xc6, 0xd9, 0x84, 0x9b, 0xba, 0xa5, 85 | 0x00, 0xed, 0xc7, 0x2a, 0x93, 0x7e, 0x54, 0xb9, 0x3b, 0xd6, 0xfc, 0x11, 0xa8, 0x45, 0x6f, 0x82, 86 | 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1d, 0x3d, 0x5d, 0x7d, 0x9d, 0xbd, 0xdd, 0xfd, 87 | 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6, 0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b, 88 | 0x00, 0x21, 0x42, 0x63, 0x84, 0xa5, 0xc6, 0xe7, 0x15, 0x34, 0x57, 0x76, 0x91, 0xb0, 0xd3, 0xf2, 89 | 0x00, 0x2a, 0x54, 0x7e, 0xa8, 0x82, 0xfc, 0xd6, 0x4d, 0x67, 0x19, 0x33, 0xe5, 0xcf, 0xb1, 0x9b, 90 | 0x00, 0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x0d, 0x2f, 0x49, 0x6b, 0x85, 0xa7, 0xc1, 0xe3, 91 | 0x00, 0x1a, 0x34, 0x2e, 0x68, 0x72, 0x5c, 0x46, 0xd0, 0xca, 0xe4, 0xfe, 0xb8, 0xa2, 0x8c, 0x96, 92 | 0x00, 0x23, 0x46, 0x65, 0x8c, 0xaf, 0xca, 0xe9, 0x05, 0x26, 0x43, 0x60, 0x89, 0xaa, 0xcf, 0xec, 93 | 0x00, 0x0a, 0x14, 0x1e, 0x28, 0x22, 0x3c, 0x36, 0x50, 0x5a, 0x44, 0x4e, 0x78, 0x72, 0x6c, 0x66, 94 | 0x00, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0xd8, 0xfc, 0x3d, 0x19, 0x75, 0x51, 0xad, 0x89, 0xe5, 0xc1, 95 | 0x00, 0x7a, 0xf4, 0x8e, 0xf5, 0x8f, 0x01, 0x7b, 0xf7, 0x8d, 0x03, 0x79, 0x02, 0x78, 0xf6, 0x8c, 96 | 0x00, 0x25, 0x4a, 0x6f, 0x94, 0xb1, 0xde, 0xfb, 0x35, 0x10, 0x7f, 0x5a, 0xa1, 0x84, 0xeb, 0xce, 97 | 0x00, 0x6a, 0xd4, 0xbe, 0xb5, 0xdf, 0x61, 0x0b, 0x77, 0x1d, 0xa3, 0xc9, 0xc2, 0xa8, 0x16, 0x7c, 98 | 0x00, 0x26, 0x4c, 0x6a, 0x98, 0xbe, 0xd4, 0xf2, 0x2d, 0x0b, 0x61, 0x47, 0xb5, 0x93, 0xf9, 0xdf, 99 | 0x00, 0x5a, 0xb4, 0xee, 0x75, 0x2f, 0xc1, 0x9b, 0xea, 0xb0, 0x5e, 0x04, 0x9f, 0xc5, 0x2b, 0x71, 100 | 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5, 0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0, 101 | 0x00, 0x4a, 0x94, 0xde, 0x35, 0x7f, 0xa1, 0xeb, 0x6a, 0x20, 0xfe, 0xb4, 0x5f, 0x15, 0xcb, 0x81, 102 | 0x00, 0x28, 0x50, 0x78, 0xa0, 0x88, 0xf0, 0xd8, 0x5d, 0x75, 0x0d, 0x25, 0xfd, 0xd5, 0xad, 0x85, 103 | 0x00, 0xba, 0x69, 0xd3, 0xd2, 0x68, 0xbb, 0x01, 0xb9, 0x03, 0xd0, 0x6a, 0x6b, 0xd1, 0x02, 0xb8, 104 | 0x00, 0x29, 0x52, 0x7b, 0xa4, 0x8d, 0xf6, 0xdf, 0x55, 0x7c, 0x07, 0x2e, 0xf1, 0xd8, 0xa3, 0x8a, 105 | 0x00, 0xaa, 0x49, 0xe3, 0x92, 0x38, 0xdb, 0x71, 0x39, 0x93, 0x70, 0xda, 0xab, 0x01, 0xe2, 0x48, 106 | 0x00, 0x2a, 0x54, 0x7e, 0xa8, 0x82, 0xfc, 0xd6, 0x4d, 0x67, 0x19, 0x33, 0xe5, 0xcf, 0xb1, 0x9b, 107 | 0x00, 0x9a, 0x29, 0xb3, 0x52, 0xc8, 0x7b, 0xe1, 0xa4, 0x3e, 0x8d, 0x17, 0xf6, 0x6c, 0xdf, 0x45, 108 | 0x00, 0x2b, 0x56, 0x7d, 0xac, 0x87, 0xfa, 0xd1, 0x45, 0x6e, 0x13, 0x38, 0xe9, 0xc2, 0xbf, 0x94, 109 | 0x00, 0x8a, 0x09, 0x83, 0x12, 0x98, 0x1b, 0x91, 0x24, 0xae, 0x2d, 0xa7, 0x36, 0xbc, 0x3f, 0xb5, 110 | 0x00, 0x2c, 0x58, 0x74, 0xb0, 0x9c, 0xe8, 0xc4, 0x7d, 0x51, 0x25, 0x09, 0xcd, 0xe1, 0x95, 0xb9, 111 | 0x00, 0xfa, 0xe9, 0x13, 0xcf, 0x35, 0x26, 0xdc, 0x83, 0x79, 0x6a, 0x90, 0x4c, 0xb6, 0xa5, 0x5f, 112 | 0x00, 0x2d, 0x5a, 0x77, 0xb4, 0x99, 0xee, 0xc3, 0x75, 0x58, 0x2f, 0x02, 0xc1, 0xec, 0x9b, 0xb6, 113 | 0x00, 0xea, 0xc9, 0x23, 0x8f, 0x65, 0x46, 0xac, 0x03, 0xe9, 0xca, 0x20, 0x8c, 0x66, 0x45, 0xaf, 114 | 0x00, 0x2e, 0x5c, 0x72, 0xb8, 0x96, 0xe4, 0xca, 0x6d, 0x43, 0x31, 0x1f, 0xd5, 0xfb, 0x89, 0xa7, 115 | 0x00, 0xda, 0xa9, 0x73, 0x4f, 0x95, 0xe6, 0x3c, 0x9e, 0x44, 0x37, 0xed, 0xd1, 0x0b, 0x78, 0xa2, 116 | 0x00, 0x2f, 0x5e, 0x71, 0xbc, 0x93, 0xe2, 0xcd, 0x65, 0x4a, 0x3b, 0x14, 0xd9, 0xf6, 0x87, 0xa8, 117 | 0x00, 0xca, 0x89, 0x43, 0x0f, 0xc5, 0x86, 0x4c, 0x1e, 0xd4, 0x97, 0x5d, 0x11, 0xdb, 0x98, 0x52, 118 | 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90, 0x9d, 0xad, 0xfd, 0xcd, 0x5d, 0x6d, 0x3d, 0x0d, 119 | 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5, 0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0, 120 | 0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0x95, 0xa4, 0xf7, 0xc6, 0x51, 0x60, 0x33, 0x02, 121 | 0x00, 0x37, 0x6e, 0x59, 0xdc, 0xeb, 0xb2, 0x85, 0xa5, 0x92, 0xcb, 0xfc, 0x79, 0x4e, 0x17, 0x20, 122 | 0x00, 0x32, 0x64, 0x56, 0xc8, 0xfa, 0xac, 0x9e, 0x8d, 0xbf, 0xe9, 0xdb, 0x45, 0x77, 0x21, 0x13, 123 | 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 124 | 0x00, 0x33, 0x66, 0x55, 0xcc, 0xff, 0xaa, 0x99, 0x85, 0xb6, 0xe3, 0xd0, 0x49, 0x7a, 0x2f, 0x1c, 125 | 0x00, 0x17, 0x2e, 0x39, 0x5c, 0x4b, 0x72, 0x65, 0xb8, 0xaf, 0x96, 0x81, 0xe4, 0xf3, 0xca, 0xdd, 126 | 0x00, 0x34, 0x68, 0x5c, 0xd0, 0xe4, 0xb8, 0x8c, 0xbd, 0x89, 0xd5, 0xe1, 0x6d, 0x59, 0x05, 0x31, 127 | 0x00, 0x67, 0xce, 0xa9, 0x81, 0xe6, 0x4f, 0x28, 0x1f, 0x78, 0xd1, 0xb6, 0x9e, 0xf9, 0x50, 0x37, 128 | 0x00, 0x35, 0x6a, 0x5f, 0xd4, 0xe1, 0xbe, 0x8b, 0xb5, 0x80, 0xdf, 0xea, 0x61, 0x54, 0x0b, 0x3e, 129 | 0x00, 0x77, 0xee, 0x99, 0xc1, 0xb6, 0x2f, 0x58, 0x9f, 0xe8, 0x71, 0x06, 0x5e, 0x29, 0xb0, 0xc7, 130 | 0x00, 0x36, 0x6c, 0x5a, 0xd8, 0xee, 0xb4, 0x82, 0xad, 0x9b, 0xc1, 0xf7, 0x75, 0x43, 0x19, 0x2f, 131 | 0x00, 0x47, 0x8e, 0xc9, 0x01, 0x46, 0x8f, 0xc8, 0x02, 0x45, 0x8c, 0xcb, 0x03, 0x44, 0x8d, 0xca, 132 | 0x00, 0x37, 0x6e, 0x59, 0xdc, 0xeb, 0xb2, 0x85, 0xa5, 0x92, 0xcb, 0xfc, 0x79, 0x4e, 0x17, 0x20, 133 | 0x00, 0x57, 0xae, 0xf9, 0x41, 0x16, 0xef, 0xb8, 0x82, 0xd5, 0x2c, 0x7b, 0xc3, 0x94, 0x6d, 0x3a, 134 | 0x00, 0x38, 0x70, 0x48, 0xe0, 0xd8, 0x90, 0xa8, 0xdd, 0xe5, 0xad, 0x95, 0x3d, 0x05, 0x4d, 0x75, 135 | 0x00, 0xa7, 0x53, 0xf4, 0xa6, 0x01, 0xf5, 0x52, 0x51, 0xf6, 0x02, 0xa5, 0xf7, 0x50, 0xa4, 0x03, 136 | 0x00, 0x39, 0x72, 0x4b, 0xe4, 0xdd, 0x96, 0xaf, 0xd5, 0xec, 0xa7, 0x9e, 0x31, 0x08, 0x43, 0x7a, 137 | 0x00, 0xb7, 0x73, 0xc4, 0xe6, 0x51, 0x95, 0x22, 0xd1, 0x66, 0xa2, 0x15, 0x37, 0x80, 0x44, 0xf3, 138 | 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6, 0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b, 139 | 0x00, 0x87, 0x13, 0x94, 0x26, 0xa1, 0x35, 0xb2, 0x4c, 0xcb, 0x5f, 0xd8, 0x6a, 0xed, 0x79, 0xfe, 140 | 0x00, 0x3b, 0x76, 0x4d, 0xec, 0xd7, 0x9a, 0xa1, 0xc5, 0xfe, 0xb3, 0x88, 0x29, 0x12, 0x5f, 0x64, 141 | 0x00, 0x97, 0x33, 0xa4, 0x66, 0xf1, 0x55, 0xc2, 0xcc, 0x5b, 0xff, 0x68, 0xaa, 0x3d, 0x99, 0x0e, 142 | 0x00, 0x3c, 0x78, 0x44, 0xf0, 0xcc, 0x88, 0xb4, 0xfd, 0xc1, 0x85, 0xb9, 0x0d, 0x31, 0x75, 0x49, 143 | 0x00, 0xe7, 0xd3, 0x34, 0xbb, 0x5c, 0x68, 0x8f, 0x6b, 0x8c, 0xb8, 0x5f, 0xd0, 0x37, 0x03, 0xe4, 144 | 0x00, 0x3d, 0x7a, 0x47, 0xf4, 0xc9, 0x8e, 0xb3, 0xf5, 0xc8, 0x8f, 0xb2, 0x01, 0x3c, 0x7b, 0x46, 145 | 0x00, 0xf7, 0xf3, 0x04, 0xfb, 0x0c, 0x08, 0xff, 0xeb, 0x1c, 0x18, 0xef, 0x10, 0xe7, 0xe3, 0x14, 146 | 0x00, 0x3e, 0x7c, 0x42, 0xf8, 0xc6, 0x84, 0xba, 0xed, 0xd3, 0x91, 0xaf, 0x15, 0x2b, 0x69, 0x57, 147 | 0x00, 0xc7, 0x93, 0x54, 0x3b, 0xfc, 0xa8, 0x6f, 0x76, 0xb1, 0xe5, 0x22, 0x4d, 0x8a, 0xde, 0x19, 148 | 0x00, 0x3f, 0x7e, 0x41, 0xfc, 0xc3, 0x82, 0xbd, 0xe5, 0xda, 0x9b, 0xa4, 0x19, 0x26, 0x67, 0x58, 149 | 0x00, 0xd7, 0xb3, 0x64, 0x7b, 0xac, 0xc8, 0x1f, 0xf6, 0x21, 0x45, 0x92, 0x8d, 0x5a, 0x3e, 0xe9, 150 | 0x00, 0x40, 0x80, 0xc0, 0x1d, 0x5d, 0x9d, 0xdd, 0x3a, 0x7a, 0xba, 0xfa, 0x27, 0x67, 0xa7, 0xe7, 151 | 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51, 0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6, 152 | 0x00, 0x41, 0x82, 0xc3, 0x19, 0x58, 0x9b, 0xda, 0x32, 0x73, 0xb0, 0xf1, 0x2b, 0x6a, 0xa9, 0xe8, 153 | 0x00, 0x64, 0xc8, 0xac, 0x8d, 0xe9, 0x45, 0x21, 0x07, 0x63, 0xcf, 0xab, 0x8a, 0xee, 0x42, 0x26, 154 | 0x00, 0x42, 0x84, 0xc6, 0x15, 0x57, 0x91, 0xd3, 0x2a, 0x68, 0xae, 0xec, 0x3f, 0x7d, 0xbb, 0xf9, 155 | 0x00, 0x54, 0xa8, 0xfc, 0x4d, 0x19, 0xe5, 0xb1, 0x9a, 0xce, 0x32, 0x66, 0xd7, 0x83, 0x7f, 0x2b, 156 | 0x00, 0x43, 0x86, 0xc5, 0x11, 0x52, 0x97, 0xd4, 0x22, 0x61, 0xa4, 0xe7, 0x33, 0x70, 0xb5, 0xf6, 157 | 0x00, 0x44, 0x88, 0xcc, 0x0d, 0x49, 0x85, 0xc1, 0x1a, 0x5e, 0x92, 0xd6, 0x17, 0x53, 0x9f, 0xdb, 158 | 0x00, 0x44, 0x88, 0xcc, 0x0d, 0x49, 0x85, 0xc1, 0x1a, 0x5e, 0x92, 0xd6, 0x17, 0x53, 0x9f, 0xdb, 159 | 0x00, 0x34, 0x68, 0x5c, 0xd0, 0xe4, 0xb8, 0x8c, 0xbd, 0x89, 0xd5, 0xe1, 0x6d, 0x59, 0x05, 0x31, 160 | 0x00, 0x45, 0x8a, 0xcf, 0x09, 0x4c, 0x83, 0xc6, 0x12, 0x57, 0x98, 0xdd, 0x1b, 0x5e, 0x91, 0xd4, 161 | 0x00, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0xd8, 0xfc, 0x3d, 0x19, 0x75, 0x51, 0xad, 0x89, 0xe5, 0xc1, 162 | 0x00, 0x46, 0x8c, 0xca, 0x05, 0x43, 0x89, 0xcf, 0x0a, 0x4c, 0x86, 0xc0, 0x0f, 0x49, 0x83, 0xc5, 163 | 0x00, 0x14, 0x28, 0x3c, 0x50, 0x44, 0x78, 0x6c, 0xa0, 0xb4, 0x88, 0x9c, 0xf0, 0xe4, 0xd8, 0xcc, 164 | 0x00, 0x47, 0x8e, 0xc9, 0x01, 0x46, 0x8f, 0xc8, 0x02, 0x45, 0x8c, 0xcb, 0x03, 0x44, 0x8d, 0xca, 165 | 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c, 166 | 0x00, 0x48, 0x90, 0xd8, 0x3d, 0x75, 0xad, 0xe5, 0x7a, 0x32, 0xea, 0xa2, 0x47, 0x0f, 0xd7, 0x9f, 167 | 0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05, 168 | 0x00, 0x49, 0x92, 0xdb, 0x39, 0x70, 0xab, 0xe2, 0x72, 0x3b, 0xe0, 0xa9, 0x4b, 0x02, 0xd9, 0x90, 169 | 0x00, 0xe4, 0xd5, 0x31, 0xb7, 0x53, 0x62, 0x86, 0x73, 0x97, 0xa6, 0x42, 0xc4, 0x20, 0x11, 0xf5, 170 | 0x00, 0x4a, 0x94, 0xde, 0x35, 0x7f, 0xa1, 0xeb, 0x6a, 0x20, 0xfe, 0xb4, 0x5f, 0x15, 0xcb, 0x81, 171 | 0x00, 0xd4, 0xb5, 0x61, 0x77, 0xa3, 0xc2, 0x16, 0xee, 0x3a, 0x5b, 0x8f, 0x99, 0x4d, 0x2c, 0xf8, 172 | 0x00, 0x4b, 0x96, 0xdd, 0x31, 0x7a, 0xa7, 0xec, 0x62, 0x29, 0xf4, 0xbf, 0x53, 0x18, 0xc5, 0x8e, 173 | 0x00, 0xc4, 0x95, 0x51, 0x37, 0xf3, 0xa2, 0x66, 0x6e, 0xaa, 0xfb, 0x3f, 0x59, 0x9d, 0xcc, 0x08, 174 | 0x00, 0x4c, 0x98, 0xd4, 0x2d, 0x61, 0xb5, 0xf9, 0x5a, 0x16, 0xc2, 0x8e, 0x77, 0x3b, 0xef, 0xa3, 175 | 0x00, 0xb4, 0x75, 0xc1, 0xea, 0x5e, 0x9f, 0x2b, 0xc9, 0x7d, 0xbc, 0x08, 0x23, 0x97, 0x56, 0xe2, 176 | 0x00, 0x4d, 0x9a, 0xd7, 0x29, 0x64, 0xb3, 0xfe, 0x52, 0x1f, 0xc8, 0x85, 0x7b, 0x36, 0xe1, 0xac, 177 | 0x00, 0xa4, 0x55, 0xf1, 0xaa, 0x0e, 0xff, 0x5b, 0x49, 0xed, 0x1c, 0xb8, 0xe3, 0x47, 0xb6, 0x12, 178 | 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7, 0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd, 179 | 0x00, 0x94, 0x35, 0xa1, 0x6a, 0xfe, 0x5f, 0xcb, 0xd4, 0x40, 0xe1, 0x75, 0xbe, 0x2a, 0x8b, 0x1f, 180 | 0x00, 0x4f, 0x9e, 0xd1, 0x21, 0x6e, 0xbf, 0xf0, 0x42, 0x0d, 0xdc, 0x93, 0x63, 0x2c, 0xfd, 0xb2, 181 | 0x00, 0x84, 0x15, 0x91, 0x2a, 0xae, 0x3f, 0xbb, 0x54, 0xd0, 0x41, 0xc5, 0x7e, 0xfa, 0x6b, 0xef, 182 | 0x00, 0x50, 0xa0, 0xf0, 0x5d, 0x0d, 0xfd, 0xad, 0xba, 0xea, 0x1a, 0x4a, 0xe7, 0xb7, 0x47, 0x17, 183 | 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02, 0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d, 184 | 0x00, 0x51, 0xa2, 0xf3, 0x59, 0x08, 0xfb, 0xaa, 0xb2, 0xe3, 0x10, 0x41, 0xeb, 0xba, 0x49, 0x18, 185 | 0x00, 0x79, 0xf2, 0x8b, 0xf9, 0x80, 0x0b, 0x72, 0xef, 0x96, 0x1d, 0x64, 0x16, 0x6f, 0xe4, 0x9d, 186 | 0x00, 0x52, 0xa4, 0xf6, 0x55, 0x07, 0xf1, 0xa3, 0xaa, 0xf8, 0x0e, 0x5c, 0xff, 0xad, 0x5b, 0x09, 187 | 0x00, 0x49, 0x92, 0xdb, 0x39, 0x70, 0xab, 0xe2, 0x72, 0x3b, 0xe0, 0xa9, 0x4b, 0x02, 0xd9, 0x90, 188 | 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4, 0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06, 189 | 0x00, 0x59, 0xb2, 0xeb, 0x79, 0x20, 0xcb, 0x92, 0xf2, 0xab, 0x40, 0x19, 0x8b, 0xd2, 0x39, 0x60, 190 | 0x00, 0x54, 0xa8, 0xfc, 0x4d, 0x19, 0xe5, 0xb1, 0x9a, 0xce, 0x32, 0x66, 0xd7, 0x83, 0x7f, 0x2b, 191 | 0x00, 0x29, 0x52, 0x7b, 0xa4, 0x8d, 0xf6, 0xdf, 0x55, 0x7c, 0x07, 0x2e, 0xf1, 0xd8, 0xa3, 0x8a, 192 | 0x00, 0x55, 0xaa, 0xff, 0x49, 0x1c, 0xe3, 0xb6, 0x92, 0xc7, 0x38, 0x6d, 0xdb, 0x8e, 0x71, 0x24, 193 | 0x00, 0x39, 0x72, 0x4b, 0xe4, 0xdd, 0x96, 0xaf, 0xd5, 0xec, 0xa7, 0x9e, 0x31, 0x08, 0x43, 0x7a, 194 | 0x00, 0x56, 0xac, 0xfa, 0x45, 0x13, 0xe9, 0xbf, 0x8a, 0xdc, 0x26, 0x70, 0xcf, 0x99, 0x63, 0x35, 195 | 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 196 | 0x00, 0x57, 0xae, 0xf9, 0x41, 0x16, 0xef, 0xb8, 0x82, 0xd5, 0x2c, 0x7b, 0xc3, 0x94, 0x6d, 0x3a, 197 | 0x00, 0x19, 0x32, 0x2b, 0x64, 0x7d, 0x56, 0x4f, 0xc8, 0xd1, 0xfa, 0xe3, 0xac, 0xb5, 0x9e, 0x87, 198 | 0x00, 0x58, 0xb0, 0xe8, 0x7d, 0x25, 0xcd, 0x95, 0xfa, 0xa2, 0x4a, 0x12, 0x87, 0xdf, 0x37, 0x6f, 199 | 0x00, 0xe9, 0xcf, 0x26, 0x83, 0x6a, 0x4c, 0xa5, 0x1b, 0xf2, 0xd4, 0x3d, 0x98, 0x71, 0x57, 0xbe, 200 | 0x00, 0x59, 0xb2, 0xeb, 0x79, 0x20, 0xcb, 0x92, 0xf2, 0xab, 0x40, 0x19, 0x8b, 0xd2, 0x39, 0x60, 201 | 0x00, 0xf9, 0xef, 0x16, 0xc3, 0x3a, 0x2c, 0xd5, 0x9b, 0x62, 0x74, 0x8d, 0x58, 0xa1, 0xb7, 0x4e, 202 | 0x00, 0x5a, 0xb4, 0xee, 0x75, 0x2f, 0xc1, 0x9b, 0xea, 0xb0, 0x5e, 0x04, 0x9f, 0xc5, 0x2b, 0x71, 203 | 0x00, 0xc9, 0x8f, 0x46, 0x03, 0xca, 0x8c, 0x45, 0x06, 0xcf, 0x89, 0x40, 0x05, 0xcc, 0x8a, 0x43, 204 | 0x00, 0x5b, 0xb6, 0xed, 0x71, 0x2a, 0xc7, 0x9c, 0xe2, 0xb9, 0x54, 0x0f, 0x93, 0xc8, 0x25, 0x7e, 205 | 0x00, 0xd9, 0xaf, 0x76, 0x43, 0x9a, 0xec, 0x35, 0x86, 0x5f, 0x29, 0xf0, 0xc5, 0x1c, 0x6a, 0xb3, 206 | 0x00, 0x5c, 0xb8, 0xe4, 0x6d, 0x31, 0xd5, 0x89, 0xda, 0x86, 0x62, 0x3e, 0xb7, 0xeb, 0x0f, 0x53, 207 | 0x00, 0xa9, 0x4f, 0xe6, 0x9e, 0x37, 0xd1, 0x78, 0x21, 0x88, 0x6e, 0xc7, 0xbf, 0x16, 0xf0, 0x59, 208 | 0x00, 0x5d, 0xba, 0xe7, 0x69, 0x34, 0xd3, 0x8e, 0xd2, 0x8f, 0x68, 0x35, 0xbb, 0xe6, 0x01, 0x5c, 209 | 0x00, 0xb9, 0x6f, 0xd6, 0xde, 0x67, 0xb1, 0x08, 0xa1, 0x18, 0xce, 0x77, 0x7f, 0xc6, 0x10, 0xa9, 210 | 0x00, 0x5e, 0xbc, 0xe2, 0x65, 0x3b, 0xd9, 0x87, 0xca, 0x94, 0x76, 0x28, 0xaf, 0xf1, 0x13, 0x4d, 211 | 0x00, 0x89, 0x0f, 0x86, 0x1e, 0x97, 0x11, 0x98, 0x3c, 0xb5, 0x33, 0xba, 0x22, 0xab, 0x2d, 0xa4, 212 | 0x00, 0x5f, 0xbe, 0xe1, 0x61, 0x3e, 0xdf, 0x80, 0xc2, 0x9d, 0x7c, 0x23, 0xa3, 0xfc, 0x1d, 0x42, 213 | 0x00, 0x99, 0x2f, 0xb6, 0x5e, 0xc7, 0x71, 0xe8, 0xbc, 0x25, 0x93, 0x0a, 0xe2, 0x7b, 0xcd, 0x54, 214 | 0x00, 0x60, 0xc0, 0xa0, 0x9d, 0xfd, 0x5d, 0x3d, 0x27, 0x47, 0xe7, 0x87, 0xba, 0xda, 0x7a, 0x1a, 215 | 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7, 0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd, 216 | 0x00, 0x61, 0xc2, 0xa3, 0x99, 0xf8, 0x5b, 0x3a, 0x2f, 0x4e, 0xed, 0x8c, 0xb6, 0xd7, 0x74, 0x15, 217 | 0x00, 0x5e, 0xbc, 0xe2, 0x65, 0x3b, 0xd9, 0x87, 0xca, 0x94, 0x76, 0x28, 0xaf, 0xf1, 0x13, 0x4d, 218 | 0x00, 0x62, 0xc4, 0xa6, 0x95, 0xf7, 0x51, 0x33, 0x37, 0x55, 0xf3, 0x91, 0xa2, 0xc0, 0x66, 0x04, 219 | 0x00, 0x6e, 0xdc, 0xb2, 0xa5, 0xcb, 0x79, 0x17, 0x57, 0x39, 0x8b, 0xe5, 0xf2, 0x9c, 0x2e, 0x40, 220 | 0x00, 0x63, 0xc6, 0xa5, 0x91, 0xf2, 0x57, 0x34, 0x3f, 0x5c, 0xf9, 0x9a, 0xae, 0xcd, 0x68, 0x0b, 221 | 0x00, 0x7e, 0xfc, 0x82, 0xe5, 0x9b, 0x19, 0x67, 0xd7, 0xa9, 0x2b, 0x55, 0x32, 0x4c, 0xce, 0xb0, 222 | 0x00, 0x64, 0xc8, 0xac, 0x8d, 0xe9, 0x45, 0x21, 0x07, 0x63, 0xcf, 0xab, 0x8a, 0xee, 0x42, 0x26, 223 | 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 224 | 0x00, 0x65, 0xca, 0xaf, 0x89, 0xec, 0x43, 0x26, 0x0f, 0x6a, 0xc5, 0xa0, 0x86, 0xe3, 0x4c, 0x29, 225 | 0x00, 0x1e, 0x3c, 0x22, 0x78, 0x66, 0x44, 0x5a, 0xf0, 0xee, 0xcc, 0xd2, 0x88, 0x96, 0xb4, 0xaa, 226 | 0x00, 0x66, 0xcc, 0xaa, 0x85, 0xe3, 0x49, 0x2f, 0x17, 0x71, 0xdb, 0xbd, 0x92, 0xf4, 0x5e, 0x38, 227 | 0x00, 0x2e, 0x5c, 0x72, 0xb8, 0x96, 0xe4, 0xca, 0x6d, 0x43, 0x31, 0x1f, 0xd5, 0xfb, 0x89, 0xa7, 228 | 0x00, 0x67, 0xce, 0xa9, 0x81, 0xe6, 0x4f, 0x28, 0x1f, 0x78, 0xd1, 0xb6, 0x9e, 0xf9, 0x50, 0x37, 229 | 0x00, 0x3e, 0x7c, 0x42, 0xf8, 0xc6, 0x84, 0xba, 0xed, 0xd3, 0x91, 0xaf, 0x15, 0x2b, 0x69, 0x57, 230 | 0x00, 0x68, 0xd0, 0xb8, 0xbd, 0xd5, 0x6d, 0x05, 0x67, 0x0f, 0xb7, 0xdf, 0xda, 0xb2, 0x0a, 0x62, 231 | 0x00, 0xce, 0x81, 0x4f, 0x1f, 0xd1, 0x9e, 0x50, 0x3e, 0xf0, 0xbf, 0x71, 0x21, 0xef, 0xa0, 0x6e, 232 | 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02, 0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d, 233 | 0x00, 0xde, 0xa1, 0x7f, 0x5f, 0x81, 0xfe, 0x20, 0xbe, 0x60, 0x1f, 0xc1, 0xe1, 0x3f, 0x40, 0x9e, 234 | 0x00, 0x6a, 0xd4, 0xbe, 0xb5, 0xdf, 0x61, 0x0b, 0x77, 0x1d, 0xa3, 0xc9, 0xc2, 0xa8, 0x16, 0x7c, 235 | 0x00, 0xee, 0xc1, 0x2f, 0x9f, 0x71, 0x5e, 0xb0, 0x23, 0xcd, 0xe2, 0x0c, 0xbc, 0x52, 0x7d, 0x93, 236 | 0x00, 0x6b, 0xd6, 0xbd, 0xb1, 0xda, 0x67, 0x0c, 0x7f, 0x14, 0xa9, 0xc2, 0xce, 0xa5, 0x18, 0x73, 237 | 0x00, 0xfe, 0xe1, 0x1f, 0xdf, 0x21, 0x3e, 0xc0, 0xa3, 0x5d, 0x42, 0xbc, 0x7c, 0x82, 0x9d, 0x63, 238 | 0x00, 0x6c, 0xd8, 0xb4, 0xad, 0xc1, 0x75, 0x19, 0x47, 0x2b, 0x9f, 0xf3, 0xea, 0x86, 0x32, 0x5e, 239 | 0x00, 0x8e, 0x01, 0x8f, 0x02, 0x8c, 0x03, 0x8d, 0x04, 0x8a, 0x05, 0x8b, 0x06, 0x88, 0x07, 0x89, 240 | 0x00, 0x6d, 0xda, 0xb7, 0xa9, 0xc4, 0x73, 0x1e, 0x4f, 0x22, 0x95, 0xf8, 0xe6, 0x8b, 0x3c, 0x51, 241 | 0x00, 0x9e, 0x21, 0xbf, 0x42, 0xdc, 0x63, 0xfd, 0x84, 0x1a, 0xa5, 0x3b, 0xc6, 0x58, 0xe7, 0x79, 242 | 0x00, 0x6e, 0xdc, 0xb2, 0xa5, 0xcb, 0x79, 0x17, 0x57, 0x39, 0x8b, 0xe5, 0xf2, 0x9c, 0x2e, 0x40, 243 | 0x00, 0xae, 0x41, 0xef, 0x82, 0x2c, 0xc3, 0x6d, 0x19, 0xb7, 0x58, 0xf6, 0x9b, 0x35, 0xda, 0x74, 244 | 0x00, 0x6f, 0xde, 0xb1, 0xa1, 0xce, 0x7f, 0x10, 0x5f, 0x30, 0x81, 0xee, 0xfe, 0x91, 0x20, 0x4f, 245 | 0x00, 0xbe, 0x61, 0xdf, 0xc2, 0x7c, 0xa3, 0x1d, 0x99, 0x27, 0xf8, 0x46, 0x5b, 0xe5, 0x3a, 0x84, 246 | 0x00, 0x70, 0xe0, 0x90, 0xdd, 0xad, 0x3d, 0x4d, 0xa7, 0xd7, 0x47, 0x37, 0x7a, 0x0a, 0x9a, 0xea, 247 | 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4, 0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06, 248 | 0x00, 0x71, 0xe2, 0x93, 0xd9, 0xa8, 0x3b, 0x4a, 0xaf, 0xde, 0x4d, 0x3c, 0x76, 0x07, 0x94, 0xe5, 249 | 0x00, 0x43, 0x86, 0xc5, 0x11, 0x52, 0x97, 0xd4, 0x22, 0x61, 0xa4, 0xe7, 0x33, 0x70, 0xb5, 0xf6, 250 | 0x00, 0x72, 0xe4, 0x96, 0xd5, 0xa7, 0x31, 0x43, 0xb7, 0xc5, 0x53, 0x21, 0x62, 0x10, 0x86, 0xf4, 251 | 0x00, 0x73, 0xe6, 0x95, 0xd1, 0xa2, 0x37, 0x44, 0xbf, 0xcc, 0x59, 0x2a, 0x6e, 0x1d, 0x88, 0xfb, 252 | 0x00, 0x73, 0xe6, 0x95, 0xd1, 0xa2, 0x37, 0x44, 0xbf, 0xcc, 0x59, 0x2a, 0x6e, 0x1d, 0x88, 0xfb, 253 | 0x00, 0x63, 0xc6, 0xa5, 0x91, 0xf2, 0x57, 0x34, 0x3f, 0x5c, 0xf9, 0x9a, 0xae, 0xcd, 0x68, 0x0b, 254 | 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51, 0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6, 255 | 0x00, 0x13, 0x26, 0x35, 0x4c, 0x5f, 0x6a, 0x79, 0x98, 0x8b, 0xbe, 0xad, 0xd4, 0xc7, 0xf2, 0xe1, 256 | 0x00, 0x75, 0xea, 0x9f, 0xc9, 0xbc, 0x23, 0x56, 0x8f, 0xfa, 0x65, 0x10, 0x46, 0x33, 0xac, 0xd9, 257 | 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 258 | 0x00, 0x76, 0xec, 0x9a, 0xc5, 0xb3, 0x29, 0x5f, 0x97, 0xe1, 0x7b, 0x0d, 0x52, 0x24, 0xbe, 0xc8, 259 | 0x00, 0x33, 0x66, 0x55, 0xcc, 0xff, 0xaa, 0x99, 0x85, 0xb6, 0xe3, 0xd0, 0x49, 0x7a, 0x2f, 0x1c, 260 | 0x00, 0x77, 0xee, 0x99, 0xc1, 0xb6, 0x2f, 0x58, 0x9f, 0xe8, 0x71, 0x06, 0x5e, 0x29, 0xb0, 0xc7, 261 | 0x00, 0x23, 0x46, 0x65, 0x8c, 0xaf, 0xca, 0xe9, 0x05, 0x26, 0x43, 0x60, 0x89, 0xaa, 0xcf, 0xec, 262 | 0x00, 0x78, 0xf0, 0x88, 0xfd, 0x85, 0x0d, 0x75, 0xe7, 0x9f, 0x17, 0x6f, 0x1a, 0x62, 0xea, 0x92, 263 | 0x00, 0xd3, 0xbb, 0x68, 0x6b, 0xb8, 0xd0, 0x03, 0xd6, 0x05, 0x6d, 0xbe, 0xbd, 0x6e, 0x06, 0xd5, 264 | 0x00, 0x79, 0xf2, 0x8b, 0xf9, 0x80, 0x0b, 0x72, 0xef, 0x96, 0x1d, 0x64, 0x16, 0x6f, 0xe4, 0x9d, 265 | 0x00, 0xc3, 0x9b, 0x58, 0x2b, 0xe8, 0xb0, 0x73, 0x56, 0x95, 0xcd, 0x0e, 0x7d, 0xbe, 0xe6, 0x25, 266 | 0x00, 0x7a, 0xf4, 0x8e, 0xf5, 0x8f, 0x01, 0x7b, 0xf7, 0x8d, 0x03, 0x79, 0x02, 0x78, 0xf6, 0x8c, 267 | 0x00, 0xf3, 0xfb, 0x08, 0xeb, 0x18, 0x10, 0xe3, 0xcb, 0x38, 0x30, 0xc3, 0x20, 0xd3, 0xdb, 0x28, 268 | 0x00, 0x7b, 0xf6, 0x8d, 0xf1, 0x8a, 0x07, 0x7c, 0xff, 0x84, 0x09, 0x72, 0x0e, 0x75, 0xf8, 0x83, 269 | 0x00, 0xe3, 0xdb, 0x38, 0xab, 0x48, 0x70, 0x93, 0x4b, 0xa8, 0x90, 0x73, 0xe0, 0x03, 0x3b, 0xd8, 270 | 0x00, 0x7c, 0xf8, 0x84, 0xed, 0x91, 0x15, 0x69, 0xc7, 0xbb, 0x3f, 0x43, 0x2a, 0x56, 0xd2, 0xae, 271 | 0x00, 0x93, 0x3b, 0xa8, 0x76, 0xe5, 0x4d, 0xde, 0xec, 0x7f, 0xd7, 0x44, 0x9a, 0x09, 0xa1, 0x32, 272 | 0x00, 0x7d, 0xfa, 0x87, 0xe9, 0x94, 0x13, 0x6e, 0xcf, 0xb2, 0x35, 0x48, 0x26, 0x5b, 0xdc, 0xa1, 273 | 0x00, 0x83, 0x1b, 0x98, 0x36, 0xb5, 0x2d, 0xae, 0x6c, 0xef, 0x77, 0xf4, 0x5a, 0xd9, 0x41, 0xc2, 274 | 0x00, 0x7e, 0xfc, 0x82, 0xe5, 0x9b, 0x19, 0x67, 0xd7, 0xa9, 0x2b, 0x55, 0x32, 0x4c, 0xce, 0xb0, 275 | 0x00, 0xb3, 0x7b, 0xc8, 0xf6, 0x45, 0x8d, 0x3e, 0xf1, 0x42, 0x8a, 0x39, 0x07, 0xb4, 0x7c, 0xcf, 276 | 0x00, 0x7f, 0xfe, 0x81, 0xe1, 0x9e, 0x1f, 0x60, 0xdf, 0xa0, 0x21, 0x5e, 0x3e, 0x41, 0xc0, 0xbf, 277 | 0x00, 0xa3, 0x5b, 0xf8, 0xb6, 0x15, 0xed, 0x4e, 0x71, 0xd2, 0x2a, 0x89, 0xc7, 0x64, 0x9c, 0x3f, 278 | 0x00, 0x80, 0x1d, 0x9d, 0x3a, 0xba, 0x27, 0xa7, 0x74, 0xf4, 0x69, 0xe9, 0x4e, 0xce, 0x53, 0xd3, 279 | 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2, 0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1, 280 | 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0, 0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc, 281 | 0x00, 0xf8, 0xed, 0x15, 0xc7, 0x3f, 0x2a, 0xd2, 0x93, 0x6b, 0x7e, 0x86, 0x54, 0xac, 0xb9, 0x41, 282 | 0x00, 0x82, 0x19, 0x9b, 0x32, 0xb0, 0x2b, 0xa9, 0x64, 0xe6, 0x7d, 0xff, 0x56, 0xd4, 0x4f, 0xcd, 283 | 0x00, 0xc8, 0x8d, 0x45, 0x07, 0xcf, 0x8a, 0x42, 0x0e, 0xc6, 0x83, 0x4b, 0x09, 0xc1, 0x84, 0x4c, 284 | 0x00, 0x83, 0x1b, 0x98, 0x36, 0xb5, 0x2d, 0xae, 0x6c, 0xef, 0x77, 0xf4, 0x5a, 0xd9, 0x41, 0xc2, 285 | 0x00, 0xd8, 0xad, 0x75, 0x47, 0x9f, 0xea, 0x32, 0x8e, 0x56, 0x23, 0xfb, 0xc9, 0x11, 0x64, 0xbc, 286 | 0x00, 0x84, 0x15, 0x91, 0x2a, 0xae, 0x3f, 0xbb, 0x54, 0xd0, 0x41, 0xc5, 0x7e, 0xfa, 0x6b, 0xef, 287 | 0x00, 0xa8, 0x4d, 0xe5, 0x9a, 0x32, 0xd7, 0x7f, 0x29, 0x81, 0x64, 0xcc, 0xb3, 0x1b, 0xfe, 0x56, 288 | 0x00, 0x85, 0x17, 0x92, 0x2e, 0xab, 0x39, 0xbc, 0x5c, 0xd9, 0x4b, 0xce, 0x72, 0xf7, 0x65, 0xe0, 289 | 0x00, 0xb8, 0x6d, 0xd5, 0xda, 0x62, 0xb7, 0x0f, 0xa9, 0x11, 0xc4, 0x7c, 0x73, 0xcb, 0x1e, 0xa6, 290 | 0x00, 0x86, 0x11, 0x97, 0x22, 0xa4, 0x33, 0xb5, 0x44, 0xc2, 0x55, 0xd3, 0x66, 0xe0, 0x77, 0xf1, 291 | 0x00, 0x88, 0x0d, 0x85, 0x1a, 0x92, 0x17, 0x9f, 0x34, 0xbc, 0x39, 0xb1, 0x2e, 0xa6, 0x23, 0xab, 292 | 0x00, 0x87, 0x13, 0x94, 0x26, 0xa1, 0x35, 0xb2, 0x4c, 0xcb, 0x5f, 0xd8, 0x6a, 0xed, 0x79, 0xfe, 293 | 0x00, 0x98, 0x2d, 0xb5, 0x5a, 0xc2, 0x77, 0xef, 0xb4, 0x2c, 0x99, 0x01, 0xee, 0x76, 0xc3, 0x5b, 294 | 0x00, 0x88, 0x0d, 0x85, 0x1a, 0x92, 0x17, 0x9f, 0x34, 0xbc, 0x39, 0xb1, 0x2e, 0xa6, 0x23, 0xab, 295 | 0x00, 0x68, 0xd0, 0xb8, 0xbd, 0xd5, 0x6d, 0x05, 0x67, 0x0f, 0xb7, 0xdf, 0xda, 0xb2, 0x0a, 0x62, 296 | 0x00, 0x89, 0x0f, 0x86, 0x1e, 0x97, 0x11, 0x98, 0x3c, 0xb5, 0x33, 0xba, 0x22, 0xab, 0x2d, 0xa4, 297 | 0x00, 0x78, 0xf0, 0x88, 0xfd, 0x85, 0x0d, 0x75, 0xe7, 0x9f, 0x17, 0x6f, 0x1a, 0x62, 0xea, 0x92, 298 | 0x00, 0x8a, 0x09, 0x83, 0x12, 0x98, 0x1b, 0x91, 0x24, 0xae, 0x2d, 0xa7, 0x36, 0xbc, 0x3f, 0xb5, 299 | 0x00, 0x48, 0x90, 0xd8, 0x3d, 0x75, 0xad, 0xe5, 0x7a, 0x32, 0xea, 0xa2, 0x47, 0x0f, 0xd7, 0x9f, 300 | 0x00, 0x8b, 0x0b, 0x80, 0x16, 0x9d, 0x1d, 0x96, 0x2c, 0xa7, 0x27, 0xac, 0x3a, 0xb1, 0x31, 0xba, 301 | 0x00, 0x58, 0xb0, 0xe8, 0x7d, 0x25, 0xcd, 0x95, 0xfa, 0xa2, 0x4a, 0x12, 0x87, 0xdf, 0x37, 0x6f, 302 | 0x00, 0x8c, 0x05, 0x89, 0x0a, 0x86, 0x0f, 0x83, 0x14, 0x98, 0x11, 0x9d, 0x1e, 0x92, 0x1b, 0x97, 303 | 0x00, 0x28, 0x50, 0x78, 0xa0, 0x88, 0xf0, 0xd8, 0x5d, 0x75, 0x0d, 0x25, 0xfd, 0xd5, 0xad, 0x85, 304 | 0x00, 0x8d, 0x07, 0x8a, 0x0e, 0x83, 0x09, 0x84, 0x1c, 0x91, 0x1b, 0x96, 0x12, 0x9f, 0x15, 0x98, 305 | 0x00, 0x38, 0x70, 0x48, 0xe0, 0xd8, 0x90, 0xa8, 0xdd, 0xe5, 0xad, 0x95, 0x3d, 0x05, 0x4d, 0x75, 306 | 0x00, 0x8e, 0x01, 0x8f, 0x02, 0x8c, 0x03, 0x8d, 0x04, 0x8a, 0x05, 0x8b, 0x06, 0x88, 0x07, 0x89, 307 | 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 308 | 0x00, 0x8f, 0x03, 0x8c, 0x06, 0x89, 0x05, 0x8a, 0x0c, 0x83, 0x0f, 0x80, 0x0a, 0x85, 0x09, 0x86, 309 | 0x00, 0x18, 0x30, 0x28, 0x60, 0x78, 0x50, 0x48, 0xc0, 0xd8, 0xf0, 0xe8, 0xa0, 0xb8, 0x90, 0x88, 310 | 0x00, 0x90, 0x3d, 0xad, 0x7a, 0xea, 0x47, 0xd7, 0xf4, 0x64, 0xc9, 0x59, 0x8e, 0x1e, 0xb3, 0x23, 311 | 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1, 0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a, 312 | 0x00, 0x91, 0x3f, 0xae, 0x7e, 0xef, 0x41, 0xd0, 0xfc, 0x6d, 0xc3, 0x52, 0x82, 0x13, 0xbd, 0x2c, 313 | 0x00, 0xe5, 0xd7, 0x32, 0xb3, 0x56, 0x64, 0x81, 0x7b, 0x9e, 0xac, 0x49, 0xc8, 0x2d, 0x1f, 0xfa, 314 | 0x00, 0x92, 0x39, 0xab, 0x72, 0xe0, 0x4b, 0xd9, 0xe4, 0x76, 0xdd, 0x4f, 0x96, 0x04, 0xaf, 0x3d, 315 | 0x00, 0xd5, 0xb7, 0x62, 0x73, 0xa6, 0xc4, 0x11, 0xe6, 0x33, 0x51, 0x84, 0x95, 0x40, 0x22, 0xf7, 316 | 0x00, 0x93, 0x3b, 0xa8, 0x76, 0xe5, 0x4d, 0xde, 0xec, 0x7f, 0xd7, 0x44, 0x9a, 0x09, 0xa1, 0x32, 317 | 0x00, 0xc5, 0x97, 0x52, 0x33, 0xf6, 0xa4, 0x61, 0x66, 0xa3, 0xf1, 0x34, 0x55, 0x90, 0xc2, 0x07, 318 | 0x00, 0x94, 0x35, 0xa1, 0x6a, 0xfe, 0x5f, 0xcb, 0xd4, 0x40, 0xe1, 0x75, 0xbe, 0x2a, 0x8b, 0x1f, 319 | 0x00, 0xb5, 0x77, 0xc2, 0xee, 0x5b, 0x99, 0x2c, 0xc1, 0x74, 0xb6, 0x03, 0x2f, 0x9a, 0x58, 0xed, 320 | 0x00, 0x95, 0x37, 0xa2, 0x6e, 0xfb, 0x59, 0xcc, 0xdc, 0x49, 0xeb, 0x7e, 0xb2, 0x27, 0x85, 0x10, 321 | 0x00, 0xa5, 0x57, 0xf2, 0xae, 0x0b, 0xf9, 0x5c, 0x41, 0xe4, 0x16, 0xb3, 0xef, 0x4a, 0xb8, 0x1d, 322 | 0x00, 0x96, 0x31, 0xa7, 0x62, 0xf4, 0x53, 0xc5, 0xc4, 0x52, 0xf5, 0x63, 0xa6, 0x30, 0x97, 0x01, 323 | 0x00, 0x95, 0x37, 0xa2, 0x6e, 0xfb, 0x59, 0xcc, 0xdc, 0x49, 0xeb, 0x7e, 0xb2, 0x27, 0x85, 0x10, 324 | 0x00, 0x97, 0x33, 0xa4, 0x66, 0xf1, 0x55, 0xc2, 0xcc, 0x5b, 0xff, 0x68, 0xaa, 0x3d, 0x99, 0x0e, 325 | 0x00, 0x85, 0x17, 0x92, 0x2e, 0xab, 0x39, 0xbc, 0x5c, 0xd9, 0x4b, 0xce, 0x72, 0xf7, 0x65, 0xe0, 326 | 0x00, 0x98, 0x2d, 0xb5, 0x5a, 0xc2, 0x77, 0xef, 0xb4, 0x2c, 0x99, 0x01, 0xee, 0x76, 0xc3, 0x5b, 327 | 0x00, 0x75, 0xea, 0x9f, 0xc9, 0xbc, 0x23, 0x56, 0x8f, 0xfa, 0x65, 0x10, 0x46, 0x33, 0xac, 0xd9, 328 | 0x00, 0x99, 0x2f, 0xb6, 0x5e, 0xc7, 0x71, 0xe8, 0xbc, 0x25, 0x93, 0x0a, 0xe2, 0x7b, 0xcd, 0x54, 329 | 0x00, 0x65, 0xca, 0xaf, 0x89, 0xec, 0x43, 0x26, 0x0f, 0x6a, 0xc5, 0xa0, 0x86, 0xe3, 0x4c, 0x29, 330 | 0x00, 0x9a, 0x29, 0xb3, 0x52, 0xc8, 0x7b, 0xe1, 0xa4, 0x3e, 0x8d, 0x17, 0xf6, 0x6c, 0xdf, 0x45, 331 | 0x00, 0x55, 0xaa, 0xff, 0x49, 0x1c, 0xe3, 0xb6, 0x92, 0xc7, 0x38, 0x6d, 0xdb, 0x8e, 0x71, 0x24, 332 | 0x00, 0x9b, 0x2b, 0xb0, 0x56, 0xcd, 0x7d, 0xe6, 0xac, 0x37, 0x87, 0x1c, 0xfa, 0x61, 0xd1, 0x4a, 333 | 0x00, 0x45, 0x8a, 0xcf, 0x09, 0x4c, 0x83, 0xc6, 0x12, 0x57, 0x98, 0xdd, 0x1b, 0x5e, 0x91, 0xd4, 334 | 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3, 0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67, 335 | 0x00, 0x35, 0x6a, 0x5f, 0xd4, 0xe1, 0xbe, 0x8b, 0xb5, 0x80, 0xdf, 0xea, 0x61, 0x54, 0x0b, 0x3e, 336 | 0x00, 0x9d, 0x27, 0xba, 0x4e, 0xd3, 0x69, 0xf4, 0x9c, 0x01, 0xbb, 0x26, 0xd2, 0x4f, 0xf5, 0x68, 337 | 0x00, 0x25, 0x4a, 0x6f, 0x94, 0xb1, 0xde, 0xfb, 0x35, 0x10, 0x7f, 0x5a, 0xa1, 0x84, 0xeb, 0xce, 338 | 0x00, 0x9e, 0x21, 0xbf, 0x42, 0xdc, 0x63, 0xfd, 0x84, 0x1a, 0xa5, 0x3b, 0xc6, 0x58, 0xe7, 0x79, 339 | 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x41, 0x7e, 0x6b, 0xa8, 0xbd, 0x82, 0x97, 0xfc, 0xe9, 0xd6, 0xc3, 340 | 0x00, 0x9f, 0x23, 0xbc, 0x46, 0xd9, 0x65, 0xfa, 0x8c, 0x13, 0xaf, 0x30, 0xca, 0x55, 0xe9, 0x76, 341 | 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x11, 0x1e, 0x1b, 0x28, 0x2d, 0x22, 0x27, 0x3c, 0x39, 0x36, 0x33, 342 | 0x00, 0xa0, 0x5d, 0xfd, 0xba, 0x1a, 0xe7, 0x47, 0x69, 0xc9, 0x34, 0x94, 0xd3, 0x73, 0x8e, 0x2e, 343 | 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04, 0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda, 344 | 0x00, 0xa1, 0x5f, 0xfe, 0xbe, 0x1f, 0xe1, 0x40, 0x61, 0xc0, 0x3e, 0x9f, 0xdf, 0x7e, 0x80, 0x21, 345 | 0x00, 0xc2, 0x99, 0x5b, 0x2f, 0xed, 0xb6, 0x74, 0x5e, 0x9c, 0xc7, 0x05, 0x71, 0xb3, 0xe8, 0x2a, 346 | 0x00, 0xa2, 0x59, 0xfb, 0xb2, 0x10, 0xeb, 0x49, 0x79, 0xdb, 0x20, 0x82, 0xcb, 0x69, 0x92, 0x30, 347 | 0x00, 0xf2, 0xf9, 0x0b, 0xef, 0x1d, 0x16, 0xe4, 0xc3, 0x31, 0x3a, 0xc8, 0x2c, 0xde, 0xd5, 0x27, 348 | 0x00, 0xa3, 0x5b, 0xf8, 0xb6, 0x15, 0xed, 0x4e, 0x71, 0xd2, 0x2a, 0x89, 0xc7, 0x64, 0x9c, 0x3f, 349 | 0x00, 0xe2, 0xd9, 0x3b, 0xaf, 0x4d, 0x76, 0x94, 0x43, 0xa1, 0x9a, 0x78, 0xec, 0x0e, 0x35, 0xd7, 350 | 0x00, 0xa4, 0x55, 0xf1, 0xaa, 0x0e, 0xff, 0x5b, 0x49, 0xed, 0x1c, 0xb8, 0xe3, 0x47, 0xb6, 0x12, 351 | 0x00, 0x92, 0x39, 0xab, 0x72, 0xe0, 0x4b, 0xd9, 0xe4, 0x76, 0xdd, 0x4f, 0x96, 0x04, 0xaf, 0x3d, 352 | 0x00, 0xa5, 0x57, 0xf2, 0xae, 0x0b, 0xf9, 0x5c, 0x41, 0xe4, 0x16, 0xb3, 0xef, 0x4a, 0xb8, 0x1d, 353 | 0x00, 0x82, 0x19, 0x9b, 0x32, 0xb0, 0x2b, 0xa9, 0x64, 0xe6, 0x7d, 0xff, 0x56, 0xd4, 0x4f, 0xcd, 354 | 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55, 0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c, 355 | 0x00, 0xb2, 0x79, 0xcb, 0xf2, 0x40, 0x8b, 0x39, 0xf9, 0x4b, 0x80, 0x32, 0x0b, 0xb9, 0x72, 0xc0, 356 | 0x00, 0xa7, 0x53, 0xf4, 0xa6, 0x01, 0xf5, 0x52, 0x51, 0xf6, 0x02, 0xa5, 0xf7, 0x50, 0xa4, 0x03, 357 | 0x00, 0xa2, 0x59, 0xfb, 0xb2, 0x10, 0xeb, 0x49, 0x79, 0xdb, 0x20, 0x82, 0xcb, 0x69, 0x92, 0x30, 358 | 0x00, 0xa8, 0x4d, 0xe5, 0x9a, 0x32, 0xd7, 0x7f, 0x29, 0x81, 0x64, 0xcc, 0xb3, 0x1b, 0xfe, 0x56, 359 | 0x00, 0x52, 0xa4, 0xf6, 0x55, 0x07, 0xf1, 0xa3, 0xaa, 0xf8, 0x0e, 0x5c, 0xff, 0xad, 0x5b, 0x09, 360 | 0x00, 0xa9, 0x4f, 0xe6, 0x9e, 0x37, 0xd1, 0x78, 0x21, 0x88, 0x6e, 0xc7, 0xbf, 0x16, 0xf0, 0x59, 361 | 0x00, 0x42, 0x84, 0xc6, 0x15, 0x57, 0x91, 0xd3, 0x2a, 0x68, 0xae, 0xec, 0x3f, 0x7d, 0xbb, 0xf9, 362 | 0x00, 0xaa, 0x49, 0xe3, 0x92, 0x38, 0xdb, 0x71, 0x39, 0x93, 0x70, 0xda, 0xab, 0x01, 0xe2, 0x48, 363 | 0x00, 0x72, 0xe4, 0x96, 0xd5, 0xa7, 0x31, 0x43, 0xb7, 0xc5, 0x53, 0x21, 0x62, 0x10, 0x86, 0xf4, 364 | 0x00, 0xab, 0x4b, 0xe0, 0x96, 0x3d, 0xdd, 0x76, 0x31, 0x9a, 0x7a, 0xd1, 0xa7, 0x0c, 0xec, 0x47, 365 | 0x00, 0x62, 0xc4, 0xa6, 0x95, 0xf7, 0x51, 0x33, 0x37, 0x55, 0xf3, 0x91, 0xa2, 0xc0, 0x66, 0x04, 366 | 0x00, 0xac, 0x45, 0xe9, 0x8a, 0x26, 0xcf, 0x63, 0x09, 0xa5, 0x4c, 0xe0, 0x83, 0x2f, 0xc6, 0x6a, 367 | 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, 368 | 0x00, 0xad, 0x47, 0xea, 0x8e, 0x23, 0xc9, 0x64, 0x01, 0xac, 0x46, 0xeb, 0x8f, 0x22, 0xc8, 0x65, 369 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 370 | 0x00, 0xae, 0x41, 0xef, 0x82, 0x2c, 0xc3, 0x6d, 0x19, 0xb7, 0x58, 0xf6, 0x9b, 0x35, 0xda, 0x74, 371 | 0x00, 0x32, 0x64, 0x56, 0xc8, 0xfa, 0xac, 0x9e, 0x8d, 0xbf, 0xe9, 0xdb, 0x45, 0x77, 0x21, 0x13, 372 | 0x00, 0xaf, 0x43, 0xec, 0x86, 0x29, 0xc5, 0x6a, 0x11, 0xbe, 0x52, 0xfd, 0x97, 0x38, 0xd4, 0x7b, 373 | 0x00, 0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x0d, 0x2f, 0x49, 0x6b, 0x85, 0xa7, 0xc1, 0xe3, 374 | 0x00, 0xb0, 0x7d, 0xcd, 0xfa, 0x4a, 0x87, 0x37, 0xe9, 0x59, 0x94, 0x24, 0x13, 0xa3, 0x6e, 0xde, 375 | 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57, 0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61, 376 | 0x00, 0xb1, 0x7f, 0xce, 0xfe, 0x4f, 0x81, 0x30, 0xe1, 0x50, 0x9e, 0x2f, 0x1f, 0xae, 0x60, 0xd1, 377 | 0x00, 0xdf, 0xa3, 0x7c, 0x5b, 0x84, 0xf8, 0x27, 0xb6, 0x69, 0x15, 0xca, 0xed, 0x32, 0x4e, 0x91, 378 | 0x00, 0xb2, 0x79, 0xcb, 0xf2, 0x40, 0x8b, 0x39, 0xf9, 0x4b, 0x80, 0x32, 0x0b, 0xb9, 0x72, 0xc0, 379 | 0x00, 0xef, 0xc3, 0x2c, 0x9b, 0x74, 0x58, 0xb7, 0x2b, 0xc4, 0xe8, 0x07, 0xb0, 0x5f, 0x73, 0x9c, 380 | 0x00, 0xb3, 0x7b, 0xc8, 0xf6, 0x45, 0x8d, 0x3e, 0xf1, 0x42, 0x8a, 0x39, 0x07, 0xb4, 0x7c, 0xcf, 381 | 0x00, 0xff, 0xe3, 0x1c, 0xdb, 0x24, 0x38, 0xc7, 0xab, 0x54, 0x48, 0xb7, 0x70, 0x8f, 0x93, 0x6c, 382 | 0x00, 0xb4, 0x75, 0xc1, 0xea, 0x5e, 0x9f, 0x2b, 0xc9, 0x7d, 0xbc, 0x08, 0x23, 0x97, 0x56, 0xe2, 383 | 0x00, 0x8f, 0x03, 0x8c, 0x06, 0x89, 0x05, 0x8a, 0x0c, 0x83, 0x0f, 0x80, 0x0a, 0x85, 0x09, 0x86, 384 | 0x00, 0xb5, 0x77, 0xc2, 0xee, 0x5b, 0x99, 0x2c, 0xc1, 0x74, 0xb6, 0x03, 0x2f, 0x9a, 0x58, 0xed, 385 | 0x00, 0x9f, 0x23, 0xbc, 0x46, 0xd9, 0x65, 0xfa, 0x8c, 0x13, 0xaf, 0x30, 0xca, 0x55, 0xe9, 0x76, 386 | 0x00, 0xb6, 0x71, 0xc7, 0xe2, 0x54, 0x93, 0x25, 0xd9, 0x6f, 0xa8, 0x1e, 0x3b, 0x8d, 0x4a, 0xfc, 387 | 0x00, 0xaf, 0x43, 0xec, 0x86, 0x29, 0xc5, 0x6a, 0x11, 0xbe, 0x52, 0xfd, 0x97, 0x38, 0xd4, 0x7b, 388 | 0x00, 0xb7, 0x73, 0xc4, 0xe6, 0x51, 0x95, 0x22, 0xd1, 0x66, 0xa2, 0x15, 0x37, 0x80, 0x44, 0xf3, 389 | 0x00, 0xbf, 0x63, 0xdc, 0xc6, 0x79, 0xa5, 0x1a, 0x91, 0x2e, 0xf2, 0x4d, 0x57, 0xe8, 0x34, 0x8b, 390 | 0x00, 0xb8, 0x6d, 0xd5, 0xda, 0x62, 0xb7, 0x0f, 0xa9, 0x11, 0xc4, 0x7c, 0x73, 0xcb, 0x1e, 0xa6, 391 | 0x00, 0x4f, 0x9e, 0xd1, 0x21, 0x6e, 0xbf, 0xf0, 0x42, 0x0d, 0xdc, 0x93, 0x63, 0x2c, 0xfd, 0xb2, 392 | 0x00, 0xb9, 0x6f, 0xd6, 0xde, 0x67, 0xb1, 0x08, 0xa1, 0x18, 0xce, 0x77, 0x7f, 0xc6, 0x10, 0xa9, 393 | 0x00, 0x5f, 0xbe, 0xe1, 0x61, 0x3e, 0xdf, 0x80, 0xc2, 0x9d, 0x7c, 0x23, 0xa3, 0xfc, 0x1d, 0x42, 394 | 0x00, 0xba, 0x69, 0xd3, 0xd2, 0x68, 0xbb, 0x01, 0xb9, 0x03, 0xd0, 0x6a, 0x6b, 0xd1, 0x02, 0xb8, 395 | 0x00, 0x6f, 0xde, 0xb1, 0xa1, 0xce, 0x7f, 0x10, 0x5f, 0x30, 0x81, 0xee, 0xfe, 0x91, 0x20, 0x4f, 396 | 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06, 0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7, 397 | 0x00, 0x7f, 0xfe, 0x81, 0xe1, 0x9e, 0x1f, 0x60, 0xdf, 0xa0, 0x21, 0x5e, 0x3e, 0x41, 0xc0, 0xbf, 398 | 0x00, 0xbc, 0x65, 0xd9, 0xca, 0x76, 0xaf, 0x13, 0x89, 0x35, 0xec, 0x50, 0x43, 0xff, 0x26, 0x9a, 399 | 0x00, 0x0f, 0x1e, 0x11, 0x3c, 0x33, 0x22, 0x2d, 0x78, 0x77, 0x66, 0x69, 0x44, 0x4b, 0x5a, 0x55, 400 | 0x00, 0xbd, 0x67, 0xda, 0xce, 0x73, 0xa9, 0x14, 0x81, 0x3c, 0xe6, 0x5b, 0x4f, 0xf2, 0x28, 0x95, 401 | 0x00, 0x1f, 0x3e, 0x21, 0x7c, 0x63, 0x42, 0x5d, 0xf8, 0xe7, 0xc6, 0xd9, 0x84, 0x9b, 0xba, 0xa5, 402 | 0x00, 0xbe, 0x61, 0xdf, 0xc2, 0x7c, 0xa3, 0x1d, 0x99, 0x27, 0xf8, 0x46, 0x5b, 0xe5, 0x3a, 0x84, 403 | 0x00, 0x2f, 0x5e, 0x71, 0xbc, 0x93, 0xe2, 0xcd, 0x65, 0x4a, 0x3b, 0x14, 0xd9, 0xf6, 0x87, 0xa8, 404 | 0x00, 0xbf, 0x63, 0xdc, 0xc6, 0x79, 0xa5, 0x1a, 0x91, 0x2e, 0xf2, 0x4d, 0x57, 0xe8, 0x34, 0x8b, 405 | 0x00, 0x3f, 0x7e, 0x41, 0xfc, 0xc3, 0x82, 0xbd, 0xe5, 0xda, 0x9b, 0xa4, 0x19, 0x26, 0x67, 0x58, 406 | 0x00, 0xc0, 0x9d, 0x5d, 0x27, 0xe7, 0xba, 0x7a, 0x4e, 0x8e, 0xd3, 0x13, 0x69, 0xa9, 0xf4, 0x34, 407 | 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3, 0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67, 408 | 0x00, 0xc1, 0x9f, 0x5e, 0x23, 0xe2, 0xbc, 0x7d, 0x46, 0x87, 0xd9, 0x18, 0x65, 0xa4, 0xfa, 0x3b, 409 | 0x00, 0x8c, 0x05, 0x89, 0x0a, 0x86, 0x0f, 0x83, 0x14, 0x98, 0x11, 0x9d, 0x1e, 0x92, 0x1b, 0x97, 410 | 0x00, 0xc2, 0x99, 0x5b, 0x2f, 0xed, 0xb6, 0x74, 0x5e, 0x9c, 0xc7, 0x05, 0x71, 0xb3, 0xe8, 0x2a, 411 | 0x00, 0xbc, 0x65, 0xd9, 0xca, 0x76, 0xaf, 0x13, 0x89, 0x35, 0xec, 0x50, 0x43, 0xff, 0x26, 0x9a, 412 | 0x00, 0xc3, 0x9b, 0x58, 0x2b, 0xe8, 0xb0, 0x73, 0x56, 0x95, 0xcd, 0x0e, 0x7d, 0xbe, 0xe6, 0x25, 413 | 0x00, 0xac, 0x45, 0xe9, 0x8a, 0x26, 0xcf, 0x63, 0x09, 0xa5, 0x4c, 0xe0, 0x83, 0x2f, 0xc6, 0x6a, 414 | 0x00, 0xc4, 0x95, 0x51, 0x37, 0xf3, 0xa2, 0x66, 0x6e, 0xaa, 0xfb, 0x3f, 0x59, 0x9d, 0xcc, 0x08, 415 | 0x00, 0xdc, 0xa5, 0x79, 0x57, 0x8b, 0xf2, 0x2e, 0xae, 0x72, 0x0b, 0xd7, 0xf9, 0x25, 0x5c, 0x80, 416 | 0x00, 0xc5, 0x97, 0x52, 0x33, 0xf6, 0xa4, 0x61, 0x66, 0xa3, 0xf1, 0x34, 0x55, 0x90, 0xc2, 0x07, 417 | 0x00, 0xcc, 0x85, 0x49, 0x17, 0xdb, 0x92, 0x5e, 0x2e, 0xe2, 0xab, 0x67, 0x39, 0xf5, 0xbc, 0x70, 418 | 0x00, 0xc6, 0x91, 0x57, 0x3f, 0xf9, 0xae, 0x68, 0x7e, 0xb8, 0xef, 0x29, 0x41, 0x87, 0xd0, 0x16, 419 | 0x00, 0xfc, 0xe5, 0x19, 0xd7, 0x2b, 0x32, 0xce, 0xb3, 0x4f, 0x56, 0xaa, 0x64, 0x98, 0x81, 0x7d, 420 | 0x00, 0xc7, 0x93, 0x54, 0x3b, 0xfc, 0xa8, 0x6f, 0x76, 0xb1, 0xe5, 0x22, 0x4d, 0x8a, 0xde, 0x19, 421 | 0x00, 0xec, 0xc5, 0x29, 0x97, 0x7b, 0x52, 0xbe, 0x33, 0xdf, 0xf6, 0x1a, 0xa4, 0x48, 0x61, 0x8d, 422 | 0x00, 0xc8, 0x8d, 0x45, 0x07, 0xcf, 0x8a, 0x42, 0x0e, 0xc6, 0x83, 0x4b, 0x09, 0xc1, 0x84, 0x4c, 423 | 0x00, 0x1c, 0x38, 0x24, 0x70, 0x6c, 0x48, 0x54, 0xe0, 0xfc, 0xd8, 0xc4, 0x90, 0x8c, 0xa8, 0xb4, 424 | 0x00, 0xc9, 0x8f, 0x46, 0x03, 0xca, 0x8c, 0x45, 0x06, 0xcf, 0x89, 0x40, 0x05, 0xcc, 0x8a, 0x43, 425 | 0x00, 0x0c, 0x18, 0x14, 0x30, 0x3c, 0x28, 0x24, 0x60, 0x6c, 0x78, 0x74, 0x50, 0x5c, 0x48, 0x44, 426 | 0x00, 0xca, 0x89, 0x43, 0x0f, 0xc5, 0x86, 0x4c, 0x1e, 0xd4, 0x97, 0x5d, 0x11, 0xdb, 0x98, 0x52, 427 | 0x00, 0x3c, 0x78, 0x44, 0xf0, 0xcc, 0x88, 0xb4, 0xfd, 0xc1, 0x85, 0xb9, 0x0d, 0x31, 0x75, 0x49, 428 | 0x00, 0xcb, 0x8b, 0x40, 0x0b, 0xc0, 0x80, 0x4b, 0x16, 0xdd, 0x9d, 0x56, 0x1d, 0xd6, 0x96, 0x5d, 429 | 0x00, 0x2c, 0x58, 0x74, 0xb0, 0x9c, 0xe8, 0xc4, 0x7d, 0x51, 0x25, 0x09, 0xcd, 0xe1, 0x95, 0xb9, 430 | 0x00, 0xcc, 0x85, 0x49, 0x17, 0xdb, 0x92, 0x5e, 0x2e, 0xe2, 0xab, 0x67, 0x39, 0xf5, 0xbc, 0x70, 431 | 0x00, 0x5c, 0xb8, 0xe4, 0x6d, 0x31, 0xd5, 0x89, 0xda, 0x86, 0x62, 0x3e, 0xb7, 0xeb, 0x0f, 0x53, 432 | 0x00, 0xcd, 0x87, 0x4a, 0x13, 0xde, 0x94, 0x59, 0x26, 0xeb, 0xa1, 0x6c, 0x35, 0xf8, 0xb2, 0x7f, 433 | 0x00, 0x4c, 0x98, 0xd4, 0x2d, 0x61, 0xb5, 0xf9, 0x5a, 0x16, 0xc2, 0x8e, 0x77, 0x3b, 0xef, 0xa3, 434 | 0x00, 0xce, 0x81, 0x4f, 0x1f, 0xd1, 0x9e, 0x50, 0x3e, 0xf0, 0xbf, 0x71, 0x21, 0xef, 0xa0, 0x6e, 435 | 0x00, 0x7c, 0xf8, 0x84, 0xed, 0x91, 0x15, 0x69, 0xc7, 0xbb, 0x3f, 0x43, 0x2a, 0x56, 0xd2, 0xae, 436 | 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57, 0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61, 437 | 0x00, 0x6c, 0xd8, 0xb4, 0xad, 0xc1, 0x75, 0x19, 0x47, 0x2b, 0x9f, 0xf3, 0xea, 0x86, 0x32, 0x5e, 438 | 0x00, 0xd0, 0xbd, 0x6d, 0x67, 0xb7, 0xda, 0x0a, 0xce, 0x1e, 0x73, 0xa3, 0xa9, 0x79, 0x14, 0xc4, 439 | 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0, 0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc, 440 | 0x00, 0xd1, 0xbf, 0x6e, 0x63, 0xb2, 0xdc, 0x0d, 0xc6, 0x17, 0x79, 0xa8, 0xa5, 0x74, 0x1a, 0xcb, 441 | 0x00, 0x91, 0x3f, 0xae, 0x7e, 0xef, 0x41, 0xd0, 0xfc, 0x6d, 0xc3, 0x52, 0x82, 0x13, 0xbd, 0x2c, 442 | 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04, 0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda, 443 | 0x00, 0xa1, 0x5f, 0xfe, 0xbe, 0x1f, 0xe1, 0x40, 0x61, 0xc0, 0x3e, 0x9f, 0xdf, 0x7e, 0x80, 0x21, 444 | 0x00, 0xd3, 0xbb, 0x68, 0x6b, 0xb8, 0xd0, 0x03, 0xd6, 0x05, 0x6d, 0xbe, 0xbd, 0x6e, 0x06, 0xd5, 445 | 0x00, 0xb1, 0x7f, 0xce, 0xfe, 0x4f, 0x81, 0x30, 0xe1, 0x50, 0x9e, 0x2f, 0x1f, 0xae, 0x60, 0xd1, 446 | 0x00, 0xd4, 0xb5, 0x61, 0x77, 0xa3, 0xc2, 0x16, 0xee, 0x3a, 0x5b, 0x8f, 0x99, 0x4d, 0x2c, 0xf8, 447 | 0x00, 0xc1, 0x9f, 0x5e, 0x23, 0xe2, 0xbc, 0x7d, 0x46, 0x87, 0xd9, 0x18, 0x65, 0xa4, 0xfa, 0x3b, 448 | 0x00, 0xd5, 0xb7, 0x62, 0x73, 0xa6, 0xc4, 0x11, 0xe6, 0x33, 0x51, 0x84, 0x95, 0x40, 0x22, 0xf7, 449 | 0x00, 0xd1, 0xbf, 0x6e, 0x63, 0xb2, 0xdc, 0x0d, 0xc6, 0x17, 0x79, 0xa8, 0xa5, 0x74, 0x1a, 0xcb, 450 | 0x00, 0xd6, 0xb1, 0x67, 0x7f, 0xa9, 0xce, 0x18, 0xfe, 0x28, 0x4f, 0x99, 0x81, 0x57, 0x30, 0xe6, 451 | 0x00, 0xe1, 0xdf, 0x3e, 0xa3, 0x42, 0x7c, 0x9d, 0x5b, 0xba, 0x84, 0x65, 0xf8, 0x19, 0x27, 0xc6, 452 | 0x00, 0xd7, 0xb3, 0x64, 0x7b, 0xac, 0xc8, 0x1f, 0xf6, 0x21, 0x45, 0x92, 0x8d, 0x5a, 0x3e, 0xe9, 453 | 0x00, 0xf1, 0xff, 0x0e, 0xe3, 0x12, 0x1c, 0xed, 0xdb, 0x2a, 0x24, 0xd5, 0x38, 0xc9, 0xc7, 0x36, 454 | 0x00, 0xd8, 0xad, 0x75, 0x47, 0x9f, 0xea, 0x32, 0x8e, 0x56, 0x23, 0xfb, 0xc9, 0x11, 0x64, 0xbc, 455 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 456 | 0x00, 0xd9, 0xaf, 0x76, 0x43, 0x9a, 0xec, 0x35, 0x86, 0x5f, 0x29, 0xf0, 0xc5, 0x1c, 0x6a, 0xb3, 457 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 458 | 0x00, 0xda, 0xa9, 0x73, 0x4f, 0x95, 0xe6, 0x3c, 0x9e, 0x44, 0x37, 0xed, 0xd1, 0x0b, 0x78, 0xa2, 459 | 0x00, 0x21, 0x42, 0x63, 0x84, 0xa5, 0xc6, 0xe7, 0x15, 0x34, 0x57, 0x76, 0x91, 0xb0, 0xd3, 0xf2, 460 | 0x00, 0xdb, 0xab, 0x70, 0x4b, 0x90, 0xe0, 0x3b, 0x96, 0x4d, 0x3d, 0xe6, 0xdd, 0x06, 0x76, 0xad, 461 | 0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0x95, 0xa4, 0xf7, 0xc6, 0x51, 0x60, 0x33, 0x02, 462 | 0x00, 0xdc, 0xa5, 0x79, 0x57, 0x8b, 0xf2, 0x2e, 0xae, 0x72, 0x0b, 0xd7, 0xf9, 0x25, 0x5c, 0x80, 463 | 0x00, 0x41, 0x82, 0xc3, 0x19, 0x58, 0x9b, 0xda, 0x32, 0x73, 0xb0, 0xf1, 0x2b, 0x6a, 0xa9, 0xe8, 464 | 0x00, 0xdd, 0xa7, 0x7a, 0x53, 0x8e, 0xf4, 0x29, 0xa6, 0x7b, 0x01, 0xdc, 0xf5, 0x28, 0x52, 0x8f, 465 | 0x00, 0x51, 0xa2, 0xf3, 0x59, 0x08, 0xfb, 0xaa, 0xb2, 0xe3, 0x10, 0x41, 0xeb, 0xba, 0x49, 0x18, 466 | 0x00, 0xde, 0xa1, 0x7f, 0x5f, 0x81, 0xfe, 0x20, 0xbe, 0x60, 0x1f, 0xc1, 0xe1, 0x3f, 0x40, 0x9e, 467 | 0x00, 0x61, 0xc2, 0xa3, 0x99, 0xf8, 0x5b, 0x3a, 0x2f, 0x4e, 0xed, 0x8c, 0xb6, 0xd7, 0x74, 0x15, 468 | 0x00, 0xdf, 0xa3, 0x7c, 0x5b, 0x84, 0xf8, 0x27, 0xb6, 0x69, 0x15, 0xca, 0xed, 0x32, 0x4e, 0x91, 469 | 0x00, 0x71, 0xe2, 0x93, 0xd9, 0xa8, 0x3b, 0x4a, 0xaf, 0xde, 0x4d, 0x3c, 0x76, 0x07, 0x94, 0xe5, 470 | 0x00, 0xe0, 0xdd, 0x3d, 0xa7, 0x47, 0x7a, 0x9a, 0x53, 0xb3, 0x8e, 0x6e, 0xf4, 0x14, 0x29, 0xc9, 471 | 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55, 0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c, 472 | 0x00, 0xe1, 0xdf, 0x3e, 0xa3, 0x42, 0x7c, 0x9d, 0x5b, 0xba, 0x84, 0x65, 0xf8, 0x19, 0x27, 0xc6, 473 | 0x00, 0xb6, 0x71, 0xc7, 0xe2, 0x54, 0x93, 0x25, 0xd9, 0x6f, 0xa8, 0x1e, 0x3b, 0x8d, 0x4a, 0xfc, 474 | 0x00, 0xe2, 0xd9, 0x3b, 0xaf, 0x4d, 0x76, 0x94, 0x43, 0xa1, 0x9a, 0x78, 0xec, 0x0e, 0x35, 0xd7, 475 | 0x00, 0x86, 0x11, 0x97, 0x22, 0xa4, 0x33, 0xb5, 0x44, 0xc2, 0x55, 0xd3, 0x66, 0xe0, 0x77, 0xf1, 476 | 0x00, 0xe3, 0xdb, 0x38, 0xab, 0x48, 0x70, 0x93, 0x4b, 0xa8, 0x90, 0x73, 0xe0, 0x03, 0x3b, 0xd8, 477 | 0x00, 0x96, 0x31, 0xa7, 0x62, 0xf4, 0x53, 0xc5, 0xc4, 0x52, 0xf5, 0x63, 0xa6, 0x30, 0x97, 0x01, 478 | 0x00, 0xe4, 0xd5, 0x31, 0xb7, 0x53, 0x62, 0x86, 0x73, 0x97, 0xa6, 0x42, 0xc4, 0x20, 0x11, 0xf5, 479 | 0x00, 0xe6, 0xd1, 0x37, 0xbf, 0x59, 0x6e, 0x88, 0x63, 0x85, 0xb2, 0x54, 0xdc, 0x3a, 0x0d, 0xeb, 480 | 0x00, 0xe5, 0xd7, 0x32, 0xb3, 0x56, 0x64, 0x81, 0x7b, 0x9e, 0xac, 0x49, 0xc8, 0x2d, 0x1f, 0xfa, 481 | 0x00, 0xf6, 0xf1, 0x07, 0xff, 0x09, 0x0e, 0xf8, 0xe3, 0x15, 0x12, 0xe4, 0x1c, 0xea, 0xed, 0x1b, 482 | 0x00, 0xe6, 0xd1, 0x37, 0xbf, 0x59, 0x6e, 0x88, 0x63, 0x85, 0xb2, 0x54, 0xdc, 0x3a, 0x0d, 0xeb, 483 | 0x00, 0xc6, 0x91, 0x57, 0x3f, 0xf9, 0xae, 0x68, 0x7e, 0xb8, 0xef, 0x29, 0x41, 0x87, 0xd0, 0x16, 484 | 0x00, 0xe7, 0xd3, 0x34, 0xbb, 0x5c, 0x68, 0x8f, 0x6b, 0x8c, 0xb8, 0x5f, 0xd0, 0x37, 0x03, 0xe4, 485 | 0x00, 0xd6, 0xb1, 0x67, 0x7f, 0xa9, 0xce, 0x18, 0xfe, 0x28, 0x4f, 0x99, 0x81, 0x57, 0x30, 0xe6, 486 | 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2, 0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1, 487 | 0x00, 0x26, 0x4c, 0x6a, 0x98, 0xbe, 0xd4, 0xf2, 0x2d, 0x0b, 0x61, 0x47, 0xb5, 0x93, 0xf9, 0xdf, 488 | 0x00, 0xe9, 0xcf, 0x26, 0x83, 0x6a, 0x4c, 0xa5, 0x1b, 0xf2, 0xd4, 0x3d, 0x98, 0x71, 0x57, 0xbe, 489 | 0x00, 0x36, 0x6c, 0x5a, 0xd8, 0xee, 0xb4, 0x82, 0xad, 0x9b, 0xc1, 0xf7, 0x75, 0x43, 0x19, 0x2f, 490 | 0x00, 0xea, 0xc9, 0x23, 0x8f, 0x65, 0x46, 0xac, 0x03, 0xe9, 0xca, 0x20, 0x8c, 0x66, 0x45, 0xaf, 491 | 0x00, 0x06, 0x0c, 0x0a, 0x18, 0x1e, 0x14, 0x12, 0x30, 0x36, 0x3c, 0x3a, 0x28, 0x2e, 0x24, 0x22, 492 | 0x00, 0xeb, 0xcb, 0x20, 0x8b, 0x60, 0x40, 0xab, 0x0b, 0xe0, 0xc0, 0x2b, 0x80, 0x6b, 0x4b, 0xa0, 493 | 0x00, 0x16, 0x2c, 0x3a, 0x58, 0x4e, 0x74, 0x62, 0xb0, 0xa6, 0x9c, 0x8a, 0xe8, 0xfe, 0xc4, 0xd2, 494 | 0x00, 0xec, 0xc5, 0x29, 0x97, 0x7b, 0x52, 0xbe, 0x33, 0xdf, 0xf6, 0x1a, 0xa4, 0x48, 0x61, 0x8d, 495 | 0x00, 0x66, 0xcc, 0xaa, 0x85, 0xe3, 0x49, 0x2f, 0x17, 0x71, 0xdb, 0xbd, 0x92, 0xf4, 0x5e, 0x38, 496 | 0x00, 0xed, 0xc7, 0x2a, 0x93, 0x7e, 0x54, 0xb9, 0x3b, 0xd6, 0xfc, 0x11, 0xa8, 0x45, 0x6f, 0x82, 497 | 0x00, 0x76, 0xec, 0x9a, 0xc5, 0xb3, 0x29, 0x5f, 0x97, 0xe1, 0x7b, 0x0d, 0x52, 0x24, 0xbe, 0xc8, 498 | 0x00, 0xee, 0xc1, 0x2f, 0x9f, 0x71, 0x5e, 0xb0, 0x23, 0xcd, 0xe2, 0x0c, 0xbc, 0x52, 0x7d, 0x93, 499 | 0x00, 0x46, 0x8c, 0xca, 0x05, 0x43, 0x89, 0xcf, 0x0a, 0x4c, 0x86, 0xc0, 0x0f, 0x49, 0x83, 0xc5, 500 | 0x00, 0xef, 0xc3, 0x2c, 0x9b, 0x74, 0x58, 0xb7, 0x2b, 0xc4, 0xe8, 0x07, 0xb0, 0x5f, 0x73, 0x9c, 501 | 0x00, 0x56, 0xac, 0xfa, 0x45, 0x13, 0xe9, 0xbf, 0x8a, 0xdc, 0x26, 0x70, 0xcf, 0x99, 0x63, 0x35, 502 | 0x00, 0xf0, 0xfd, 0x0d, 0xe7, 0x17, 0x1a, 0xea, 0xd3, 0x23, 0x2e, 0xde, 0x34, 0xc4, 0xc9, 0x39, 503 | 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06, 0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7, 504 | 0x00, 0xf1, 0xff, 0x0e, 0xe3, 0x12, 0x1c, 0xed, 0xdb, 0x2a, 0x24, 0xd5, 0x38, 0xc9, 0xc7, 0x36, 505 | 0x00, 0xab, 0x4b, 0xe0, 0x96, 0x3d, 0xdd, 0x76, 0x31, 0x9a, 0x7a, 0xd1, 0xa7, 0x0c, 0xec, 0x47, 506 | 0x00, 0xf2, 0xf9, 0x0b, 0xef, 0x1d, 0x16, 0xe4, 0xc3, 0x31, 0x3a, 0xc8, 0x2c, 0xde, 0xd5, 0x27, 507 | 0x00, 0x9b, 0x2b, 0xb0, 0x56, 0xcd, 0x7d, 0xe6, 0xac, 0x37, 0x87, 0x1c, 0xfa, 0x61, 0xd1, 0x4a, 508 | 0x00, 0xf3, 0xfb, 0x08, 0xeb, 0x18, 0x10, 0xe3, 0xcb, 0x38, 0x30, 0xc3, 0x20, 0xd3, 0xdb, 0x28, 509 | 0x00, 0x8b, 0x0b, 0x80, 0x16, 0x9d, 0x1d, 0x96, 0x2c, 0xa7, 0x27, 0xac, 0x3a, 0xb1, 0x31, 0xba, 510 | 0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05, 511 | 0x00, 0xfb, 0xeb, 0x10, 0xcb, 0x30, 0x20, 0xdb, 0x8b, 0x70, 0x60, 0x9b, 0x40, 0xbb, 0xab, 0x50, 512 | 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1, 0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a, 513 | 0x00, 0xeb, 0xcb, 0x20, 0x8b, 0x60, 0x40, 0xab, 0x0b, 0xe0, 0xc0, 0x2b, 0x80, 0x6b, 0x4b, 0xa0, 514 | 0x00, 0xf6, 0xf1, 0x07, 0xff, 0x09, 0x0e, 0xf8, 0xe3, 0x15, 0x12, 0xe4, 0x1c, 0xea, 0xed, 0x1b, 515 | 0x00, 0xdb, 0xab, 0x70, 0x4b, 0x90, 0xe0, 0x3b, 0x96, 0x4d, 0x3d, 0xe6, 0xdd, 0x06, 0x76, 0xad, 516 | 0x00, 0xf7, 0xf3, 0x04, 0xfb, 0x0c, 0x08, 0xff, 0xeb, 0x1c, 0x18, 0xef, 0x10, 0xe7, 0xe3, 0x14, 517 | 0x00, 0xcb, 0x8b, 0x40, 0x0b, 0xc0, 0x80, 0x4b, 0x16, 0xdd, 0x9d, 0x56, 0x1d, 0xd6, 0x96, 0x5d, 518 | 0x00, 0xf8, 0xed, 0x15, 0xc7, 0x3f, 0x2a, 0xd2, 0x93, 0x6b, 0x7e, 0x86, 0x54, 0xac, 0xb9, 0x41, 519 | 0x00, 0x3b, 0x76, 0x4d, 0xec, 0xd7, 0x9a, 0xa1, 0xc5, 0xfe, 0xb3, 0x88, 0x29, 0x12, 0x5f, 0x64, 520 | 0x00, 0xf9, 0xef, 0x16, 0xc3, 0x3a, 0x2c, 0xd5, 0x9b, 0x62, 0x74, 0x8d, 0x58, 0xa1, 0xb7, 0x4e, 521 | 0x00, 0x2b, 0x56, 0x7d, 0xac, 0x87, 0xfa, 0xd1, 0x45, 0x6e, 0x13, 0x38, 0xe9, 0xc2, 0xbf, 0x94, 522 | 0x00, 0xfa, 0xe9, 0x13, 0xcf, 0x35, 0x26, 0xdc, 0x83, 0x79, 0x6a, 0x90, 0x4c, 0xb6, 0xa5, 0x5f, 523 | 0x00, 0x1b, 0x36, 0x2d, 0x6c, 0x77, 0x5a, 0x41, 0xd8, 0xc3, 0xee, 0xf5, 0xb4, 0xaf, 0x82, 0x99, 524 | 0x00, 0xfb, 0xeb, 0x10, 0xcb, 0x30, 0x20, 0xdb, 0x8b, 0x70, 0x60, 0x9b, 0x40, 0xbb, 0xab, 0x50, 525 | 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 526 | 0x00, 0xfc, 0xe5, 0x19, 0xd7, 0x2b, 0x32, 0xce, 0xb3, 0x4f, 0x56, 0xaa, 0x64, 0x98, 0x81, 0x7d, 527 | 0x00, 0x7b, 0xf6, 0x8d, 0xf1, 0x8a, 0x07, 0x7c, 0xff, 0x84, 0x09, 0x72, 0x0e, 0x75, 0xf8, 0x83, 528 | 0x00, 0xfd, 0xe7, 0x1a, 0xd3, 0x2e, 0x34, 0xc9, 0xbb, 0x46, 0x5c, 0xa1, 0x68, 0x95, 0x8f, 0x72, 529 | 0x00, 0x6b, 0xd6, 0xbd, 0xb1, 0xda, 0x67, 0x0c, 0x7f, 0x14, 0xa9, 0xc2, 0xce, 0xa5, 0x18, 0x73, 530 | 0x00, 0xfe, 0xe1, 0x1f, 0xdf, 0x21, 0x3e, 0xc0, 0xa3, 0x5d, 0x42, 0xbc, 0x7c, 0x82, 0x9d, 0x63, 531 | 0x00, 0x5b, 0xb6, 0xed, 0x71, 0x2a, 0xc7, 0x9c, 0xe2, 0xb9, 0x54, 0x0f, 0x93, 0xc8, 0x25, 0x7e, 532 | 0x00, 0xff, 0xe3, 0x1c, 0xdb, 0x24, 0x38, 0xc7, 0xab, 0x54, 0x48, 0xb7, 0x70, 0x8f, 0x93, 0x6c, 533 | 0x00, 0x4b, 0x96, 0xdd, 0x31, 0x7a, 0xa7, 0xec, 0x62, 0x29, 0xf4, 0xbf, 0x53, 0x18, 0xc5, 0x8e }; 534 | 535 | } 536 | 537 | size_t addmul_ssse3(uint8_t z[], const uint8_t x[], uint8_t y, size_t size) 538 | { 539 | const __m128i mask = _mm_set1_epi8(0x0f); 540 | // fetch the lookup tables for the given y 541 | const __m128i t_lo = _mm_load_si128((const __m128i*)(GFTBL + 32*y)); 542 | const __m128i t_hi = _mm_load_si128((const __m128i*)(GFTBL + 32*y + 16)); 543 | 544 | const size_t consumed = size - (size % 16); 545 | 546 | while(size >= 16) 547 | { 548 | const __m128i x_1 = _mm_loadu_si128((const __m128i*)(x)); 549 | const __m128i z_1 = _mm_load_si128((const __m128i*)(z)); 550 | 551 | // mask to get LO nibble for LO LUT input 552 | const __m128i x_lo = _mm_and_si128(x_1, mask); 553 | // mask to get HI nibble for HI LUT input 554 | const __m128i x_hi = _mm_and_si128(_mm_srli_epi64(x_1, 4), mask); 555 | 556 | // 16x parallel lookups 557 | const __m128i r_lo = _mm_shuffle_epi8(t_lo, x_lo); 558 | const __m128i r_hi = _mm_shuffle_epi8(t_hi, x_hi); 559 | 560 | // sum the outputs. 561 | __m128i s = _mm_xor_si128(z_1, _mm_xor_si128(r_hi, r_lo)); 562 | 563 | _mm_store_si128((__m128i*)(z), s); 564 | 565 | x += 16; 566 | z += 16; 567 | size -= 16; 568 | } 569 | 570 | return consumed; 571 | } 572 | 573 | } 574 | 575 | -------------------------------------------------------------------------------- /format.txt: -------------------------------------------------------------------------------- 1 | 2 | Proposal for a standardized FEC format, with partial justifications why 3 | the current zfec format isn't cutting it. 4 | 5 | Header 6 | --------------- 7 | 8 | - 4 bytes: magic number 9 | 10 | A magic number is useful for automated identification by applications. 11 | A canonical example would be file(1). Without such a magic number an 12 | application has to rely on other information (file extensions, 13 | user-provided information, blind guessing) to figure out how to 14 | process the file. 15 | 16 | The value I initially preferred was 0xFE 0xCC 0x0D 0xEC, which is the 17 | magic number used internally by Rizzo's FEC. Unfortunately this 18 | sequence is also a legal zfec header, which would mean it cannot be 19 | unambiguously parsed (though the use of n=255 is probably not high), 20 | assuming you are decoding zfec data. So instead we reverse the bytes 21 | (0xEC, 0x0D, 0xCC, 0xFE) which is not a legal zfec header, because as 22 | zfec would interpret this, the share number (0xFE) is greater than N 23 | (0xEC), so it "must" be a FEC file. 24 | 25 | - 2 bytes: chunk size in units of 1024 bytes (big endian) 26 | 27 | Currently zfec's encoding works splitting the file into chunks, K*4096 28 | bytes. This cannot be changed in the zfec format because there is no 29 | info in the header about it. In the future (or even now) (depending on 30 | characteristics of CPU, caches, memory, disks, and operating systems) 31 | it might be much faster to encode 16K, 32K or even larger chunks at a 32 | time, so why not let the encoder choose (if it wants). 33 | 34 | Supporting sub-kilobyte values does not seem particularly useful, and 35 | expressing it in 1 KiB units allows up to 64 MiB chunks, which seems 36 | more than sufficient. 37 | 38 | - 1 byte: N-1 39 | - 1 byte: K-1 40 | - 1 byte: share # 41 | 42 | Why use full byte for N, K, share#? My feeling is the bit packing 43 | scheme used by zfec is not worth it: saves only 2 bytes (at most) and 44 | makes it much harder/more bug prone to write and parse the header. 45 | 46 | - 1 byte: hash id 47 | 48 | 0: no hash 49 | 1: SHA-1 50 | 2: SHA-256 51 | 3: SHA-256d [SHA-256d(m) == SHA-256(SHA-256(m)] 52 | 53 | Allow error checking of recovered inputs 54 | 55 | Semantics of this are currently undefined. 56 | 57 | - 2 bytes: reserved (0) 58 | 59 | Round the header to 12 bytes, and leave some room for expansion. 60 | 61 | If necessary this could be treated as a big-endian length field, with 62 | N following bytes being whatever extra information was needed. 63 | 64 | Trailing Padding 65 | ---------- 66 | 67 | zfec handles data that isn't a multiple of k bytes by adding 68 | sufficient number of 0 bytes. The number of bytes added is 69 | included in header. 70 | 71 | Problem: this requires knowing the length of the input prior to 72 | writing out the header. For files, this can be done (stat the file 73 | ahead of time) but it seems pretty inelegant. Also it doesn't deal at 74 | all well with streaming inputs. 75 | 76 | Instead, prior to encoding, form padding like so: 77 | 78 | 0x80 0x00* 79 | 80 | where is a 2 byte big endian integer specifying the number of 81 | padding bytes. 82 | 83 | is the hash of the entire plaintext, using whatever algorithm 84 | was specified in the header (if any). 85 | 86 | The minimum number of 0x00 bytes are used to pad the total (input + 87 | 0x80 + hash + 2 byte len + zeros) to a multiple of k bytes. 88 | 89 | The decoder then decodes the entire trailing block, and, knowing that 90 | it is looking at the final block, strip off the trailing bytes, saving 91 | the hash to compare with the final value. 92 | 93 | Other thoughts on hashing 94 | ------------------- 95 | 96 | Doing a straight end-to-end hash of the plaintext would require 97 | processing the blocks in-order when decoding, which would require 98 | saving copies instead of emitting them and forgetting about them as 99 | soon as we find them. 100 | 101 | Instead, perhaps, a construction like this: 102 | 103 | H_i = H(share_i) 104 | 105 | Final H = H(H_1 || H_2 || ... || H_n) 106 | 107 | Which would require saving only the hash values instead of the entire 108 | input. 109 | 110 | This also offers reasonable parallelism opportunities, especially 111 | since the inputs (except possibly the last block) will all be the same 112 | size, so you can relatively easily do 4-way hashing on SIMD 113 | processors. 114 | 115 | As always, if hash_id=0 (no hash) is selected, this is all a no-op and 116 | the hash value placed in the trailer is empty. 117 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | (C) 1996-1998 Luigi Rizzo (luigi@iet.unipi.it) 2 | 2009,2010,2018 Jack Lloyd (jack@randombit.net) 3 | 2011 Billy Brumley (billy.brumley@aalto.fi) 4 | 5 | Portions derived from code by Phil Karn (karn@ka9q.ampr.org), 6 | Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari 7 | Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are 11 | met: 12 | 13 | 1. Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 16 | 2. Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the 19 | distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /news.txt: -------------------------------------------------------------------------------- 1 | 2 | 2018-09-24: 0.10 3 | - Convert to using C++11 instead of C++98 + TR1 4 | - Add runtime detection for SSSE3 5 | - Add an SSSE3 implementation of the core routine contributed by 6 | Billy Brumley which is 2 to 3 times faster than the SSE2 7 | implementation on Core i5/i7 processors. 8 | 9 | 2010-03-12: 0.9 10 | - Add Boost.Python wrapper 11 | - Decoder would output blocks with share ids < k more than once 12 | - Add a document formatting a possible new FEC format 13 | 14 | 2009-01-19: 0.8 15 | - First public release 16 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | 2 | NO LONGER MAINTAINED 3 | ======================== 4 | 5 | The same functionality as this library is available in Botan 6 | (https://github.com/randombit/botan) starting in 3.0.0 7 | 8 | THE OLD README -> 9 | =================== 10 | 11 | FECpp: Erasure codes based on Vandermonde matrices 12 | 13 | FECpp contains an implementation of an encoder/decoder for an erasure 14 | code based on Vandermonde matrices computed over GF(2^8). It is based 15 | on fec, by Luigi Rizzo, which is available at 16 | http://info.iet.unipi.it/~luigi/fec.html 17 | 18 | FECpp should be compatible with zfec (http://allmydata.org/trac/zfec), 19 | producing bitwise identical results in all cases. 20 | 21 | Principle of Operation 22 | ======================================== 23 | 24 | The encoded data is computed as 25 | 26 | y = E x 27 | 28 | where x is a k-vector with source data, y is an n-vector with the 29 | redundant info, and E is an n*k matrix derived from a Vandermonde 30 | matrix. The code is systematic, meaning the first k rows of E are the 31 | identity matrix. This causes the first k blocks of output to be equal 32 | to the input, split into k pieces. 33 | 34 | At the receiver, any subset y' of k elements from y allows the 35 | reconstruction of the whole x by solving the system 36 | 37 | y' = E' x 38 | 39 | where E' is made of rows from E corresponding to the received 40 | elements. 41 | 42 | The complexity of matrix inversion is O(k*l^2) where l is the number 43 | of elements not in x available at the receiver. This might seem 44 | large, but data elements are in fact be packets of large size, so 45 | the inversion cost can be amortized over the size of the packet. 46 | For practical applications (k and l as large as 30, packet sizes 47 | of 1KB) the cost can be neglected. 48 | 49 | API Usage 50 | ======================================== 51 | 52 | fecpp provides a single class, fec_code, which is declared in the 53 | header file fecpp.h 54 | 55 | fec_code's constructor takes two integers, k and n. The encoder will 56 | generate n shares, any k of which will be sufficient to recover the 57 | original input. 58 | 59 | To encode, call fec_code's encode operation with a pointer to a 60 | buffer, a length, and a std::function which will be called for each 61 | output block: 62 | 63 | void encode(const byte input[], size_t size, 64 | std::function out) const 65 | 66 | The length of the input must be a multiple of k bytes. 67 | 68 | The arguments to the callback are, in order, the share identifier, the 69 | maximum share that will be generated, and the share contents and 70 | length. The buffer that contains the share data may be reused once the 71 | callback function returns, so if the data must be retained, make a 72 | copy. However in many applications the share will be immediately 73 | written to a file or socket, in which case no copy is necessary. 74 | Each share will be of equal length, specifically size / k bytes. 75 | 76 | To decode a set of shares into the original input, call decode: 77 | 78 | void decode(const std::map& shares, 79 | size_t share_size, 80 | std::function out) const 81 | 82 | The map of shares is a mapping from share identifier (the first 83 | parameter to the encoding callback) to the contents of the share. It 84 | is essential that the share identifiers and shares are associated 85 | properly: otherwise the decoding will fail. As described above, each 86 | share is of equal length, which is specified using the share_size 87 | parameter. 88 | 89 | The output callback for decoding has the same interface, and much the 90 | same semantics, as for encoding. The second parameter, which sets the 91 | maximum number of blocks, will be k instead of n, since there are k 92 | original input blocks. Since each block is the same size, you can 93 | compute the full size of the output (which will be k, the second 94 | parameter, multiplied by the size of each subpart, which is the fourth 95 | parameter). For example to reconstruct the input into a file, you 96 | could seek back and forth writing each block as it becomes available. 97 | 98 | For both encoding and decoding, you should not assume that the output 99 | blocks will be provided to the callback in order. Currently this is 100 | the case for encoding, but not for decoding, and later if 101 | multithreaded operations or OpenMP is used to parellize the encoding 102 | it is quite likely that shares will be provided out of order. 103 | 104 | Future Work / Todos / Send Patches 105 | ======================================== 106 | 107 | * Use threads or OpenMP 108 | * Investigate loop tiling and other matrix multiplication optimizations 109 | * Use a sliding window for the SSE2 multiplication 110 | * Add support for NEON, AVX2, AVX-512, ... 111 | * Streaming interface 112 | * Progressive decoding (is that even possible?) 113 | * Allow use of different polynomials 114 | -------------------------------------------------------------------------------- /test/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "fecpp.h" 2 | #include 3 | #include 4 | 5 | using fecpp::byte; 6 | 7 | namespace { 8 | 9 | class output_checker 10 | { 11 | public: 12 | void operator()(size_t block, size_t /*max_blocks*/, 13 | const byte buf[], size_t size) 14 | { 15 | for(size_t i = 0; i != size; ++i) 16 | { 17 | byte expected = block*size + i; 18 | if(buf[i] != expected) 19 | printf("block=%d i=%d got=%02X expected=%02X\n", 20 | (int)block, (int)i, buf[i], expected); 21 | 22 | } 23 | } 24 | }; 25 | 26 | class save_to_map 27 | { 28 | public: 29 | save_to_map(size_t& share_len_arg, 30 | std::map& m_arg) : 31 | share_len(share_len_arg), m(m_arg) {} 32 | 33 | void operator()(size_t block_no, size_t, 34 | const byte share[], size_t len) 35 | { 36 | share_len = len; 37 | 38 | // Contents of share[] are only valid in this scope, must copy 39 | byte* share_copy = new byte[share_len]; 40 | memcpy(share_copy, share, share_len); 41 | m[block_no] = share_copy; 42 | } 43 | private: 44 | size_t& share_len; 45 | std::map& m; 46 | }; 47 | 48 | void benchmark_fec(size_t k, size_t n) 49 | { 50 | 51 | fecpp::fec_code fec(k, n); 52 | 53 | std::vector input(k * 1024); 54 | for(size_t i = 0; i != input.size(); ++i) 55 | input[i] = i; 56 | 57 | std::map shares; 58 | size_t share_len; 59 | 60 | save_to_map saver(share_len, shares); 61 | 62 | fec.encode(&input[0], input.size(), std::ref(saver)); 63 | 64 | while(shares.size() > k) 65 | shares.erase(shares.begin()); 66 | 67 | output_checker check_output; 68 | fec.decode(shares, share_len, check_output); 69 | } 70 | 71 | } 72 | 73 | int main() 74 | { 75 | const int Ms[] = {1, 2, 3, 4, 5, 7, 8, 16, 32, 64, 128, 192, 254, 255, 0 }; 76 | const int Ks[] = {1,2,3,4,5,6,7,8,9,10,15,16,17,20,31,32,33,63,64,65,127,128,129,192,255 ,0}; 77 | 78 | for(int i = 0; Ms[i]; ++i) 79 | { 80 | for(int j = 0; Ks[j]; ++j) 81 | { 82 | int k = Ks[j]; 83 | int m = Ms[i]; 84 | 85 | if(k >= m) 86 | continue; 87 | 88 | printf("%d %d\n", k, m); 89 | benchmark_fec(k, m); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /test/gen_test_vec.cpp: -------------------------------------------------------------------------------- 1 | #include "fecpp.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using fecpp::byte; 7 | 8 | void print_block(size_t block_no, size_t n, 9 | const byte share[], size_t share_len) 10 | { 11 | printf("block_%d=", (int)block_no); 12 | for(size_t j = 0; j != share_len; ++j) 13 | printf("%02X", share[j]); 14 | if(block_no != n - 1) 15 | printf(", "); 16 | } 17 | 18 | void gen_test_vector(int k, int n) 19 | { 20 | fecpp::fec_code fec(k, n); 21 | 22 | std::vector buf(k * (64 + rand() % 512)); 23 | //std::vector buf(k * (3 + rand() % 5)); 24 | 25 | for(size_t i = 0; i != buf.size(); ++i) 26 | buf[i] = rand(); 27 | 28 | printf("k=%d, n=%d, input=", k, n); 29 | for(size_t i = 0; i != buf.size(); ++i) 30 | printf("%02X", buf[i]); 31 | printf(", "); 32 | 33 | fec.encode(&buf[0], buf.size(), print_block); 34 | 35 | printf("\n"); 36 | } 37 | 38 | int main() 39 | { 40 | srand(0); 41 | 42 | const int Ms[] = {1, 2, 3, 4, 5, 7, 8, 9, 11, 16, 17, 19, 32, 33, 35, 64,65, 66, 67, 43 | 128, 129, 130, 131, 192, 254, 255, 0 }; 44 | const int Ks[] = {1,2,3,4,5,6,7,8,9,10,15,16,17,20,31,32,33,63,64,65,127,128,129,192,255 ,0}; 45 | 46 | for(int i = 0; Ms[i]; ++i) 47 | { 48 | for(int j = 0; Ks[j]; ++j) 49 | { 50 | int k = Ks[j]; 51 | int m = Ms[i]; 52 | 53 | if(k >= m) 54 | continue; 55 | 56 | gen_test_vector(k, m); 57 | } 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /test/test_fec.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test.c -- test code for FEC library 3 | * 4 | * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "fecpp.h" 11 | 12 | /* 13 | * compatibility stuff 14 | */ 15 | #ifdef MSDOS /* but also for others, e.g. sun... */ 16 | #define NEED_BCOPY 17 | #define bcmp(a,b,n) memcmp(a,b,n) 18 | #endif 19 | 20 | #ifdef NEED_BCOPY 21 | #define bcopy(s, d, siz) memcpy((d), (s), (siz)) 22 | #define bzero(d, siz) memset((d), '\0', (siz)) 23 | #endif 24 | 25 | /* 26 | * stuff used for testing purposes only 27 | */ 28 | 29 | #define DEB(x) 30 | #define DDB(x) x 31 | #define DEBUG 0 /* minimal debugging */ 32 | #ifdef MSDOS 33 | #include 34 | struct timeval { 35 | unsigned long ticks; 36 | }; 37 | #define gettimeofday(x, dummy) { (x)->ticks = clock() ; } 38 | #define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC ) 39 | typedef unsigned long u_long ; 40 | typedef unsigned short u_short ; 41 | #else /* typically, unix systems */ 42 | #include 43 | #define DIFF_T(a,b) \ 44 | (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) 45 | #endif 46 | 47 | #define TICK(t) \ 48 | {struct timeval x ; \ 49 | gettimeofday(&x, NULL) ; \ 50 | t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ 51 | } 52 | #define TOCK(t) \ 53 | { u_long t1 ; TICK(t1) ; \ 54 | if (t1 < t) t = 256000000 + t1 - t ; \ 55 | else t = t1 - t ; \ 56 | if (t == 0) t = 1 ;} 57 | 58 | u_long ticks[10]; /* vars for timekeeping */ 59 | 60 | void * 61 | my_malloc(int sz, const char *s) 62 | { 63 | void *p = malloc(sz) ; 64 | if (p != NULL) 65 | return p ; 66 | fprintf(stderr, "test: malloc failure for %d bytes in <%s>\n", 67 | sz, s); 68 | exit(1); 69 | } 70 | 71 | /* 72 | * the following is only test code and can be safely omitted 73 | * in applications. 74 | * Creates k packets of size sz of random data, encodes them, 75 | * and tries to decode. 76 | * Index contains the permutation entry. 77 | */ 78 | 79 | int 80 | test_decode(fec_code& code, size_t k, size_t index[], size_t sz, 81 | const char *s) 82 | { 83 | int errors; 84 | int reconstruct = 0 ; 85 | int item, i ; 86 | 87 | static size_t prev_k = 0, prev_sz = 0; 88 | static byte **d_original = NULL, **d_src = NULL ; 89 | 90 | if (sz < 1 || sz > 8192) { 91 | fprintf(stderr, "test_decode: size %d invalid, must be 1..8K\n", 92 | sz); 93 | return 1 ; 94 | } 95 | if (k < 1 || k > 255 + 1) { 96 | fprintf(stderr, "test_decode: k %d invalid, must be 1..%d\n", 97 | k, 255 + 1 ); 98 | return 2 ; 99 | } 100 | if (prev_k != k || prev_sz != sz) { 101 | if (d_original != NULL) { 102 | for (i = 0 ; i < prev_k ; i++ ) { 103 | free(d_original[i]); 104 | free(d_src[i]); 105 | } 106 | free(d_original); 107 | free(d_src); 108 | d_original = NULL ; 109 | d_src = NULL ; 110 | } 111 | } 112 | prev_k = k ; 113 | prev_sz = sz ; 114 | if (d_original == NULL) { 115 | d_original = (byte**)my_malloc(k * sizeof(byte *), "d_original ptr"); 116 | d_src = (byte**)my_malloc(k * sizeof(void *), "d_src ptr"); 117 | 118 | for (i = 0 ; i < k ; i++ ) { 119 | d_original[i] = (byte*)my_malloc(sz, "d_original data"); 120 | d_src[i] = (byte*)my_malloc(sz, "d_src data"); 121 | } 122 | /* 123 | * build sample data 124 | */ 125 | for (i = 0 ; i < k ; i++ ) { 126 | for (item=0; item < sz; item++) 127 | d_original[i][item] = ((item ^ i) + 3) & 255; 128 | } 129 | } 130 | 131 | errors = 0 ; 132 | 133 | for( i = 0 ; i < k ; i++ ) 134 | if (index[i] >= k ) reconstruct ++ ; 135 | 136 | TICK(ticks[2]); 137 | for( i = 0 ; i < k ; i++ ) 138 | code.encode(d_original, d_src[i], index[i], sz ); 139 | TOCK(ticks[2]); 140 | 141 | TICK(ticks[1]); 142 | code.decode(d_src, index, sz); 143 | TOCK(ticks[1]); 144 | 145 | for (i=0; i 1024) lim = 1024 ; 202 | 203 | #if 0 204 | test_gf(); 205 | #endif 206 | 207 | for ( kk = KK ; kk > 2 ; kk-- ) 208 | { 209 | fec_code code(kk, lim); 210 | ixs = (size_t*)my_malloc(kk * sizeof(size_t), "ixs" ); 211 | 212 | for (i=0; i= kk ; i--) 228 | { 229 | int j ; 230 | for (j=0; j= 0 && i>= lim - kk - 4 ; i--) 237 | { 238 | int j ; 239 | for (j=0; j lim) 248 | max_i0 = lim - KK ; 249 | for (i= 0 ; i <= max_i0 ; i++) 250 | { 251 | for (j=0; j 3 | #include 4 | #include 5 | #include 6 | 7 | using fecpp::byte; 8 | 9 | std::string decode_hex(const std::string& in) 10 | { 11 | const unsigned char HEX_TO_BIN[256] = { 12 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 13 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 14 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 15 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 16 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 17 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 18 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 19 | 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 20 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 21 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 22 | 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 23 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 24 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 25 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 26 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 27 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 28 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 29 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 30 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 31 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 32 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 33 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 34 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 35 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 36 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 37 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; 38 | 39 | if(in.size() % 2 != 0) 40 | throw std::invalid_argument("Odd sized hex string: "+ in); 41 | 42 | std::string out; 43 | 44 | for(size_t i = 0; i != in.size(); i += 2) 45 | { 46 | unsigned char c1 = in[i]; 47 | unsigned char c2 = in[i+1]; 48 | 49 | c1 = HEX_TO_BIN[c1]; 50 | c2 = HEX_TO_BIN[c2]; 51 | 52 | if(c1 == 0x80 || c2 == 0x80) 53 | throw std::invalid_argument("Invalid hex: " + in); 54 | 55 | unsigned char c = (c1 << 4) | c2; 56 | 57 | out.push_back(c); 58 | } 59 | 60 | return out; 61 | } 62 | 63 | // this is really, stupendouly dumb, but it works for current purposes 64 | class chooser_of_k_of_n 65 | { 66 | public: 67 | int choose(); 68 | 69 | chooser_of_k_of_n(int k_arg, int n_arg) : 70 | k(k_arg), n(n_arg), chosen(n) {} 71 | 72 | private: 73 | int k, n; 74 | std::vector chosen; 75 | }; 76 | 77 | int chooser_of_k_of_n::choose() 78 | { 79 | while(true) 80 | { 81 | for(size_t i = 0; i != chosen.size(); ++i) 82 | { 83 | if(std::rand() % 16 == 0) 84 | if(chosen[i] == false) 85 | { 86 | chosen[i] = true; 87 | return i; 88 | } 89 | } 90 | } 91 | } 92 | 93 | class output_checker 94 | { 95 | public: 96 | output_checker(const std::string& in_arg) : in(in_arg) {} 97 | 98 | void operator()(size_t block, size_t max_blocks, 99 | const byte buf[], size_t size) 100 | { 101 | if(out.size() == 0) 102 | out.resize(max_blocks * size); 103 | 104 | for(size_t i = 0; i != size; ++i) 105 | { 106 | byte inb = in.at(block*size+i); 107 | if(inb != buf[i]) 108 | { 109 | printf("Bad: block=%d/%d i=%d in=%02X buf=%02X\n", 110 | (int)block, (int)max_blocks, (int)i, inb, buf[i]); 111 | } 112 | out[block*size+i] = buf[i]; 113 | } 114 | } 115 | 116 | void confirm() 117 | { 118 | if(in != out) 119 | printf("Mismatch in final check!\n"); 120 | } 121 | private: 122 | std::string in; 123 | std::string out; 124 | }; 125 | 126 | bool check_recovery(byte k, byte n, const std::string& hex_input, 127 | const std::vector& hex_packets) 128 | { 129 | std::string input = decode_hex(hex_input); 130 | 131 | std::vector packets; 132 | for(size_t i = 0; i != hex_packets.size(); ++i) 133 | packets.push_back(decode_hex(hex_packets[i])); 134 | 135 | //printf("%d, %d\n", k, n); 136 | fecpp::fec_code code(k, n); 137 | 138 | std::map packets_map; 139 | for(size_t i = 0; i != packets.size(); ++i) 140 | packets_map[i] = (const byte*)packets[i].c_str(); 141 | 142 | output_checker check_output(input); 143 | 144 | chooser_of_k_of_n chooser(k,n); 145 | 146 | while(packets_map.size() > k) 147 | packets_map.erase(chooser.choose()); 148 | 149 | // assumes all same size 150 | code.decode(packets_map, packets[0].size(), std::ref(check_output)); 151 | 152 | check_output.confirm(); 153 | 154 | return true; 155 | } 156 | 157 | int main() 158 | { 159 | std::ifstream testfile("tests.txt"); 160 | 161 | if(!testfile) 162 | { 163 | printf("Could not open input file\n"); 164 | return 1; 165 | } 166 | 167 | int seed = time(0); 168 | 169 | //printf("Using %d as random seed\n", seed); 170 | 171 | std::srand(seed); 172 | 173 | while(testfile.good()) 174 | { 175 | std::string line; 176 | std::getline(testfile, line); 177 | 178 | if(line == "") 179 | continue; 180 | 181 | std::vector inputs; 182 | boost::split(inputs, line, boost::is_any_of(", ")); 183 | 184 | int k = 0, n = 0; 185 | std::string input; 186 | std::vector blocks; 187 | 188 | for(size_t i = 0; i != inputs.size(); ++i) 189 | { 190 | if(inputs[i] == "") 191 | continue; 192 | 193 | std::vector name_val; 194 | boost::split(name_val, inputs[i], boost::is_any_of("=")); 195 | 196 | if(name_val.size() != 2) 197 | throw std::invalid_argument("Bad test line " + inputs[i]); 198 | 199 | std::string name = name_val[0]; 200 | std::string val = name_val[1]; 201 | 202 | if(name == "k") 203 | k = atoi(val.c_str()); 204 | else if(name == "n") 205 | n = atoi(val.c_str()); 206 | else if(name == "input") 207 | input = val; 208 | 209 | // assuming stored in text file in order 210 | else if(name.find_first_of("block_") != std::string::npos) 211 | blocks.push_back(val); 212 | } 213 | 214 | if((int)blocks.size() != n) 215 | throw std::logic_error("Bad block count"); 216 | 217 | if(check_recovery(k, n, input, blocks)) 218 | printf("Good recovery %d %d\n", k, n); 219 | else 220 | printf("Bad recovery %d %d\n", k, n); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /test/zfec.cpp: -------------------------------------------------------------------------------- 1 | #include "fecpp.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using fecpp::byte; 8 | 9 | namespace { 10 | 11 | size_t log2_ceil(size_t n) 12 | { 13 | size_t i = 0; 14 | while(n) 15 | { 16 | n >>= 1; 17 | ++i; 18 | } 19 | return i; 20 | } 21 | 22 | template inline byte get_byte(size_t byte_num, T input) 23 | { 24 | return (input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3)); 25 | } 26 | 27 | void write_zfec_header(std::ostream& output, 28 | size_t n, size_t k, size_t pad_bytes, size_t share_num) 29 | { 30 | // What a waste of effort to save, at best, 2 bytes. Blech. 31 | const size_t nbits = log2_ceil(n-1); 32 | const size_t kbits = log2_ceil(k-1); 33 | 34 | size_t out = (n - 1); 35 | out <<= nbits; 36 | out |= (k - 1); 37 | out <<= kbits; 38 | out |= pad_bytes; 39 | out <<= nbits; 40 | out |= share_num; 41 | 42 | size_t bitsused = 8 + kbits + nbits*2; 43 | 44 | if(bitsused <= 16) 45 | out <<= (16 - bitsused); 46 | else if(bitsused <= 24) 47 | out <<= (24 - bitsused); 48 | else if(bitsused <= 32) 49 | out <<= (32 - bitsused); 50 | 51 | for(size_t i = 0; i != (bitsused+7)/8; ++i) 52 | { 53 | unsigned char b = get_byte(i + (sizeof(size_t) - (bitsused+7)/8), out); 54 | output.write((char*)&b, 1); 55 | } 56 | } 57 | 58 | class zfec_file_writer 59 | { 60 | public: 61 | zfec_file_writer(const std::string& prefix, 62 | size_t n, size_t k, size_t pad_bytes) 63 | { 64 | for(size_t i = 0; i != n; ++i) 65 | { 66 | std::ostringstream outname; 67 | outname << prefix << '.'; 68 | 69 | if(n > 10 && i < 10) 70 | outname << '0'; 71 | if(n > 100 && i < 100) 72 | outname << '0'; 73 | 74 | outname << i << '_' << n << ".fec"; 75 | 76 | std::ofstream* out = new std::ofstream(outname.str().c_str()); 77 | 78 | if(!*out) 79 | throw std::runtime_error("Failed to write " + outname.str()); 80 | 81 | write_zfec_header(*out, n, k, pad_bytes, i); 82 | outputs.push_back(out); 83 | } 84 | } 85 | 86 | ~zfec_file_writer() 87 | { 88 | for(size_t i = 0; i != outputs.size(); ++i) 89 | { 90 | outputs[i]->close(); 91 | delete outputs[i]; 92 | } 93 | } 94 | 95 | void operator()(size_t block, size_t /*max_blocks*/, 96 | const byte buf[], size_t buflen) 97 | { 98 | outputs[block]->write((const char*)buf, buflen); 99 | } 100 | private: 101 | // Have to use pointers instead of obj as copy constructor disabled 102 | std::vector outputs; 103 | }; 104 | 105 | } 106 | 107 | void zfec_encode(size_t k, size_t n, 108 | const std::string& prefix, 109 | std::istream& in, 110 | size_t in_len) 111 | { 112 | const size_t chunksize = 4096; 113 | 114 | fecpp::fec_code fec(k, n); 115 | 116 | std::vector buf(chunksize * k); 117 | 118 | size_t pad_bytes = (in_len % k == 0) ? 0 : k - (in_len % k); 119 | 120 | zfec_file_writer file_writer(prefix, n, k, pad_bytes); 121 | 122 | while(in.good()) 123 | { 124 | in.read((char*)&buf[0], buf.size()); 125 | size_t got = in.gcount(); 126 | 127 | if(got == buf.size()) 128 | fec.encode(&buf[0], buf.size(), std::ref(file_writer)); 129 | else 130 | { 131 | // Handle final block by padding up to k bytes with 0s 132 | for(size_t i = 0; i != pad_bytes; ++i) 133 | buf[i+got] = 0; 134 | fec.encode(&buf[0], got + pad_bytes, std::ref(file_writer)); 135 | } 136 | } 137 | } 138 | 139 | void zfec_encode(size_t k, size_t n, 140 | const std::string& prefix, 141 | std::ifstream& in) 142 | { 143 | in.seekg (0, std::ios::end); 144 | size_t in_length = in.tellg(); 145 | in.seekg (0, std::ios::beg); 146 | 147 | zfec_encode(k, n, prefix, in, in_length); 148 | } 149 | 150 | #include 151 | 152 | int main(int argc, char* argv[]) 153 | { 154 | if(argc != 4) 155 | { 156 | printf("Usage: %s file k m\n", argv[0]); 157 | return 1; 158 | } 159 | 160 | std::ifstream in(argv[1]); 161 | 162 | int k = atoi(argv[2]); 163 | int m = atoi(argv[3]); 164 | 165 | zfec_encode(k, m, "fecpp/out", in); 166 | } 167 | -------------------------------------------------------------------------------- /test_decode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import pyfecpp 4 | import random 5 | 6 | c = pyfecpp.fec_code(3,10) 7 | 8 | shares = c.encode('abcdef012345') 9 | 10 | print shares 11 | 12 | shares = dict([share for share in zip(xrange(0,len(shares)), shares)]) 13 | 14 | print shares 15 | 16 | while len(shares) > c.K: 17 | del shares[random.choice(shares.keys())] 18 | 19 | print shares 20 | 21 | dec = c.decode(shares) 22 | 23 | print dec 24 | 25 | print ''.join(dec) 26 | --------------------------------------------------------------------------------