Exemple #1
0
    def coerce(self, other: object) -> CurvePolynomialElement:
        """
        Attempts to coerce other into an element of the algebra.

        Parameters:
            other (object): Object to coerce.
        
        Returns:
            CurvePolynomialElement: Coerced element.
        """
        if type(other) is CurvePolynomialElement:
            return other

        if type(other) is tuple:
            x_poly = other[0]
            y_poly = other[1] or self.poly_ring.zero()
        else:
            x_poly = other
            y_poly = self.poly_ring.zero()

        coerced = []
        for poly in [x_poly, y_poly]:
            if type(poly) is list:
                coerced.append(Polynomial(poly, self.poly_ring.ring))

            elif issubclass(type(poly), Polynomial):
                coerced.append(poly)

            elif type(poly) is int:
                coerced.append(Polynomial([poly], self.poly_ring.ring))

            else:
                raise CoercionException('Coercion failed')

        return CurvePolynomialElement(*coerced, ring=self)
Exemple #2
0
    def __init__(self, p: int, n: int = 1, reducing_poly: Polynomial = None):
        """
        Parameters:
            p                    (int): Prime.
            n                    (int): Exponent.
            reducing_poly (Polynomial): Polynomial to reduce the `PolynomialRing`.
        """
        from samson.math.algebra.rings.integer_ring import ZZ

        assert is_prime(p)
        self.p = p
        self.n = n

        self.internal_ring = ZZ / ZZ(p)

        if not reducing_poly:
            if n == 1:
                reducing_poly = Polynomial([0, 1], self.internal_ring)
            else:
                for c in itertools.product(range(p), repeat=n):
                    poly = Polynomial((1, *c)[::-1], self.internal_ring)
                    if poly.is_irreducible():
                        reducing_poly = poly
                        break

        self.reducing_poly = reducing_poly
        poly_ring = self.reducing_poly.ring
        self.internal_field = poly_ring / poly_ring(reducing_poly)
    def coerce(self, other: object) -> Polynomial:
        """
        Attempts to coerce other into an element of the algebra.

        Parameters:
            other (object): Object to coerce.
        
        Returns:
            Polynomial: Coerced element.
        """
        # Handle grounds
        type_o = type(other)
        if type_o is int or hasattr(other, 'ring') and other.ring == self.ring:
            other  = [other]
            type_o = type(other)

        if type_o is list or type_o is dict:
            return Polynomial(other, coeff_ring=self.ring, ring=self, symbol=self.symbol)

        elif type_o is Polynomial and other.ring == self:
            return other

        elif type_o is Symbol and other.var.ring == self:
            return other.var

        raise CoercionException('Coercion failed')
Exemple #4
0
    def __init__(self, seed: int, polynomial: Polynomial):
        """
        Parameters:
            seed              (int): Initial value.
            polynomial (Polynomial): Either a `Polynomial` or an integer that represents the polynomal.
        """
        self.state = seed

        if type(polynomial) is Polynomial:
            polynomial = poly_to_int(polynomial)

        self.polynomial = polynomial
        self.mask = 1
        self.wrap_around_mask = 2**polynomial.bit_length() - 1
        self.state &= self.wrap_around_mask

        poly_mask = polynomial
        while poly_mask:
            if poly_mask & self.mask:
                poly_mask ^= self.mask

            if not poly_mask:
                break

            self.mask <<= 1
Exemple #5
0
 def one(self) -> CurvePolynomialElement:
     """
     Returns:
         CurvePolynomialElement: '1' element of the algebra.
     """
     return CurvePolynomialElement(
         Polynomial([self.poly_ring.ring(1)], self.poly_ring.ring), None,
         self)
Exemple #6
0
def invert_poly(f_poly: Polynomial, R_poly: Polynomial, p: int) -> Polynomial:
    """
    Inverts a polynomial `f_poly` over `R_poly` in GF(p).

    Parameters:
        f_poly (Polynomial): Polynomial to be inverted.
        R_poly (Polynomial): Polynomial to be inverted _over_.
        p             (int): Integer modulus.

    Returns:
        Polynomial: Inverted polynomial.
    """
    power_of_two = is_power_of_two(p)
    if is_prime(p) or power_of_two:
        if power_of_two:
            Z_p = ZZ / ZZ(2)
        else:
            Z_p = ZZ / ZZ(p)

        f_poly_p = Polynomial([(idx, Z_p[coeff])
                               for idx, coeff in f_poly.coeffs], Z_p)
        R_poly_p = Polynomial([(idx, Z_p[coeff])
                               for idx, coeff in R_poly.coeffs], Z_p)

        inv_poly = mod_inv(f_poly_p, R_poly_p)
        inv_poly = Polynomial([(idx, ZZ[int(coeff)])
                               for idx, coeff in inv_poly.coeffs], ZZ)

        if power_of_two:
            for _ in range(int(math.log(p, 2))):
                inv_poly = (2 * inv_poly) - (f_poly * (inv_poly**2))
                inv_poly = (inv_poly % R_poly).trunc(p)

    else:
        raise Exception(
            f"Polynomial not invertible in Z_{p}. NTRU: p and q must be prime or power of two."
        )

    return inv_poly
def gcm_to_poly(ad, ciphertext, tag):
    l = (len(ad) << (3 + 64)) | (len(ciphertext) << 3)

    ct_ints = [
        chunk.int()
        for chunk in ciphertext.pad_congruent_right(16).chunk(16)[::-1]
    ]
    ad_ints = [
        chunk.int() for chunk in ad.pad_congruent_right(16).chunk(16)[::-1]
    ]

    return Polynomial(
        [int_to_elem(coeff) for coeff in [tag.int(), l, *ct_ints, *ad_ints]])
Exemple #8
0
def rand_poly(length: int,
              len_non_zeroes: int,
              neg_ones_mod: int = 0) -> Polynomial:
    """
    Generates a random polynomial.

    Parameters:
        length         (int): Desired length of polynomial.
        len_non_zeroes (int): Number of non-zero values in polynomial.
        neg_ones_mod   (int): Modifier that reduces the number of -1 coefficients.
    
    Returns:
        Polynomial: Random polynomial.
    """
    poly_arr = [0] * ((length - len_non_zeroes * 2) + neg_ones_mod)
    poly_arr += [1] * len_non_zeroes
    poly_arr += [-1] * (len_non_zeroes - neg_ones_mod)

    shuffle(poly_arr)

    return Polynomial(poly_arr, ZZ)
 def one(self) -> Polynomial:
     """
     Returns:
         Polynomial: '1' element of the algebra.
     """
     return Polynomial([self.ring.one()], coeff_ring=self.ring, ring=self, symbol=self.symbol)