
    #)diP                       d Z ddlZddlZ	 e ean# e$ r ddlmZ d5daY nw xY w	 e n# e$ r eZY nw xY w G d de	          Z
t	          dgd	z            at	          d
          a ed          ad Zd6dZd7dZd Zd Zd Zd Zd Zd Zd Zd8dZd9dZd Zd Zd Zd  Zd! Zd" Z d# Z!d$ Z"d:d%Z#d:d&Z$d;d'Z%d;d(Z&d:d)Z'd:d*Z(d<d+Z)d=d,Z*d- Z+d=d.Z,d=d/Z-d>d0Z.d>d1Z/d:d2Z0 G d3 d4e1          Z2dS )?uW  
Reed Solomon
============

A pure-python `universal errors-and-erasures Reed-Solomon Codec <http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction>`_
, based on the wonderful tutorial at
`wikiversity <http://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders>`_,
written by "Bobmath" and "LRQ3000".

The code of wikiversity is here consolidated into a nice API with exceptions handling.
The algorithm can correct up to 2*e+v <= nsym, where e is the number of errors,
v the number of erasures and nsym = n-k = the number of ECC (error correction code) symbols.
This means that you can either correct exactly floor(nsym/2) errors, or nsym erasures
(errors where you know the position), and a combination of both errors and erasures.
The code should work on pretty much any reasonable version of python (2.4-3.5),
but I'm only testing on 2.7 - 3.4.

.. note::
   The codec is universal, meaning that it can decode any message encoded by another RS encoder
   as long as you provide the correct parameters.
   Note however that if you use higher fields (ie, bigger c_exp), the algorithms will be slower, first because
   we cannot then use the optimized bytearray() structure but only array.array('i', ...), and also because
   Reed-Solomon's complexity is quadratic (both in encoding and decoding), so this means that the longer
   your messages, the longer it will take to encode/decode (quadratically!).

   The algorithm itself can handle messages up to (2^c_exp)-1 symbols, including the ECC symbols,
   and each symbol can have a value of up to (2^c_exp)-1 (indeed, both the message length and the maximum
   value for one character is constrained by the same mathematical reason). By default, we use the field GF(2^8),
   which means that you are limited to values between 0 and 255 (perfect to represent a single hexadecimal
   symbol on computers, so you can encode any binary stream) and limited to messages+ecc of maximum
   length 255. However, you can "chunk" longer messages to fit them into the message length limit.
   The ``RSCodec`` class will automatically apply chunking, by splitting longer messages into chunks and
   encode/decode them separately; it shouldn't make a difference from an API perspective (ie, from your POV).

::

    # Initialization
    >>> from reedsolo import RSCodec
    >>> rsc = RSCodec(10)  # 10 ecc symbols

    # Encoding
    >>> rsc.encode([1,2,3,4])
    b',+=øhúM'
    >>> rsc.encode(bytearray([1,2,3,4]))
    bytearray(b',+=øhúM')
    >>> rsc.encode(b'hello world')
    b'hello worldí%TÄýýó¨ª'
    # Note that chunking is supported transparently to encode any string length.

    # Decoding (repairing)
    >>> rsc.decode(b'hello worldí%TÄýýó¨ª')[0]
    b'hello world'
    >>> rsc.decode(b'heXlo worXdí%TÄýXó¨ª')[0]     # 3 errors
    b'hello world'
    >>> rsc.decode(b'hXXXo worXdí%TÄýXó¨ª')[0]     # 5 errors
    b'hello world'
    >>> rsc.decode(b'hXXXo worXdí%TÄýXXó¨ª')[0]        # 6 errors - fail
    Traceback (most recent call last):
      ...
    ReedSolomonError: Could not locate error

    >>> rsc = RSCodec(12)  # using 2 more ecc symbols (to correct max 6 errors or 12 erasures)
    >>> rsc.encode(b'hello world')
    b'hello world?Ay²¼Üq¹ãâ='
    >>> rsc.decode(b'hello worXXXXy²XXq¹ãâ=')[0]         # 6 errors - ok
    b'hello world'
    >>> rsc.decode(b'helXXXXXXXXXXy²XXq¹ãâ=', erase_pos=[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16])[0]  # 12 erasures - OK
    b'hello world'

    # Checking
    >> rsc.check(b'hello worXXXXy²XXq¹ãâ=')
    [False]
    >> rmes, rmesecc = rsc.decode(b'hello worXXXXy²XXq¹ãâ=')
    >> rsc.check(rmesecc)
    [True]

    # To use longer chunks or bigger values than 255 (may be very slow)
    >> rsc = RSCodec(12, nsize=4095)  # always use a power of 2 minus 1
    >> rsc = RSCodec(12, c_exp=12)  # alternative way to set nsize=4095
    >> mes = 'a' * (4095-12)
    >> mesecc = rsc.encode(mes)
    >> mesecc[2] = 1
    >> mesecc[-1] = 1
    >> rmes, rmesecc = rsc.decode(mesecc)
    >> rsc.check(mesecc)
    [False]
    >> rsc.check(rmesecc)
    [True]

    If you want full control, you can skip the API and directly use the library as-is. Here's how:

    First you need to init the precomputed tables:
    >> import reedsolo as rs
    >> rs.init_tables(0x11d)
    Pro tip: if you get the error: ValueError: byte must be in range(0, 256), please check that your prime polynomial is correct for your field.
    Pro tip2: by default, you can only encode messages of max length and max symbol value = 256. If you want to encode bigger messages,
    please use the following (where c_exp is the exponent of your Galois Field, eg, 12 = max length 2^12 = 4096):
    >> prim = rs.find_prime_polys(c_exp=12, fast_primes=True, single=True)
    >> rs.init_tables(c_exp=12, prim=prim)
    
    Let's define our RS message and ecc size:
    >> n = 255  # length of total message+ecc
    >> nsym = 12  # length of ecc
    >> mes = "a" * (n-nsym)  # generate a sample message

    To optimize, you can precompute the generator polynomial:
    >> gen = rs.rs_generator_poly_all(n)

    Then to encode:
    >> mesecc = rs.rs_encode_msg(mes, nsym, gen=gen[nsym])

    Let's tamper our message:
    >> mesecc[1] = 0

    To decode:
    >> rmes, recc, errata_pos = rs.rs_correct_msg(mesecc, nsym, erase_pos=erase_pos)
    Note that both the message and the ecc are corrected (if possible of course).
    Pro tip: if you know a few erasures positions, you can specify them in a list `erase_pos` to double the repair power. But you can also just specify an empty list.

    If the decoding fails, it will normally automatically check and raise a ReedSolomonError exception that you can handle.
    However if you want to manually check if the repaired message is correct, you can do so:
    >> rs.rs_check(rmes + recc, nsym)

    Note: if you want to use multiple reedsolomon with different parameters, you need to backup the globals and restore them before calling reedsolo functions:
    >> rs.init_tables()
    >> global gf_log, gf_exp, field_charac
    >> bak_gf_log, bak_gf_exp, bak_field_charac = gf_log, gf_exp, field_charac
    Then at anytime, you can do:
    >> global gf_log, gf_exp, field_charac
    >> gf_log, gf_exp, field_charac = bak_gf_log, bak_gf_exp, bak_field_charac
    >> mesecc = rs.rs_encode_msg(mes, nsym)
    >> rmes, recc, errata_pos = rs.rs_correct_msg(mesecc, nsym)
    The globals backup is not necessary if you use RSCodec, it will be automatically managed.

    Read the sourcecode's comments for more info about how it works, and for the various parameters you can setup if
    you need to interface with other RS codecs.

    Narraylatin-1c                     t          | t                    r d |                     |          D             } nt          | t                    rdg| z  } t	          d|           S )zSimple bytearray replacementc                 ,    g | ]}t          |          S  ord).0chs     O/var/www/menimich/repos/protonApp/venv/lib/python3.11/site-packages/reedsolo.py
<listcomp>z_bytearray.<locals>.<listcomp>   s    :::r3r77:::    r   B)
isinstancestrencodeintr   )objencodings     r   
_bytearrayr      sb     c3 	::SZZ%9%9:::CCS!! 	#)CS#r   c                       e Zd ZdS )ReedSolomonErrorN)__name__
__module____qualname__r   r   r   r   r      s        Dr   r      i         c           	         dgt          | dz            z  t          dt          | dz            dz   d          D ]X}t          |dz                     r>dgt          | ||z  z
  dz
  d|z  z  dz             z  t          ||z  dz            d|<   Ydgfdt          dt          | dz                      D             z   S )	z Returns  a list of primes < n T      g      ?r   FNc                 0    g | ]}|         
d |z  dz   S )r!   r   r   )r   isieves     r   r   zrwh_primes1.<locals>.<listcomp>   s*    @@@AuQx@!A#a%@@@r   )r   xrange)nr$   r%   s     @r   rwh_primes1r(      s     FS1XXEAc!S&kk!mA&& F FQqS? 	F&+WsAacE!Gac?13D/E/E%EE#qsAg,,//"3@@@@#ac((!3!3@@@@@r   r!      Fc           	         d}t          ||z  dz
            t          ||dz   z  dz
            }g }|rt          |          }fd|D             }nt          dz   ||          }g }|D ]w}t          dz             }	d}
d}t                    D ]2}t	          || |dz             }|k    s|	|         dk    rd}
 nd|	|<   3|
s|                    |           |r|c S x|S )zgCompute the list of prime polynomials for the given generator and galois field characteristic exponent.r!   r   c                      g | ]
}|k    |S r   r   )r   xfield_characs     r   r   z$find_prime_polys.<locals>.<listcomp>   s#    JJJ\9I9I19I9I9Ir   FT)r   r(   r&   r   gf_mult_noLUTappend)	generatorc_expfast_primessingleroot_characfield_charac_nextprim_candidatescorrect_primesprimseenconflictr,   r$   r-   s                @r   find_prime_polysr;      sP    K{E)A-..LK%'2Q677O Q%&788JJJJoJJJ a1BKPP N # #,q.)) %% 
	 
	AaD,q.AAA <47a<< Q  	#!!$'''"d{{{ r     c                    |dk    rt           anddlm dfd	at          d|z  dz
            at          t          dz            at          t          dz             ad}t          t                    D ]0}|t
          |<   |t          |<   t          ||| t          dz             }1t          t          t          dz            D ]}t
          |t          z
           t
          |<    t          t
          t          gS )	a-  Precompute the logarithm and anti-log tables for faster computation later, using the provided primitive polynomial.
    These tables are used for multiplication/division since addition/substraction are simple XOR operations inside GF of characteristic 2.
    The basic idea is quite simple: since b**(log_b(x), log_b(y)) == x * y given any number b (the base or generator of the logarithm), then we can use any number b to precompute logarithm and anti-log (exponentiation) tables to use for multiplying two numbers x and y.
    That's why when we use a different base/generator number, the log and anti-log tables are drastically different, but the resulting computations are the same given any such tables.
    For more infos, see https://en.wikipedia.org/wiki/Finite_field_arithmetic#Implementation_tricks
    r)   r   r   r   c                    t          | t                    rb|                     |          } t          | t                    rd | D             } nht          | t                    rd | D             } nFt          dft          | t
                    rdg| z  } n!t          | t                    rd | D             }  d|           S )z;Fake bytearray replacement, supporting int values above 255c                 ,    g | ]}t          |          S r   r	   r   chrs     r   r   z_bytearray.<locals>.<listcomp>      3333s88333r   c                 ,    g | ]}t          |          S r   r   r@   s     r   r   z_bytearray.<locals>.<listcomp>  rB   r   zType of object not recognized!r   c                 ,    g | ]}t          |          S r   rD   )r   bs     r   r   z_bytearray.<locals>.<listcomp>  s    +++!s1vv+++r   r$   )r   r   r   bytes
ValueErrorr   )r   r   r   s     r   r   r   
  s     #s## ,jj**c3'' H33s333CCU++ H33s333CC$&FGGC%% ,cCiC'' ,++s+++5c??"r   r!   r   r   r   )		bytearrayr   r   r   r-   gf_expgf_logr&   r.   )r8   r0   r1   r,   r$   r   s        @r   init_tablesrM      s
    zz

	# 	# 	# 	# 	# 	#( q%x!|$$Lq())FQ''F 	
AL!! > >q	q	!Yl1n== L,"233 - -1|+,q		FL))r   c                     | |z  S Nr   r,   ys     r   gf_addrR   5      q5Lr   c                     | |z  S rO   r   rP   s     r   gf_subrU   8  rS   r   c                     | S rO   r   r,   s    r   gf_negrX   ;  s    Hr   c                 B    t           t          t          |          z
           S rO   )rK   r-   rL   rW   s    r   
gf_inverserZ   >  s    ,*++r   c                 z    | dk    s|dk    rdS t           t          |          t          |         z   t          z           S Nr   rK   rL   r-   rP   s     r   gf_mulr^   A  s5    Avvaq6!9vay(L899r   c                     |dk    rt                      | dk    rdS t          t          |          t          z   t          |         z
  t          z           S r\   )ZeroDivisionErrorrK   rL   r-   rP   s     r   gf_divra   F  sG    Avv!!!Avvq6!9|+fQi7<GHHr   c                 H    t           t          |          |z  t          z           S rO   r]   )r,   powers     r   gf_powrd   M  s    6!9u$455r   c                 \    d }d dfd	} || |          }|dk    r |||          }|S )zMultiplication in Galois Fields without using a precomputed look-up table (and thus it's slower) by using the standard carry-less multiplication + modular reduction using an irreducible prime polynomial.c                 \    d}d}||z	  dk    r|d|z  z  r|| |z  z  }|dz  }||z	  dk    |S )z-Bitwise carry-less multiplication on integersr   r   r   )r,   rQ   zr$   s       r   cl_multz#gf_mult_noLUT_slow.<locals>.cl_multT  sU    !tqjjAqDz QT	FA !tqjj r   c                 (    d}| |z	  r
|dz  }| |z	  
|S )zbCompute the position of the most significant bit (1) of an integer. Equivalent to int.bit_length()r   r   r   )r'   bitss     r   
bit_lengthz&gf_mult_noLUT_slow.<locals>.bit_length^  s'    4i"a4i"r   Nc                      |           } |          }||k     r| S t          ||z
  dd          D ]}| d||z   dz
  z  z  r| ||z  z  } | S )zFBitwise carry-less long division on integers and returns the remainderr   r&   )dividenddivisordl1dl2r$   rk   s        r   cl_divz"gf_mult_noLUT_slow.<locals>.cl_divd  s}     j""j!!99OC2&& 	) 	)A1#a<( )GqL(r   r   rO   r   )r,   rQ   r8   rh   rs   resultrk   s         @r   gf_mult_noLUT_slowru   P  so             & WQq\\Faxx%%Mr   Tc                 h    d}|r-|dz  r|r|| z  n|| z   }|dz	  }| dz  } |dk    r
| |z  r| |z  } |-|S )a7  Galois Field integer multiplication using Russian Peasant Multiplication algorithm (faster than the standard multiplication + modular reduction).
    If prim is 0 and carryless=False, then the function produces the result for a standard integers multiplication (no carry-less arithmetics nor modular reduction).r   r   r   )r,   rQ   r8   field_charac_full	carrylessrs         r   r.   r.   ~  sn     	
A
 <q53y3a!eea!e!FF!88--81t8q	  < Hr   c                 r     t           fdt          t                               D                       S )Nc                 <    g | ]}t          |                   S r   )r^   )r   r$   pr,   s     r   r   z!gf_poly_scale.<locals>.<listcomp>  s%    ???1vadA???r   )r   r&   len)r|   r,   s   ``r   gf_poly_scaler~     s6    ?????s1vv???@@@r   c                    t          t          t          |           t          |                              }| |t          |          t          |           z
  t          |          <   t          t          |                    D ]8}||t          |          z   t          |          z
  xx         ||         z  cc<   9|S rO   )r   maxr}   r&   )r|   qry   r$   s       r   gf_poly_addr     s    CAA''))AAc!ffSVVmCFF CFF^^ ' '	!c!ff*s1vv
!A$&Hr   c                     t          t                     t          |          z   dz
            } fdt          t                               D             }t          t          |                    D ]o}||         }|dk    r_t          |         }t          t                               D ]5} |         dk    r'|||z   xx         t          ||         |z            z  cc<   6p|S )zzMultiply two polynomials, inside Galois Field (but the procedure is generic). Optimized function by precomputation of log.r   c                 6    g | ]}t           |                  S r   rL   )r   r$   r|   s     r   r   zgf_poly_mul.<locals>.<listcomp>  s!    	/	/	/1&1,	/	/	/r   r   )r   r}   r&   rL   rK   )r|   r   ry   lpjqjlqr$   s   `       r   gf_poly_mulr     s     	3q66CFF?Q&''A	/	/	/	/s1vv	/	/	/BCFF^^ 3 3qT77BCFF^^ 3 3Q4199a!eHHHr!urz 22HHHHr   c           
      :   t          t          |           t          |          z   dz
            }t          t          |                    D ]N}t          t          |                     D ]/}|||z   xx         t          | |         ||                   z  cc<   0O|S )z-Multiply two polynomials, inside Galois Fieldr   )r   r}   r&   r^   )r|   r   ry   r   r$   s        r   gf_poly_mul_simpler     s     	3q66CFF?Q&''ACFF^^ + +A 	+ 	+Aa!eHHHqtQqT***HHHH	+Hr   c                     | S )zReturns the polynomial with all coefficients negated. In GF(2^p), negation does not change the coefficient, so we return the polynomial as-is.r   )polys    r   gf_poly_negr     s    Kr   c           	         t          |           }t          t          |           t          |          dz
  z
            D ]c}||         }|dk    rSt          dt          |                    D ]5}||         dk    r'|||z   xx         t          ||         |          z  cc<   6dt          |          dz
   }|d|         ||d         fS )zFast polynomial division by using Extended Synthetic Division and optimized for GF(2^p) computations (doesn't work with standard polynomials outside of this galois field).r   r   N)r   r&   r}   r^   )ro   rp   msg_outr$   coefr   	separators          r   gf_poly_divr     s     ""GCMMS\\!^455 ? ?qz199As7||,, ? ?1:??AENNNfWQZ&>&>>NNN g,,q.!I:I:	

 333r   c                 n   t          |           }t          d|z  dz
            }t          |dz
            D ]3}| |         }d|z  }|dk    rt          dt          |         z           ||<   4t          dt          | |dz
                    z           |d|z  dz
  <   |d         dk    rd| d         z  dz
  |d<   |S )aB  Linear time implementation of polynomial squaring. For details, see paper: "A fast software implementation for arithmetic operations in GF (2n)". De Win, E., Bosselaers, A., Vandenberghe, S., De Gersem, P., & Vandewalle, J. (1996, January). In Advances in Cryptology - Asiacrypt'96 (pp. 65-76). Springer Berlin Heidelberg.r!   r   r   )r}   r   r&   rK   rL   )r   lengthoutr$   r|   ks         r   gf_poly_squarer     s    YYF
QvX\
"
"CF1H ) )GaC66AfQiK(CF Qvd6!8n556C&
O
1v{{QtAwY]CFJr   c                     | d         }t          dt          |                     D ]}t          ||          | |         z  }|S )zqEvaluates a polynomial in GF(2^p) given the value for x. This is based on Horner's scheme for maximum efficiency.r   r   )r&   r}   r^   )r   r,   rQ   r$   s       r   gf_poly_evalr     sG    QAAs4yy!! # #1aLL47"Hr   c           
          t          dg          }t          |           D ]%}t          |dt          |||z             g          }&|S )z^Generate an irreducible generator polynomial (necessary to encode a message into Reed-Solomon)r   )r   r&   r   rd   )nsymfcrr0   gr$   s        r   rs_generator_polyr     sM    A3AD\\ : :Avi377899Hr   c                     i }t          dg          x|d<   |d<   t          |           D ]}t          |||          ||<   |S )zGenerate all irreducible generator polynomials up to max_nsym (usually you can use n, the length of the message+ecc). Very useful to reduce processing time if you want to encode using variable schemes and nsym rates.r   r   )r   r&   r   )max_nsymr   r0   g_allr   s        r   rs_generator_poly_allr     sT    E$aS//)E!HuQxx   > >'c9==dLr   c                 $   t          |           |z   t          k    r)t          dt          |           |z   t          fz            |t          |||          }t	          | t          t          |          dz
            z   |          \  }}| |z   }|S )zSimple Reed-Solomon encoding (mainly an example for you to understand how it works, because it's slower than the inlined function below)'Message is too long (%i when max is %i)Nr   )r}   r-   rH   r   r   r   )msg_inr   r   r0   gen_	remainderr   s           r   rs_simple_encode_msgr     s     	Fdl***=fjmntjujuvzjz  }I  jJ  >J  3K  3K  -K
{+D#yAAC v
3s88A:(>(>>DDLAyy GNr   c           	         t          |           |z   t          k    r)t          dt          |           |z   t          fz            t          |||          t	          |           } t	          |           t	          t                    dz
            z   }t	          fdt          t                              D                       }t          t          |                     D ]d}||         }|dk    rTt          |         }	t          dt                              D ])}
|||
z   xx         t          |	||
         z            z  cc<   *e| |dt          |           <   |S )zReed-Solomon main encoding function, using polynomial division (Extended Synthetic Division, the fastest algorithm available to my knowledge), better explained at http://research.swtch.com/fieldr   Nr   c                 6    g | ]}t           |                  S r   r   )r   r   r   s     r   r   z!rs_encode_msg.<locals>.<listcomp>	  s!    @@@!vc!f~@@@r   r   )r}   r-   rH   r   r   r&   rL   rK   )r   r   r   r0   r   r   lgenr$   r   lcoefr   s       `      r   rs_encode_msgr     so    	Fdl***=fjmntjujuvzjz  }I  jJ  >J  3K  3K  -K
{+D#yAACF  :c#hhqj#9#99G @@@@vc#hh/?/?@@@AAD CKK   : :qz1994LEAs3xx(( : :A&a"99 #GLS[[LNr   c                 J     dg fdt          |          D             z   S )zGiven the received codeword msg and the number of error correcting symbols (nsym), computes the syndromes polynomial.
    Mathematically, it's essentially equivalent to a Fourrier Transform (Chien search being the inverse).
    r   c           
      R    g | ]#}t          t          |z                       $S r   )r   rd   )r   r$   r   r0   msgs     r   r   z%rs_calc_syndromes.<locals>.<listcomp>$  s1    TTT!,sF9ae$<$<==TTTr   rn   r   r   r   r0   s   ` ``r   rs_calc_syndromesr     s5     3TTTTTTvd||TTTTTr   c                    t          |           fd|D             }t          ||          }t          |ddd         |t          |          dz
            ddd         }g }t	          t          |                    D ]6}	t
          ||	         z
  }
|                    t          ||
                      7t          t                              }t          |          }t          |          D ]\  }	}t          |          }g }t	          |          D ]?}||	k    r7|                    t          dt          |||                                        @d}|D ]}t          ||          }|dk    rt          d          t          |ddd         |          }t          t          |d|z
            |          }t          ||          }||||	         <   t          |          S )zUForney algorithm, computes the values (error magnitude) to correct the input message.c                 :    g | ]}t                    d z
  |z
  S r   r}   )r   r|   r   s     r   r   z%rs_correct_errata.<locals>.<listcomp>+  s(    222QC1q 222r   Nrm   r   r   zuDecoding failed: Forney algorithm could not properly detect where the errors are located (errata locator prime is 0).)r   rs_find_errata_locatorrs_find_error_evaluatorr}   r&   r-   r/   rd   	enumeraterZ   rU   r^   r   r   ra   r   )r   synderr_posr   r0   coef_poserr_locerr_evalXr$   lEXlengthXiXi_inverr_loc_prime_tmpr   err_loc_primer   rQ   	magnituder   s                        @r   rs_correct_erratar   &  s    V

C2222'222H$Xy99G&tDDbDz7CLLNKKDDbDQH 	ACMM"" * *8A;&	&QB'')))) 	3s88A!ffG1 " "2B  	L 	LAAvv!((&F61Q44H4H*I*IKKK% 	8 	8D"=$77MM A"  $[  \  \  \
 $$B$006"ae$$a(( 1m,,	!'!* c1

CJr   c           	      n   |rt          |          }t          |          }n t          dg          }t          dg          }d}t          |           |k    rt          |           |z
  }t          ||z
            D ]}|r	||z   |z   }n||z   }| |         }	t          dt          |                    D ](}
|	t          ||
dz             | ||
z
                     z  }	)|t          dg          z   }|	dk    rmt          |          t          |          k    r/t	          ||	          }t	          |t          |	                    }|}t          |t	          ||	                    }t          t          j	        d |                    }t          |          dz
  }||z
  dz  |z   |k    rt          d          |S )zSFind error/errata locator and evaluator polynomials with Berlekamp-Massey algorithmr   r   c                     | dk    S r\   r   rW   s    r   <lambda>z'rs_find_error_locator.<locals>.<lambda>  s
    a r   r!   zToo many errors to correct)r   r}   r&   r^   r~   rZ   r   list	itertools	dropwhiler   )r   r   	erase_locerase_countr   old_loc
synd_shiftr$   Kdeltar   new_locerrss                r   rs_find_error_locatorr   \  s     "Y''Y''aS//aS//
 J
4yy4c$ii$&6D$%% J J 	Aj(AA*A Q3w<<(( 	: 	:AVGacFOT!a%[999EE JsOO+ A::7||c'll** (77'E1B1BCC!
 "'=%+H+HIIG 9&'7'7AABBGw<<!D[A+d22;<<<Nr   c                     dg}| D ]>}t          |t          t          dg          t          ||          dg                    }?|S )a  Compute the erasures/errors/errata locator polynomial from the erasures/errors/errata positions (the positions must be relative to the x coefficient, eg: "hello worldxxxxxxxxx" is tampered to "h_ll_ worldxxxxxxxxx" with xxxxxxxxx being the ecc of length n-k=9, here the string positions are [1, 4], but the coefficients are reversed since the ecc characters are placed as the first coefficients of the polynomial, thus the coefficients of the erased characters are n-1 - [1, 4] = [18, 15] = erasures_loc to be specified as an argument.r   r   )r   r   r   rd   )e_posr0   e_locr$   s       r   r   r     sU     CE ^ ^UK
A3&TUBVBVXYAZ$[$[]]Lr   c                 ^    t          t          | |          dgdg|dz   z  z             \  }}|S )a  Compute the error (or erasures if you supply sigma=erasures locator polynomial, or errata) evaluator polynomial Omega from the syndrome and the error/erasures/errata locator Sigma. Omega is already computed at the same time as Sigma inside the Berlekamp-Massey implemented above, but in case you modify Sigma, you can recompute Omega afterwards using this method, or just ensure that Omega computed by BM is correct given Sigma.r   r   )r   r   )r   r   r   r   r   s        r   r   r     s:     D' : :aSA3Q<=ORRLAy r   c                    t          |           dz
  }g }t          |          D ]?}t          | t          ||                    dk    r|                    |dz
  |z
             @t          |          |k    rt          d          |S )zFind the roots (ie, where evaluation = zero) of error polynomial by bruteforce trial, this is a sort of Chien's search (but less efficient, Chien's search is a way to evaluate the polynomial such that each evaluation only takes constant time).r   r   zQToo many (or few) errors found by Chien Search for the errata locator polynomial!)r}   r&   r   rd   r/   r   )r   nmessr0   r   r   r$   s         r   rs_find_errorsr     s     w<<!DGE]] * *	1!5!566!;;NN519q=)))
7||trsssNr   c                 J   fd|D             }t          | dd                    }t          t          |                    D ]_}t          |||                   }t          t          |          dz
            D ]'}t	          ||         |          ||dz            z  ||<   (`|S )Nc                      g | ]
}d z
  |z
  S r   r   )r   r|   r   s     r   r   z'rs_forney_syndromes.<locals>.<listcomp>  s!    111%'!)111r   r   )r   r&   r}   rd   r^   )	r   posr   r0   erase_pos_reversedfsyndr$   r,   r   s	     `      r   rs_forney_syndromesr     s    1111S111 abbNNECHH : :90344E

Q'' 	: 	:AeAh**U1q5\9E!HH	: Lr   c                 4   t          |           t          k    r&t          dt          |           t          fz            t          |           }|g }n
|D ]}d||<   t          |          |k    rt	          d          t          ||||          }t          |          dk    r|d|          || d         |fS |rg }	nvt          ||t          |          |          }
t          |
|t          |                    }t          |ddd         t          |          |          }	|	t	          d          t          ||||	z   ||          }t          ||||          }t          |          dk    rt	          d          |d|          || d         ||	z   fS )	z#Reed-Solomon main decoding functionr   Nr   Too many erasures to correct)r   rm   Could not locate errorCould not correct message)r}   r-   rH   r   r   r   r   r   r   r   r   )r   r   r   r0   	erase_posonly_erasuresr   r   r   r   r   r   s               r   rs_correct_msgr     s    6{{\!!Bc&kkS_E``aaa  G		 	 	EGENN
9~~$45S$T$TTWdC;;D
4yyA~~vv::  
= $D)S\\9MM'tYPPP 2GiHH?"#;<<<  y7/BCSSGWdC;;D
4yy1}}:;;;6TE6?GTEFFOY-@@@r   c                 Z   t          |           t          k    r&t          dt          |           t          fz            t          |           |g }n
|D ]}d|<   t          |          |k    rt	          d          t          |||          }t          |          dk    rd|          | d         g fS d}d}	|r.t          |          }	fd|D             }
t          |
|          }|r|ddd         }nt          ||||	          }|ddd         }t          |t                    |          }|t	          d	          t          ||||
          t          |||          }t          |          dk    rt	          d          d|          | d         ||z   fS )zPReed-Solomon main decoding function, without using the modified Forney syndromesr   Nr   r   c                 :    g | ]}t                    d z
  |z
  S r   r   )r   erasr   s     r   r   z*rs_correct_msg_nofsynd.<locals>.<listcomp>  s(    HHHdc'll1nT1HHHr   )r0   rm   )r   r   r   r   r0   r   )r}   r-   rH   r   r   r   r   r   r   r   r   )r   r   r   r0   r   r   r   r   r   r   r   r   r   r   s                @r   rs_correct_msg_nofsyndr     s    6{{\!!Bc&kkS_E``aaa  G		 	 	EGENN
9~~$45S$T$TTWdC;;D
4yyA~~vv33 IK T)nnHHHHiHHH*+=SSS	   DDbD/ (diU`aaa$$B$- Wc'llI>>G7888  wC9UUUGWdC;;D
4yy1}}:;;;6TE6?GTEFFOY-@@@r   c                 H    t          t          | |||                    dk    S )zReturns true if the message + ecc has no error of false otherwise (may not always catch a wrong decoding or a wrong message, particularly if there are too many errors -- above the Singleton bound --, but it usually does)r   )r   r   r   s       r   rs_checkr   2  s$    "3c9==>>!CEr   c                   B    e Zd ZdZ	 dd	Zd
 ZddZddZddZddZ	dS )RSCodeca  
    A Reed Solomon encoder/decoder. After initializing the object, use ``encode`` to encode a
    (byte)string to include the RS correction code, and pass such an encoded (byte)string to
    ``decode`` to extract the original message (if the number of errors allows for correct decoding).
    The ``nsym`` argument is the length of the correction code, and it determines the number of
    error bytes (if I understand this correctly, half of ``nsym`` is correctable)
    
   r   r   r<   r!   r)   Tc                    |dk    rg|dk    rat          t          j        dt          j        t          j        |          t          j        d          z            dz   z  d                    }|dk    r4|dk    r.t	          ||dd          }|dk    rt          d|z  dz
            }||k    rt          d          || _        || _        || _        || _	        || _
        || _        t          |||          \  | _        | _        | _        |r#i | _        t#          |||	          | j        |<   d
S t%          |||	          | _        d
S )a  Initialize the Reed-Solomon codec. Note that different parameters change the internal values (the ecc symbols, look-up table values, etc) but not the output result (whether your message can be repaired or not, there is no influence of the parameters).
        nsym : number of ecc symbols (you can repair nsym/2 errors and nsym erasures.
        nsize : maximum length of each chunk. If higher than 255, will use a higher Galois Field, but the algorithm's complexity and computational cost will raise quadratically...
        single_gen : if you want to use the same RSCodec for different nsym parameters (but nsize the same), then set single_gen = False.
        r   r)   r!   r   r<   T)r0   r1   r2   r3   zOECC symbols must be strictly less than the total message length (nsym < nsize).r   N)r   mathlogfloorr;   rH   r   nsizer   r8   r0   r1   rM   rL   rK   r-   r   r   r   )selfr   r   r   r8   r0   r1   
single_gens           r   __init__zRSCodec.__init__K  sO    3;;5A::tz$(5//DHQKK2O'P'PST'T!UWXYYZZEA::$%--#iuRV_cdddD||AuHqL))5==nooo 	
	"
 7B$	SX6Y6Y3T[$"3 	RDH.t	RRRDHTNNN,UyQQQDHHHr   c              #   n   K   t          dt          |          |          D ]}||||z            }|V  dS )z Split a long message into chunksr   N)r&   r}   )r   data	chunksizer$   chunks        r   r  zRSCodec.chunkn  sN      3t99i00 	 	A1Y;'EKKKK	 	r   Nc                 v   | j         | j        | j        ca aa|s| j        }t	          |t
                    rt          |          }t                      }|                     || j        | j        z
            D ]C}|	                    t          || j        | j        | j        | j        |                              D|S )zyEncode a message (ie, add the ecc symbols) using Reed-Solomon, whatever the length of the message because we use chunking)r   r0   r   )rL   rK   r-   r   r   r   r   r  r   extendr   r   r0   r   )r   r  r   encr  s        r   r   zRSCodec.encodeu  s     (,{DKAR$ 	9DdC   	$d##DllZZdj49&<== 	t 	tEJJ}UDI48t~cgcklpcqrrrssss
r   Fc           	      .     j          j         j        ca aa|s j        }t	          |t
                    rt          |          }t                      }t                      }t                      }                     | j                  D ]}g }	|r fd|D             }	 fd|D             }t          || j
         j        |	|          \  }
}}|                    |
           |                    |
|z              |                    |           |||fS )a)  Repair a message, whatever its size is, by using chunking. May return a wrong result if number of errors > nsym.
        Note that it returns a couple of vars: the repaired messages, and the repaired messages+ecc (useful for checking).
        Usage: rmes, rmesecc = RSCodec.decode(data).
        c                 *    g | ]}|j         k     |S r   r   r   r,   r   s     r   r   z"RSCodec.decode.<locals>.<listcomp>  s     @@@qTZr   c                 :    g | ]}|j         k    |j         z
  S r   r
  r  s     r   r   z"RSCodec.decode.<locals>.<listcomp>  s&    RRR!tz//Q^///r   )r   r0   r   r   )rL   rK   r-   r   r   r   r   r  r   r   r   r0   r  )r   r  r   r   r   decdec_fullerrata_pos_allr  r   rmesrecc
errata_poss   `            r   decodezRSCodec.decode  sF    (,{DKAR$ 	9DdC   	$d##Dll<<#ZZdj11 	. 	.EE S@@@@I@@@RRRRYRRR	%3E4TXY]Ygsx  IV  &W  &W  &W"D$
JJtOODI&&&!!*----Hn,,r   c           	          |s| j         }t          |t                    rt          |          }g }|                     || j                  D ]2}|                    t          ||| j        | j	                             3|S )zCheck if a message+ecc stream is not corrupted (or fully repaired). Note: may return a wrong result if number of errors > nsym.r   )
r   r   r   r   r  r   r/   r   r   r0   )r   r  r   checkr  s        r   r  zRSCodec.check  s     	9DdC   	$d##DZZdj11 	X 	XELL%48t~VVVWWWWr   c                    | j         }t          |dz            }|}|J|dk    rD||k    rt          d          t          ||z
  dz            }|rt          d||fz             ||fS |J|dk    rD||k    rt          d          t          ||dz  z
            }|rt          d||fz             ||fS |rt          d||fz             ||fS )a  Return the Singleton Bound for the current codec, which is the max number of errata (errors and erasures) that the codec can decode/correct.
        Beyond the Singleton Bound (too many errors/erasures), the algorithm will try to raise an exception, but it may also not detect any problem with the message and return 0 errors.
        Hence why you should use checksums if your goal is to detect errors (as opposed to correcting them), as checksums have no bounds on the number of errors, the only limitation being the probability of collisions.
        By default, return a tuple wth the maximum number of errors (2nd output) OR erasures (2nd output) that can be corrected.
        If errors or erasures (not both) is specified as argument, computes the remaining **simultaneous** correction capacity (eg, if errors specified, compute the number of erasures that can be simultaneously corrected).
        Set verbose to True to get print a report.r!   Nr   zESpecified number of errors or erasures exceeding the Singleton Bound!zEThis codec can correct up to %i errors and %i erasures simultaneouslyzDThis codec can correct up to %i errors and %i erasures independently)r   r   r   print)r   errorserasuresverboser   	maxerrorsmaxerasuress          r   	maxerratazRSCodec.maxerrata  s'    yQKK	HMM+%%&'noooT(]A-..I w]ajlt`uuvvvh&&&A++	!!&'nooodF1Ho..K w]agit`uuvvv;&& 	uX\egr[ssttt+%%r   )r   r   r   r<   r!   r)   TrO   )NNF)
r   r   r   __doc__r   r  r   r  r  r  r   r   r   r   r   :  s         !R !R !R !RF       -  -  -  -D	 	 	 	!& !& !& !& !& !&r   r   rI   )r!   r)   FF)r<   r!   r)   )r   )r   r   T)r   r!   )r   r!   Nr\   )r!   )r   r!   NF)3r  r   r   rJ   r   	NameErrorr   r&   range	Exceptionr   rK   rL   r   r-   r(   r;   rM   rR   rU   rX   rZ   r^   ra   rd   ru   r.   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   objectr   r   r   r   <module>r#     s  I IZ     
IJJ 	 	 	     	
FF   FFF	 	 	 	 	y 	 	 	 
QC#I			Cs8}}A A A4 4 4 4l;* ;* ;* ;*z      , , ,: : :
I I I6 6 6, , , ,\
 
 
 
A A A         4 4 4$                 >U U U U4 4 4 4l; ; ; ;z   	 	 	      (+A +A +A +AZ4A 4A 4A 4AlF F F FY& Y& Y& Y& Y&f Y& Y& Y& Y& Y&s    ##* 44