Esempio n. 1
0
def gf2_add(a, b):

    """Add two polynomials in GF(p)[x]

    Parameters
    ----------
    a : ndarray (uint8 or uint8) or list
        Addend polynomial's coefficients.
    b : ndarray (uint8 or uint8) or list
        Addend polynomial's coefficients.
    Returns
    -------
    q : ndarray of uint8
        Resulting polynomial's coefficients.


    Notes
    -----
    Rightmost element in the arrays is the leading coefficient of the polynomial.
    In other words, the ordering for the coefficients of the polynomials is like the one used in MATLAB while
    in Sympy, for example, the leftmost element is the leading coefficient.

    Examples
    ========

    >>> a = np.array([1,0,1], dtype="uint8")
    >>> b = np.array([1,1], dtype="uint8")
    >>> gf2_add(a,b)
    array([0, 1, 1], dtype=uint8)
"""
    a, b = check_type(a, b)

    a, b = strip_zeros(a), strip_zeros(b)

    N = len(a)

    D = len(b)

    if N == D:
        res = xor(a, b)

    elif N > D:

        res = np.concatenate((xor(a[:D], b), a[D:]))

    else:

        res = np.concatenate((xor(a, b[:N]), b[N:]))

    return strip_zeros(res)
    return res
Esempio n. 2
0
def gf2_mul(a, b):
    """Multiply polynomials in GF(2), FFT instead of convolution in time domain is used
       to speed up computation significantly.

    Parameters
    ----------
    a : ndarray (uint8 or bool) or list
        Multiplicand polynomial's coefficients.
    b : ndarray (uint8 or bool) or list
        Multiplier polynomial's coefficients.
    Returns
    -------
    q : ndarray of uint8
        Resulting polynomial's coefficients.

    Examples
    ========

    >>> a = np.array([1,0,1], dtype="uint8")
    >>> b = np.array([1,1,1], dtype="uint8")
    >>> gf2_mul(a,b)
    array([1, 1, 0, 1, 1], dtype=uint8)
"""

    fsize = len(a) + len(b) - 1

    fsize = 2**np.ceil(np.log2(fsize)).astype(
        int)  #use nearest power of two much faster

    fslice = slice(0, fsize)

    ta = np.fft.fft(a, fsize)
    tb = np.fft.fft(b, fsize)

    res = np.fft.ifft(ta * tb)[fslice].copy()

    k = np.mod(np.rint(np.real(res)), 2).astype('uint8')

    return strip_zeros(k)
Esempio n. 3
0
def mul(a, b):
    """Performs polynomial multiplication over GF2.

       Parameters
       ----------
       b : ndarray (uint8 or bool) or list
           Multiplicand polynomial's coefficients.
       a : ndarray (uint8 or bool) or list
           Multiplier polynomial's coefficients.
       Returns
       -------
       out : ndarray of uint8


       Notes
       -----
       This function performs exactly the same operation as gf2_mul but here instead of the fft, convolution
       in time domain is used. This is because this function must be used multiple times in gf2_xgcd and performing the
       fft in that instance introduced significant overhead.
    """

    out = np.mod(np.convolve(a, b), 2).astype("uint8")

    return strip_zeros(out)
Esempio n. 4
0
def gf2_div(dividend, divisor):
    """This function implements polynomial division over GF2.

    Given univariate polynomials ``dividend`` and ``divisor`` with coefficients in GF2,
    returns polynomials ``q`` and ``r``
    (quotient and remainder) such that ``f = q*g + r`` (operations are intended for polynomials in GF2).

    The input arrays are the coefficients (including any coefficients
    equal to zero) of the dividend and "denominator
    divisor polynomials, respectively.
    This function was created by heavy modification of numpy.polydiv.

    Parameters
    ----------
    dividend : ndarray (uint8 or bool)
        Dividend polynomial's coefficients.
    divisor : ndarray (uint8 or bool)
        Divisor polynomial's coefficients.

    Returns
    -------
    q : ndarray of uint8
        Quotient polynomial's coefficients.

    r : ndarray of uint8
        Quotient polynomial's coefficients.

    Notes
    -----
    Rightmost element in the arrays is the leading coefficient of the polynomial.
    In other words, the ordering for the coefficients of the polynomials is like the one used in MATLAB while
    in Sympy, for example, the leftmost element is the leading coefficient.


    Examples
    ========

    >>> x = np.array([1, 0, 1, 1, 1, 0, 1], dtype="uint8")
    >>> y = np.array([1, 1, 1], dtype="uint8")
    >>> gf2_div(x, y)
    (array([1, 1, 1, 1, 1], dtype=uint8), array([], dtype=uint8))

    """

    N = len(dividend) - 1
    D = len(divisor) - 1

    if dividend[N] == 0 or divisor[D] == 0:
        dividend, divisor = strip_zeros(dividend), strip_zeros(divisor)

    if not divisor.any():  # if every element is zero
        raise ZeroDivisionError("polynomial division")
    elif D > N:
        q = np.array([])
        return q, dividend

    else:
        u = dividend.astype("uint8")
        v = divisor.astype("uint8")

        m = len(u) - 1
        n = len(v) - 1
        scale = v[n].astype("uint8")
        q = np.zeros((max(m - n + 1, 1), ), u.dtype)
        r = u.astype(u.dtype)

        for k in range(0, m - n + 1):
            d = scale and r[m - k].astype("uint8")
            q[-1 - k] = d
            r[m - k - n:m - k + 1] = np.logical_xor(r[m - k - n:m - k + 1],
                                                    np.logical_and(d, v))

        r = strip_zeros(r)

    return q, r
Esempio n. 5
0
 def __repr__(self):
     return str(gf2_help_func.strip_zeros(self.array))