def test_lagrange_interp(self): """Test lagrangian interpolation.""" modulus = 7 mod7 = IntegersModP(modulus) polysOverMod = polynomials_over(mod7).factory xs = [mod7(1), mod7(6)] ys = [mod7(1), mod7(6)] interp = lagrange_interp(mod7, xs, ys) # interp should equal x assert interp == polysOverMod([0, 1]) xs = [mod7(1), mod7(6)] ys = [mod7(0), mod7(0)] interp = lagrange_interp(mod7, xs, ys) # interp should equal 0 assert interp == polysOverMod([0]) # Test lagrange interp over general finite field Z5 = IntegersModP(5) F25 = FiniteField(5, 2) polysOverF = polynomials_over(F25).factory xs = [F25(1), F25(2)] ys = [F25(1), F25(2)] interp = lagrange_interp(F25, xs, ys) # interp should equal x assert interp == polysOverF([F25(0), F25(1)])
def test_multi_inv(self): """Test of faster multiple inverse method.""" # 6^-1 = 6 modulus = 7 mod7 = IntegersModP(modulus) outs = multi_inv(mod7, [mod7(6), mod7(6), mod7(6)]) assert outs == [6, 6, 6] # 1^-1 = 1 outs = multi_inv(mod7, [mod7(6), mod7(1), mod7(6)]) assert outs == [6, 1, 6] outs = multi_inv(mod7, [mod7(0), mod7(1), mod7(1)]) modulus = 2**256 - 2**32 * 351 + 1 field = IntegersModP(modulus) ## Root of unity such that x^precision=1 G2 = field(7)**((modulus - 1) // 4096) ### Powers of the higher-order root of unity xs = get_power_cycle(G2, field) xs_minus_1 = [x - 1 for x in xs] xs_minus_1_inv = multi_inv(field, xs_minus_1) # Skip 0 since xs_minus_1[0] == 0 for i in range(1, 5): assert xs_minus_1[i] * xs_minus_1_inv[i] == 1 steps = 512 precision = 4096 z_evals = [xs[(i * steps) % precision] - 1 for i in range(precision)] z_inv = multi_inv(field, z_evals) for i in range(1, 5): assert z_evals[i] * z_inv[i] == 1
def test_modulus(self): """Basic test of polynomial modulus.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # modulus assert p([]) == p([1, 7, 49]) % p([7]) assert p([-7]) == p([-3, 10, -5, 3]) % p([1, 3])
def test_equality(self): """Basic test of polynomial equality.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # equality assert p([]) == p([]) assert p([1, 2]) == p([1, 2]) assert p([1, 2, 0]) == p([1, 2, 0, 0])
def test_multiplication(self): """Basic test of polynomial multiplication.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # multiplication assert p([1, 2, 1]) == p([1, 1]) * p([1, 1]) assert p([2, 5, 5, 3]) == p([2, 3]) * p([1, 1, 1]) assert p([0, 7, 49]) == p([0, 1, 7]) * p([7])
def test_subtraction(self): """Basic test of polynomial subraction.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # subtraction assert p([1, -2, 3]) == p([1, 0, 3]) - p([0, 2]) assert p([1, 2, 3]) == p([1, 2, 3]) - p([]) assert p([-1, -2, -3]) == p([]) - p([1, 2, 3])
def test_addition(self): """Basic test of polynomial addition.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # addition assert p([1, 2, 3]) == p([1, 0, 3]) + p([0, 2]) assert p([1, 2, 3]) == p([1, 2, 3]) + p([]) assert p([5, 2, 3]) == p([4]) + p([1, 2, 3]) assert p([1, 2]) == p([1, 2, 3]) + p([0, 0, -3])
def test_division_more(self): """More division tests""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory assert polysOverQ([Fraction(1, 7), 1, 7]) == polysOverQ([1, 7, 49]) / polysOverQ([7]) assert polysMod5([1 / Mod5(7), 1, 7]) == polysMod5([1, 7, 49]) / polysMod5([7]) assert polysMod11([1 / Mod11(7), 1, 7]) == polysMod11([1, 7, 49]) / polysMod11([7])
def test_adfft_inverse(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) mp = 3 x = [] y = [] x.append(field(polysOver([1, 0, 0]))) y.append(field(polysOver([1, 1]))) x.append(field(polysOver([1, 1, 1]))) y.append(field(polysOver([0, 0, 1]))) x.append(field(polysOver([1, 0]))) y.append(field(polysOver([0, 1]))) x.append(field(polysOver([1, 1]))) y.append(field(polysOver([0, 1, 1]))) x.append(field(polysOver([1, 1, 1]))) y.append(field(polysOver([1, 0, 1]))) x.append(field(polysOver([1, 0, 0]))) y.append(field(polysOver([1, 1, 1]))) x.append(field(polysOver([1]))) y.append(field(polysOver([0]))) x.append(field(polysOver([1]))) y.append(field(polysOver([1, 1]))) obj = Additive_FFT(field) f = obj.adfft_inverse(x, y, mp)
def test_merkletree_zmodp(self): """Constructs merkle tree of field elements.""" modulus = 7 mod7 = IntegersModP(modulus) l = [mod7(i) for i in range(128)] m_tree = merkelize(l) assert len(m_tree) == 256
def test_mod_large_gcd(self): """Test that GCD works with a larger prime.""" ModHuge = IntegersModP(9923) assert ModHuge(38) == gcd(ModHuge(4864), ModHuge(3458)) assert (ModHuge(32), ModHuge(-45), ModHuge(38)) == extended_euclidean_algorithm( ModHuge(4864), ModHuge(3458))
def test_mod_7_gcd(self): """Test that the GCD works in mod-7 arithmetic.""" Mod7 = IntegersModP(7) # TODO(rbharath): Why are these modular equations right? Is there a way to # do simple mental arithmetic to calculate these values? assert Mod7(6) == gcd(Mod7(6), Mod7(14)) assert Mod7(2) == gcd(Mod7(6), Mod7(9))
def test_get_witness(self): """Test that a witness can be extracted from the APR instance. # TODO(rbharath): Make this test non-trivial to check the witness has # required properties. """ width = 2 # Set the field small in tests since primitive polynomial generation is slow. p = 2 m = 17 Zp = IntegersModP(p) polysOver = polynomials_over(Zp) #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) steps = 3 extension_factor = 8 inp = [field(0), field(1)] polysOver = multivariates_over(field, width).factory X_1 = polysOver({(1, 0): field(1)}) X_2 = polysOver({(0, 1): field(1)}) step_polys = [X_2, X_1 + X_2] air = AIR(field, width, inp, steps, step_polys, extension_factor) apr = APR(air) # TODO(rbharath): Uncomment this and reactivate it witness = apr.generate_witness()
def test_multiplication(self): """Basic test of floating point multiplication.""" 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([0])), field(polysOver([ 0 ])), 0, 0) == floating_point(field(polysOver( [0])), field(polysOver([0])), 0, 0) * floating_point( field(polysOver([1, 1, 1])), field(polysOver([1, 1, 1])), 0, 0) assert floating_point(field(polysOver([0])), field(polysOver( [0])), 0, 0) == floating_point(field(polysOver( [0])), field(polysOver([0])), 0, 0) * floating_point( field(polysOver([0])), field(polysOver([0])), 0, 0) assert floating_point(field(polysOver([1, 1, 1])), field(polysOver( [1])), 0, 0) == floating_point(field(polysOver( [1])), field(polysOver([0])), 0, 0) * floating_point( field(polysOver([1, 1, 1])), field(polysOver([1])), 0, 0) assert floating_point(field(polysOver([ 1, 1, 1, 1 ])), field(polysOver([ 1, 0, 1 ])), 0, 1) == floating_point(field(polysOver( [1, 0, 1])), field(polysOver([1, 1])), 0, 1) * floating_point( field(polysOver([1, 1])), field(polysOver([1, 1, 1])), 0, 0)
def test_gauss(self): """Tests the construction of gaussian elimination.""" p = 2 m = 2 t = 2 Zp = IntegersModP(p) basePolys = polynomials_over(Zp) M = [] row = 3 field = FiniteField(p, m) M.append([ basePolys([1, 1]), basePolys([0]), basePolys([0, 1]), basePolys([1]) ]) M.append([ basePolys([1]), basePolys([0]), basePolys([0, 1]), basePolys([1, 1]) ]) M.append([ basePolys([1, 0]), basePolys([0, 1]), basePolys([0, 1]), basePolys([1]) ]) result = gauss(M, row, field) assert result == [basePolys([1]), basePolys([1]), basePolys([1])]
def test_construct_affine_vanishing_poly_Moore(self): """Tests the construction of an affine vanishing poly.""" p = 2 m = 2 # Degree of space we construct t = 2 Zp = IntegersModP(p) basePolys = polynomials_over(Zp) # g g = basePolys([0, 1]) field = FiniteField(p, m) ################################################ print("field") print(field) print("field.__name__") print(field.__name__) ################################################ H0 = AffineSpace(Zp, [g**k for k in range(t - 1)]) ################################################ print("field") print(field) ################################################ Z_H0 = construct_affine_vanishing_polynomial_Moore(field, H0) print(len(H0)) for i in H0: print(Z_H0(field(i)))
def __truediv__(self, other): ''' if we are dividing A = (v_a, p_a, z_a, s_a) and B = (v_b, p_b, z_b, s_b), then: 1- z_output = z_a 2- s_output = s_a XOR s_b 3- if z_output == 1, then v_output = 0; otherwise, v_output = v_a * inverse(v_b) 4- if z_output == 1, then p_output = 0; otherwise, p_output = p_a - p_b + l ''' polysOver = polynomials_over(IntegersModP(field.p)) if other.z == 1: raise ZeroDivisionError if other.v == field(polysOver([0])): raise ZeroDivisionError z_c = self.z | other.z s_c = self.s ^ other.s if z_c == 1: v_c = field(polysOver([0])) else: v_c = self.v / other.v if z_c == 1: p_c = field(polysOver([0])) else: p_c = self.p - other.p p_c = p_c + num_to_binary_list( self.v.poly.degree() + other.v.inverse().poly.degree() - (self.v.m - 1)) output = Fp(v_c, p_c, z_c, s_c) return output
def test_construct_multivariate_dirac_delta(self): """Tests the construct of the multivariate dirac delta.""" modulus = 3 mod7 = IntegersModP(modulus) n = 3 # Let's make polynomials in (Z/7)[x, y, z] multi = multivariates_over(mod7, n).factory # Let's generate the dirac delta at x=0, y=0, z=0 values = [mod7(0), mod7(0), mod7(0)] dirac = construct_multivariate_dirac_delta(mod7, values, n) # The dirac delta should be 1 at x=0, y=0, z=0 assert dirac((0, 0, 0)) == 1 # It should be 0 elsewhere assert dirac((1, 0, 0)) == 0 assert dirac((0, 1, 0)) == 0 assert dirac((0, 0, 1)) == 0 # Let's generate the dirac delta at x=1, y=1, z=1 values = [mod7(1), mod7(1), mod7(1)] dirac = construct_multivariate_dirac_delta(mod7, values, n) # The dirac delta should be 1 at x=1, y=1, z=1 assert dirac((1, 1, 1)) == 1 # It should be 0 elsewehre assert dirac((1, 0, 0)) == 0 assert dirac((0, 1, 0)) == 0 assert dirac((0, 0, 1)) == 0
def __mul__(self, other): ''' if we are multiplying A = (v_a, p_a, z_a, s_a) and B = (v_b, p_b, z_b, s_b), then: 1- z_output = z_a OR z_b 2- s_output = s_a XOR s_b 3- if z_output == 1, then v_output = 0; otherwise, v_output = v_a * v_b 4- if z_output == 1, then p_output = 0; otherwise, p_output = p_a + p_b + l ''' polysOver = polynomials_over(IntegersModP(field.p)) z_c = self.z | other.z s_c = self.s ^ other.s if z_c == 1: v_c = field(polysOver([0])) else: v_c = self.v * other.v if z_c == 1: p_c = field(polysOver([0])) else: p_c = self.p + other.p p_c = p_c + num_to_binary_list(self.v.poly.degree() + self.v.poly.degree() - (self.v.m - 1)) output = Fp(v_c, p_c, z_c, s_c) return output
def test_binary_air(self): """"Test construction of a binary AIR.""" steps = 512 - 1 # This finite field is of size 2^17 p = 2 m = 17 # TODO(rbharath): Extension factor shouldn't be an # argument. extension_factor = 8 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_polys = [X_2, X_1 + X_2] air = AIR(field, width, inp, steps, step_polys, extension_factor)
def is_irreducible(polynomial: Poly, p: int) -> bool: """is_irreducible: Polynomial, int -> bool Determine if the given monic polynomial with coefficients in Z/p is irreducible over Z/p where p is the given integer Algorithm 4.69 in the Handbook of Applied Cryptography """ ZmodP = IntegersModP(p) if polynomial.ring is not ZmodP: raise TypeError( "Given a polynomial that's not over %s, but instead %r" % (ZmodP.__name__, polynomial.ring.__name__)) poly = polynomials_over(ZmodP).factory x = poly([0, 1]) power_term = x is_unit = lambda p: p.degree() == 0 for _ in range(int(polynomial.degree() / 2)): power_term = power_term.powmod(p, polynomial) gcd_over_Zmodp = gcd(polynomial, power_term - x) if not is_unit(gcd_over_Zmodp): return False return True
def test_compress_fri(self): """ Basic tests of compression """ degree = 4 modulus = 2**256 - 2**32 * 351 + 1 field = IntegersModP(modulus) polysOver = polynomials_over(field).factory # 1 + 2x + 3x^2 + 4 x^3 mod 31 poly = polysOver([val for val in range(degree)]) # TODO(rbharath): How does the choice of the n-th root of # unity make a difference in the fft? # A root of unity is a number such that z^n = 1 # This provides us a 6-th root of unity (z^6 = 1) root_of_unity = field(3)**((modulus - 1) // 8) fri = SmoothSubgroupFRI(field) proof = fri.generate_proximity_proof(poly, root_of_unity, degree, modulus) compressed = compress_fri(proof) length = bin_length(compressed) print("bin_length: %d" % length) # TODO(rbharath): This is a lame test that checks length # of compressed proof is > 0. Need better unit test. assert length > 0
def test_apr_constructor(self): """Test that the APR class can be initialized.""" width = 2 # Set the field small in tests since primitive polynomial generation is slow. p = 2 m = 2 Zp = IntegersModP(p) polysOver = polynomials_over(Zp) field = FiniteField(p, m) #m = 17 ##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) steps = 7 extension_factor = 8 inp = [field(0), field(1)] polysOver = multivariates_over(field, width).factory X_1 = polysOver({(1, 0): field(1)}) X_2 = polysOver({(0, 1): field(1)}) step_polys = [X_2, X_1 + X_2] air = AIR(field, width, inp, steps, step_polys, extension_factor) apr = APR(air)
def test_large_modulus(self): """Runs basic tests in large modulus needed for starks.""" modulus = 2**256 - 2**32 * 351 + 1 modM = IntegersModP(modulus) assert modM(5) != modM(11) assert modM(2**32) != modM(2**64) assert modM(2**64) != modM(2**128) assert modM(2**256) == modM(2**32 * 351 - 1)
def test_exponentiation(self): """Tests that old and new multiplication match.""" steps = 512 modulus = 2**256 - 2**32 * 351 + 1 mod = IntegersModP(modulus) Gorig = pow(7, (modulus - 1) // steps, modulus) G = mod(7)**((modulus - 1) // steps) assert int(G) == Gorig
def Float_to_Fix(self): polysOver = polynomials_over(IntegersModP(field.p)) if self.z == 1: return field(polysOver([0])), 0 result_of_power = self.p.two_pow() output = self.v * result_of_power return output, self.s
def test_division(self): """Basic test of polynomial division.""" Mod5 = IntegersModP(5) Mod11 = IntegersModP(11) polysOverQ = polynomials_over(Fraction).factory polysMod5 = polynomials_over(Mod5).factory polysMod11 = polynomials_over(Mod11).factory for p in [polysOverQ, polysMod5, polysMod11]: # division assert p([1, 1, 1, 1, 1, 1]) == p([-1, 0, 0, 0, 0, 0, 1]) / p([-1, 1]) assert p([-1, 1, -1, 1, -1, 1]) == p([1, 0, 0, 0, 0, 0, 1]) / p([1, 1]) assert p([]) == p([]) / p([1, 1]) assert p([1, 1]) == p([1, 1]) / p([1]) assert p([1, 1]) == p([2, 2]) / p([2])
def Taylor_Expansion(self, Polys, n): # Let F be any field of characteristic two, t > 1 any integer, so we consider as 2 # if n <= t then return the original function if n <= 2: return Polys # Find k such that t * 2^k < n ≤ 2 * t * 2^k for x in range(n): if 2**(x + 1) < n and 2**(x + 2) >= n: k = x # Split f(x) into three blocks f0, f1, and f2 where f(x) = f0(x) + x^{t * 2^k} (f1(x) + x ^{(t-1) * 2^k} * f2(x)) polysOver = polynomials_over(IntegersModP(2)) list_f0 = [] for i in range(2**(k + 1)): if i > Polys.poly.degree(): list_f0.append(0) else: list_f0.append(int(str(Polys.poly.coefficients[i])[0])) list_f1 = [] for i in range(2**(k)): if 2**(k + 1) + i > Polys.poly.degree(): list_f1.append(0) else: list_f1.append( int(str(Polys.poly.coefficients[2**(k + 1) + i])[0])) list_f2 = [] for i in range(2**k): if 2**(k + 1) + 2**k + i > Polys.poly.degree(): list_f2.append(0) else: list_f2.append( int( str(Polys.poly.coefficients[2**(k + 1) + 2**k + i])[0])) f0 = self.field(polysOver(list_f0)) f1 = self.field(polysOver(list_f1)) f2 = self.field(polysOver(list_f2)) # h = f1+f2, g0 = f0 + x^{2^k} * h, and g1 = h + x^{(t-1) * 2^k} * f2 h = f1 + f2 twoK = [] for i in range(2**(k)): twoK.append(0) twoK.append(1) f_twoK = self.field(polysOver(twoK)) g0 = f0 + f_twoK * h g1 = h + f_twoK * f2 # recursive part V1 = self.Taylor_Expansion(g0, n / 2) V2 = self.Taylor_Expansion(g1, n / 2) return V1, V2
def test_basic(self): """Basic test""" #field7 = PrimeField(7) mod7 = IntegersModP(7) # 12 % 7 == 5 assert mod7(6) + mod7(6) == mod7(5) # 6^-1 = 6 assert 1 / mod7(6) == mod7(6)
def test_typecast(self): """Test typecasting operation""" mod3 = IntegersModP(3) Polynomial = polynomials_over(mod3) x = mod3(1) p = Polynomial([1, 2]) x + p p + x