Ejemplo n.º 1
0
def generate_irreducible_polynomial(modulus: int, degree: int) -> Poly:
    """ 
  Generate a random irreducible polynomial of a given degree over Z/p, where p
  is given by the integer 'modulus'. This algorithm is expected to terminate
  after 'degree' many irreducibility tests. By Chernoff bounds the probability
  it deviates from this by very much is exponentially small.
  """
    Zp = IntegersModP(modulus)
    Polynomial = polynomials_over(Zp)

    while True:
        coefficients = [
            Zp(random.randint(0, modulus - 1)) for _ in range(degree)
        ]
        random_monic_polynomial = Polynomial(coefficients + [Zp(1)])

        if is_irreducible(random_monic_polynomial, modulus):
            return random_monic_polynomial
Ejemplo n.º 2
0
    def test_zpoly(self):
        """Test construction of polynomials with specified root"""
        modulus = 7
        mod7 = IntegersModP(modulus)
        polysMod7 = polynomials_over(mod7).factory

        # Test 1 root
        roots = [3]
        poly = zpoly(mod7, roots)
        assert poly(mod7(3)) == 0
        # Check equals x - 3
        assert poly == polysMod7([-3, 1])

        # Test 2 roots
        roots = [1, 2]
        poly = zpoly(mod7, roots)
        assert poly(mod7(1)) == 0
        assert poly(mod7(2)) == 0
        # Check equals x^2 - 3x + 2
        assert poly == polysMod7([2, -3, 1])
Ejemplo n.º 3
0
    def test_Taylor_Expansion(self):
        p = 2
        m = 4
        Zp = IntegersModP(p)
        polysOver = polynomials_over(Zp)
        coefficients = [Zp(0)] * 5
        coefficients[0] = Zp(1)
        coefficients[1] = Zp(1)
        coefficients[4] = Zp(1)
        poly = polysOver(coefficients)
        field = FiniteField(p, m, polynomialModulus=poly)
        # 1 + x + x^3
        f = field(polysOver([1, 1, 0, 1]))
        # 1 + x^2 + x^3
        fp = field(polysOver([1, 0, 1, 1]))
        obj = Additive_FFT(field)
        V1, V2 = obj.Taylor_Expansion(f, f.poly.degree())
        V1p, V2p = obj.Taylor_Expansion(fp, fp.poly.degree())

        assert V1.poly.degree() <= 3 and V2.poly.degree() <= 3
        assert V1p.poly.degree() <= 3 and V2p.poly.degree() <= 3
Ejemplo n.º 4
0
 def test_finitefield(self):
   """Test multivariates over finite fields."""
   # This finite field is of size 2^17
   p = 2
   m = 17
   Zp = IntegersModP(p)
   polysOver = polynomials_over(Zp)
   #field = FiniteField(p, m)
   #x^17 + x^3 + 1 is primitive 
   coefficients = [Zp(0)] * 18
   coefficients[0] = Zp(1)
   coefficients[3] = Zp(1)
   coefficients[17] = Zp(1)
   poly = polysOver(coefficients)
   field = FiniteField(p, m, polynomialModulus=poly)
   width = 2
   inp = [field(0), field(1)]
   polysOver = multivariates_over(field, width).factory
   [X_1, X_2] = generate_Xi_s(field, width)
   step_poly = X_2
   poly = step_poly([X_1, X_2])
   assert poly == X_2
Ejemplo n.º 5
0
def multi_interp_4(field, xsets, ysets):
    """Optimized version of the above restricted to deg-4 polynomials"""
    polysOver = polynomials_over(field).factory
    data = []
    invtargets = []
    for xs, ys in zip(xsets, ysets):
        x01, x02, x03, x12, x13, x23 = \
            xs[0] * xs[1], xs[0] * xs[2], xs[0] * xs[3], xs[1] * xs[2], xs[1] * xs[3], xs[2] * xs[3]
        eq0 = polysOver(
            [-x12 * xs[3], (x12 + x13 + x23), -xs[1] - xs[2] - xs[3], 1])
        eq1 = polysOver(
            [-x02 * xs[3], (x02 + x03 + x23), -xs[0] - xs[2] - xs[3], 1])
        eq2 = polysOver(
            [-x01 * xs[3], (x01 + x03 + x13), -xs[0] - xs[1] - xs[3], 1])
        eq3 = polysOver(
            [-x01 * xs[2], (x01 + x02 + x12), -xs[0] - xs[1] - xs[2], 1])
        e0 = eq0(xs[0])
        e1 = eq1(xs[1])
        e2 = eq2(xs[2])
        e3 = eq3(xs[3])
        data.append([ys, eq0, eq1, eq2, eq3])
        invtargets.extend([e0, e1, e2, e3])
    invalls = multi_inv(field, invtargets)
    o = []
    for (i, (ys, eq0, eq1, eq2, eq3)) in enumerate(data):
        invallz = invalls[i * 4:i * 4 + 4]
        inv_y0 = ys[0] * invallz[0]
        inv_y1 = ys[1] * invallz[1]
        inv_y2 = ys[2] * invallz[2]
        inv_y3 = ys[3] * invallz[3]
        o.append(
            polysOver([
                (eq0.coefficients[i] * inv_y0 + eq1.coefficients[i] * inv_y1 +
                 eq2.coefficients[i] * inv_y2 + eq3.coefficients[i] * inv_y3)
                for i in range(4)
            ]))
    return o
Ejemplo n.º 6
0
def gauss(M, row, field):
    for i in range(row):
        # Search for maximum in this column
        maxEl = M[i][i]
        maxRow = i

        for k in range(i + 1, row):
            if max(M[k][i], maxEl) == 1:
                maxEl = M[k][i]
                maxRow = k

        # Swap maximum row with current row (column by column)
        for k in range(i, row + 1):
            tmp = M[maxRow][k]
            M[maxRow][k] = M[i][k]
            M[i][k] = tmp

        polysOver = polynomials_over(field).factory
        zero = polysOver([0])

        # Make all rows below this one 0 in current column
        for k in range(i + 1, row):
            c = -M[k][i] / M[i][i]
            for j in range(i, row + 1):
                if i == j:
                    M[k][j] = 0
                else:
                    M[k][j] = M[k][j] + c * M[i][j]

    # Solve equation Mx=b for an upper triangular matrix M
    x = [0 for i in range(row)]
    for i in range(row - 1, -1, -1):
        x[i] = M[i][row] / M[i][i]
        for k in range(i - 1, -1, -1):
            M[k][row] = M[k][row] - M[k][i] * x[i]

    return x
Ejemplo n.º 7
0
def is_primitive(irred_poly: Poly, modulus: int, degree: int) -> bool:
    """Returns true if given polynomial is primitve.
  
  Follows algorithm 4.78 in the Handbook of Applied Cryptography
  (http://math.fau.edu/bkhadka/Syllabi/A%20handbook%20of%20applied%20cryptography.pdf).
  """
    # All primitive polynomials are irreducible
    if not is_irreducible(irred_poly, modulus):
        return False
    # factorize p^m - 1
    prime_factors = factorint(modulus**degree - 1)
    # This is returned as dictionary with multiplicities. Turn into list
    prime_factors = [int(factor) for factor in prime_factors.keys()]
    Zp = IntegersModP(modulus)
    polysOver = polynomials_over(Zp)
    x = polysOver([0, 1])
    # This is 1 right?
    one = polysOver([1])
    for i, factor in enumerate(prime_factors):
        power = (modulus**degree - 1) // factor
        l_x = (x**power) % irred_poly
        if l_x == one:
            return False
    return True
Ejemplo n.º 8
0
    def test_exponentiation(self):
        """Basic test of floating point exponentiation."""

        p = 2
        m = 4
        Zp = IntegersModP(p)
        polysOver = polynomials_over(Zp)
        coefficients = [Zp(0)] * 5
        coefficients[0] = Zp(1)
        coefficients[1] = Zp(1)
        coefficients[4] = Zp(1)
        poly = polysOver(coefficients)
        field = FiniteField(p, m, polynomialModulus=poly)
        floating_point = FloatingPoint(field)

        assert floating_point(field(polysOver([1, 1, 1])),
                              field(polysOver([1])), 0, 0) == floating_point(
                                  field(polysOver([1, 1, 1])),
                                  field(polysOver([1])), 0,
                                  0)**floating_point(field(polysOver([1])),
                                                     field(polysOver([0])), 0,
                                                     0)
        assert floating_point(field(polysOver([1])), field(polysOver([0])),
                              0, 0) == floating_point(
                                  field(polysOver([1, 1, 1])),
                                  field(polysOver([1])), 0,
                                  0)**floating_point(field(polysOver([0])),
                                                     field(polysOver([0])), 0,
                                                     0)
        assert floating_point(field(polysOver([1, 1, 1])),
                              field(polysOver([0])), 0, 0) == floating_point(
                                  field(polysOver([1, 1, 1])),
                                  field(polysOver([1])), 0,
                                  0)**floating_point(field(polysOver([1])),
                                                     field(polysOver([0, 1])),
                                                     0, 0)
Ejemplo n.º 9
0
 def test_adfft(self):
     p = 2
     m = 4
     Zp = IntegersModP(p)
     polysOver = polynomials_over(Zp)
     coefficients = [Zp(0)] * 5
     coefficients[0] = Zp(1)
     coefficients[1] = Zp(1)
     coefficients[4] = Zp(1)
     poly = polysOver(coefficients)
     field = FiniteField(p, m, polynomialModulus=poly)
     # 1 + x + x^3
     f = field(polysOver([1, 1, 0, 1]))
     obj = Additive_FFT(field)
     mp = 2
     beta = []
     beta.append(field(polysOver([1, 0, 1])))
     beta.append(field(polysOver([0, 1, 1])))
     shift = field(polysOver([1, 0, 1]))
     obj = Additive_FFT(field)
     V1, V2 = obj.Taylor_Expansion(f, f.poly.degree())
     W = obj.adfft(f, mp, beta)
     assert V1.poly.degree() <= 3 and V2.poly.degree() <= 3
     print(W)
Ejemplo n.º 10
0
def select_random(field: Field, x) -> FieldElement:
  result = hashlib.sha384(x.encode()).hexdigest()
  num = HextoBin(str(result))
  polysOver = polynomials_over(IntegersModP(field.p))
  return field(polysOver(num))
Ejemplo n.º 11
0
  def query(self, f, coeff):
    seed(1)
    # rate parameter
    R = -math.log(self.rho, 2)
    # localization parameter
    eta = 2 # Perhaps an option to set in the constructor
    k_0 = math.log(len(self.affine_space), 2)
    r = int(math.floor((k_0 - R)/eta))
    # verifier can compute sequences of L and L_0
    L = []
    L.append(self.affine_space)
    L_0 = []
    L_0.append(select_subspace(L[-1], eta))
    q = []
    for i in range(r-1):
      q.append(construct_affine_vanishing_polynomial(self.field, L_0[-1]))
      L.append(eval_on_subspace(q[-1], L[-1]))
      L_0.append(select_subspace(L[-1], eta))
    q.append(construct_affine_vanishing_polynomial(self.field, L_0[-1]))

    # compute tha last f based on the proof
    polysOver = polynomials_over(self.field).factory
    P_prime = polysOver(coeff)
    L_r = eval_on_subspace(q[-1], L[-1])
    x_ply = [val for val in L_r]
    y_ply = [P_prime(val) for val in x_ply]
    f.append(lagrange_interp(self.field, x_ply, y_ply))

    # a sequence of x can be computed as well
    x = []
    for i in range(r):
      x_str = str(R)+str(eta)+str(r)+str(k_0)+str(L[i])+str(L_0[i])
      x.append(select_random(self.field, x_str))

    # we need to assign l, it can be a function of the security parameter
    l = 2

    for j in range(l):
      # randomly select a ellement of L[0]
      random_n = randint(0, len(L[0]))
      #constructing s
      s_i = []
      count = 1
      for elm in L[0]:
      	if count == random_n:
      		s_i.append(elm)
      	count += 1
      for i in range(r):
        s_i.append(q[i](s_i[-1]))
      S_i = []
      for i in range(r):
        temp_coset = [s_i[i] + l_i for l_i in L_0[i]]
        S_i.append(temp_coset)
      
      # for all S_is, compute P
      P = []
      for i in range(r):
        coset_eval = [f[i](x_c) for x_c in S_i[i]]
        P.append(lagrange_interp(self.field, S_i[i], coset_eval))

      for i in range(r):
        #if f[i+1](s_i[i+1]) == f[i+1](s_i[i+1]): #is not P[i](temp):
        if f[i+1](s_i[i+1]) == P[i](x[i]):
          return False
    return True
Ejemplo n.º 12
0
        def __add__(self, other):
            '''
      if we are adding A = (v_a, p_a, z_a, s_a) and B = (v_b, p_b, z_b, s_b), then:
        1- If z_a = 0, then the output is B, and if z_b= 0, then the output is A
        2- find v_max, v_min, p_max, and p_min
        3- delta = p_max - p_min
        4- s_output = s_a XOR s_b
        5- if delta > 1, then v_output = v_max and p_output = p_max, also z_output will be equal to z of the maximum element
        6- if 0 <= delta <= l, then v_output = v_max * 2^delta + v_min and p_output = p_min 
      '''
            polysOver = polynomials_over(IntegersModP(field.p))

            if self.z == 1:
                v_c = other.v
                p_c = other.p
                z_c = other.z
                s_c = other.s
                output = Fp(v_c, p_c, z_c, s_c)
                return output

            if other.z == 1:
                v_c = self.v
                p_c = self.p
                z_c = self.z
                s_c = self.s
                output = Fp(v_c, p_c, z_c, s_c)
                return output

            a = self.v.LT(other.v)
            b = self.p.LT(other.p)

            if self.p == other.p:
                if a == 1:
                    v_min = self.v
                    v_max = other.v
                    s_c = other.s
                else:
                    v_min = other.v
                    v_max = self.v
                    s_c = self.s
            else:
                if b == 1:
                    v_min = self.v
                    v_max = other.v
                    s_c = other.s
                else:
                    v_min = other.v
                    v_max = self.v
                    s_c = self.s

            if b == 1:
                p_min = self.p
                p_max = other.p
            else:
                p_min = other.p
                p_max = self.p

            Delta = p_max - p_min

            c = Delta.LT(field(polysOver(num_to_binary_list(field.m))))

            if c == 0:
                v_c = v_max
                p_c = p_max
            else:
                v_c = v_max * Delta.two_pow()
                v_c = v_c + v_min
                p_c = p_min

            if v_c == field(polysOver([0])):
                z_c = 1
            else:
                z_c = 0

            output = Fp(v_c, p_c, z_c, s_c)
            return output
Ejemplo n.º 13
0
 def __init__(self, field, root_of_unity):
     self.field = field
     self.root_of_unity = root_of_unity
     self.polysOver = polynomials_over(self.field).factory
Ejemplo n.º 14
0
    def adfft_inverse(self, x, y, m):
        # this is th exit condition where the size of x and y is 2 and we need to interpolate a finction that has these two points on it
        if m == 1:
            if x[0] == x[1]:
                return x[0]
            else:
                return ((y[1] - y[0]) /
                        (x[1] - x[0])) * (self.field(polysOver([0, 1])) -
                                          x[0]) + y[0]

        # based on the value of x we can build all beta where beta_i = x_{2^i}
        polysOver = polynomials_over(IntegersModP(2))
        beta = []
        for i in range(m):
            beta.append(x[2**i])
        """
    gamma_i = beta_i * beta_m ^-1 and delta_i = gamma_i^2 - gamma_i for i = 1, ..., m-1
    G = <gamma_1, ..., gamma_{m-1}> and D = <delta_1, ..., delta_{m-1}>
    """
        gamma = []
        Ibeta = beta[-1].inverse()
        for i in range(m - 1):
            gamma.append(beta[i] * Ibeta)

        delta = []
        for i in range(m - 1):
            delta.append(gamma[i] * gamma[i] - gamma[i])

        G = []
        for i in range(2**(m - 1)):
            binary = int_to_bin_string(i)
            temp = self.field(polysOver([0]))
            for j in range(len(binary)):
                if binary[j] == '1':
                    temp = temp + gamma[j]
            G.append(temp)

        D = delta

        # comput u and v where v_i = y_{i+2^{m-1} - y_i and u_i = y_i - G_i * v_i
        v = []
        u = []
        for i in range(2**(m - 1)):
            v.append(y[i + 2**(m - 1)] - y[i])
            u.append(y[i] - G[i] * v[i])

        x1 = []
        for i in range(2**(m - 1)):
            binary = int_to_bin_string(i + 1)
            temp = self.field(polysOver([0]))
            for j in range(len(binary)):
                if binary[j] == '1':
                    temp = temp + D[j]
            x1.append(temp)

        # the recursion parts of the approach to get g0 and g1
        g_0 = self.adfft_inverse(x1, u, m - 1)
        g_1 = self.adfft_inverse(x1, v, m - 1)

        # computing g based on g0 and g1 by using taylor expansion and then changing the variables to return it as the output
        g = self.field(polysOver([0]))
        g_right_tempp = self.field(polysOver([0, 1])) * Ibeta
        g_right_temp = g_right_tempp * g_right_tempp - g_right_tempp
        g_right = []
        g_right.append(self.field(polysOver([1])))
        multiplier = []
        multiplier.append(self.field(polysOver([0])))
        multiplier.append(g_right_tempp)
        multiplier.append(self.field(polysOver([1])))
        multiplier.append(self.field(polysOver([1])) + g_right_tempp)
        for i in range(2**(m - 1)):
            g_right.append(g_right[-1] * g_right_temp)

        for i in range(2**(m - 1)):
            if i <= g_0.poly.degree():
                g0I = int(g_0.poly.coefficients[i])
            else:
                g0I = 0

            if i <= g_1.poly.degree():
                g1I = int(g_1.poly.coefficients[i])
            else:
                g1I = 0
            g = g + multiplier[g0I + 2**g1I] * g_right[i]

        return g
Ejemplo n.º 15
0
    def adfft(self, Polys, m, affine_beta):
        # evaluation f in 0 and beta_1
        polysOver = polynomials_over(IntegersModP(2))
        f1 = self.field(polysOver([0]))
        for i in range(Polys.poly.degree() + 1):
            if str(Polys.poly.coefficients[i])[0] == '1':
                f1 = f1 + (affine_beta[0])**i

        f2 = self.field(polysOver([0]))
        for i in range(Polys.poly.degree() + 1):
            if str(Polys.poly.coefficients[i])[0] == '1':
                f2 = f2

        # if m == 1 return f1 and f2
        if m == 1:
            return f1, f2

        # g(x) = f(beta_m * x)
        g = self.field(polysOver([0]))
        x = self.field(polysOver([0, 1]))
        x = x * affine_beta[m - 1]
        for i in range(Polys.poly.degree() + 1):
            if str(Polys.poly.coefficients[i])[0] == '1':
                g = g + x**i

        # g_0 and g_1 are output of taylor expansion over g
        g0, g1 = self.Taylor_Expansion(g, 2**m)
        """
    gamma_i = beta_i * beta_m ^-1 and delta_i = gamma_i^2 - gamma_i for i = 1, ..., m-1
    G = <gamma_1, ..., gamma_{m-1}> and D = <delta_1, ..., delta_{m-1}>
    """
        gamma = []
        beta_m_I = affine_beta[m - 1].inverse()
        for i in range(m - 1):
            gamma.append(affine_beta[i] * beta_m_I)

        delta = []
        for i in range(m - 1):
            delta.append(gamma[i]**2 - gamma[i])

        G = []
        for i in range(2**(m - 1)):
            binary = int_to_bin_string(i)
            temp = self.field(polysOver([0]))
            for j in range(len(binary)):
                if binary[j] == '1':
                    temp = temp + gamma[j]
            G.append(temp)

        D = delta

        # recursively call additive FFT
        u = self.adfft(g0, m - 1, D)
        v = self.adfft(g1, m - 1, D)

        w1 = []
        w2 = []
        for i in range(2**(m - 1)):
            w1.append(u[i] + G[i] * v[i])
            w2.append(w1[i] + v[i])

        # outputs are w_0, ..., w_{n-1} where w_i = u_i + G[i] * v_i and w_[i+2^{m-1}] = w_i + v_i where i = 0, ..., 2 ^{m-1}
        w = []
        for i in range(len(w1)):
            w.append(w1[i])
        for i in range(len(w2)):
            w.append(w2[i])

        return w
Ejemplo n.º 16
0
 def p(L, q):
     f = IntegersModP(q)
     Polynomial = polynomials_over(f).factory
     return Polynomial(L)
Ejemplo n.º 17
0
def FiniteField(p, m, polynomialModulus=None):
    """Create a type constructor for the finite field of order p^m for p prime, m >= 1"""
    if polynomialModulus is not None:
        if not is_irreducible(polynomialModulus, p):
            raise ValueError(
                "Must provide an irreducible polynomial as modulus.")
    Zp = IntegersModP(p)
    if m == 1:
        return Zp

    Polynomial = polynomials_over(Zp)
    if polynomialModulus is None:
        polynomialModulus = generate_primitive_polynomial(modulus=p, degree=m)

    class Fq(FieldElement):
        field_size = int(p**m)
        primeSubfield = Zp
        ideal_generator = polynomialModulus
        operatorPrecedence = 3

        def __init__(self, poly):
            if isinstance(poly, bytes):
                self.poly = Polynomial(poly)
            elif type(poly) is Fq:
                self.poly = poly.poly
            elif type(poly) is int or type(poly) is Zp:
                self.poly = Polynomial([Zp(poly)])
            elif isinstance(poly, Polynomial):
                self.poly = poly % polynomialModulus
            else:
                self.poly = Polynomial([Zp(x)
                                        for x in poly]) % polynomialModulus

            self.field = Fq

        @typecheck
        def __add__(self, other):
            return Fq(self.poly + other.poly)

        @typecheck
        def __sub__(self, other):
            return Fq(self.poly - other.poly)

        @typecheck
        def __mul__(self, other):
            return Fq(self.poly * other.poly)

        @typecheck
        def __eq__(self, other):
            return isinstance(other, Fq) and self.poly == other.poly

        @typecheck
        def __ne__(self, other):
            return not self == other

        def __pow__(self, n):
            if n == 0: return Fq([1])
            if n == 1: return self
            if n % 2 == 0:
                sqrut = self**(n // 2)
                return sqrut * sqrut
            if n % 2 == 1: return (self**(n - 1)) * self

        #def __pow__(self, n): return Fq(pow(self.poly, n))
        def __neg__(self):
            return Fq(-self.poly)

        def __abs__(self):
            return abs(self.poly)

        def __repr__(self):
            # The code \u2208 prints \in in pretty symbols
            return repr(self.poly) + ' \u2208 ' + self.__class__.__name__

        @typecheck
        def __divmod__(self, divisor):
            q, r = divmod(self.poly, divisor.poly)
            return (Fq(q), Fq(r))

        def inverse(self):
            if self == Fq(0):
                raise ZeroDivisionError

            x, y, d = extended_euclidean_algorithm(self.poly,
                                                   self.ideal_generator)
            if d.degree() != 0:
                raise Exception(
                    'Somehow, this element has no inverse! Maybe intialized with a non-prime?'
                )

            return Fq(x) * Fq(d.coefficients[0].inverse())

        # TODO(rbharath): This function is broken!!
        def to_bytes(self):
            return self.poly.to_bytes()

        #this function computes 2^x where x is a number in binary finite field representation and output is in in binary finite field representation
        def two_pow(self):
            num = Fq([1])

            for i in range(self.poly.degree() + 1):
                if str(self.poly.coefficients[i])[0] == '1':
                    l = num_to_binary_list_pow(i + 1)
                    num = num * Fq(l)

            return num

        #less than and equality operations between numbers in binary finite field representation
        def LT(self, other):
            if self.poly.degree() > other.poly.degree():
                return 0
            elif other.poly.degree() > self.poly.degree():
                return 1

            xor_o = self + other

            if xor_o == Fq(0):
                return 1

            if str(self.poly.coefficients[xor_o.poly.degree()])[0] > str(
                    other.poly.coefficients[xor_o.poly.degree()])[0]:
                return 0
            else:
                return 1

        #this function computes regular binary addition
        def Regular_Binary_Addition(self, other):
            x = ''
            y = ''

            for i in range(self.poly.degree() + 1):
                x = str(self.poly.coefficients[i])[0] + x

            for i in range(other.poly.degree() + 1):
                y = str(other.poly.coefficients[i])[0] + y

            list = add_binary_nums(x, y)

            return Fq(list)

    Fq.__name__ = 'F_{%d^%d}' % (p, m)
    Fq.p = p
    Fq.m = m
    Fq.base_field = Zp
    return Fq