def decode(self, bitarr): if not bitarr: print('warning: empty block received') return output = [] if not self.allow_partial_block and len(bitarr) % (self.block_size * 8): # cut off unaligned bitarr = bitarr[:-(len(bitarr) % (self.block_size * 8))] if self.allow_partial_block: bitarr_tr = bitarr else: bitarr_tr = _transpose(bitarr, nblocks=self.block_size) bitarr_bytes = _bitarr2bytes(bitarr_tr, False) fail = False for op in range(3): fail = False for i in range(0, len(bitarr_bytes), self.block_size): try: enc_bytes = bitarr_bytes[i:i + self.block_size] if self.allow_partial_block and len( enc_bytes) < self.block_size: partial_block_coder = rs.RSCoder( len(enc_bytes), len(enc_bytes) // 2) decoded = partial_block_coder.decode(enc_bytes)[0] else: decoded = self.coder.decode(enc_bytes)[0] if len(decoded) < self.block_content: diff = self.block_content - len(decoded) decoded = '\0' * diff + decoded #print('d', _str2bitarr(decoded)) output.extend(_str2bitarr(decoded)) except: fail = True output.extend( _bytes2bitarr(bitarr_bytes[i:i + self.block_content])) if not fail: break # hardcoded off-by-one fixes if op == 0: # try adding a byte at beginning bitarr_bytes = b'\0' + bitarr_bytes elif op == 1: # try deleting a byte at end bitarr_bytes = bitarr_bytes[1:-1] return _unpad(output)
def encode(self, bitarr): output = [] if self.allow_partial_block: bitarr_bytes = _bitarr2bytes(bitarr, 8) else: bitarr_bytes = _bitarr2bytes(bitarr, self.block_content * 8) #print('e', len(bitarr_bytes)) for i in range(0, len(bitarr_bytes), self.block_content): print(i) input_bytes = bitarr_bytes[i:i + self.block_content] if self.allow_partial_block and len( input_bytes) * 2 < self.block_content: partial_block_size = len(input_bytes) * 2 partial_block_coder = rs.RSCoder(partial_block_size, len(input_bytes)) encoded = partial_block_coder.encode(input_bytes) else: encoded = self.coder.encode(input_bytes) output.extend(_str2bitarr(encoded)) if not self.allow_partial_block: output_tr = _transpose(output, blocksz=self.block_size) else: output_tr = output return output_tr
def decode(self, bitarr, starts_to_try=10): if not bitarr: print('warning: empty block received') return # sometimes we have extra bytes at the beginning, fix that by bruteforcing for offs in range(starts_to_try): try: if len(bitarr) % 8: # cut off unaligned bitarr_trim = bitarr[:-len(bitarr) % 8] else: bitarr_trim = bitarr if config.DEBUG: import os.path decoded = bitarr_trim[:] if os.path.exists('_actual_message.npy'): if offs: print('reed-solomon offset =', offs) actual = np.load('_actual_message.npy') while len(decoded) > len(actual): decoded.pop() while len(decoded) < len(actual): decoded.append(0) Y = np.array(decoded) X = np.array(actual) bitwise_errs = np.sum(np.abs(Y - X)) X = X.reshape(-1, 8) Y = Y.reshape(-1, 8) errs = np.sum(np.any(X != Y, axis=1)) #print(X) #print(Y) print('bit errors', bitwise_errs, '=', bitwise_errs / len(decoded)) print('byte errors', errs, '=', errs / (len(decoded) // 8)) bitarr_bytes = _bitarr2bytes(bitarr_trim, None) decoded = self.coder.decode(bitarr_bytes)[0] output = _bytes2bitarr(decoded) return _unpad(output, 8) except: bitarr = bitarr[8:] raise Exception('FATAL: reed-solomon decoding failed')
def decode(self, input): return zlib.decompress(_bitarr2bytes(input, pad=False)).decode('ascii')
def encode(self, bitarr): output = [] bitarr_bytes = _bitarr2bytes(bitarr, 8, 8) encoded = self.coder.encode(bitarr_bytes) output = _bytes2bitarr(encoded) return output