diff --git a/zksnark/py_pairing/LICENSE b/zksnark/py_pairing/LICENSE deleted file mode 100644 index ce488852..00000000 --- a/zksnark/py_pairing/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ - -The MIT License (MIT) - -Copyright (c) 2015 Vitalik Buterin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/zksnark/py_pairing/README.md b/zksnark/py_pairing/README.md deleted file mode 100644 index fc7a59b9..00000000 --- a/zksnark/py_pairing/README.md +++ /dev/null @@ -1 +0,0 @@ -Implements optimal ate pairings over the bn\_128 curve. diff --git a/zksnark/py_pairing/py_pairing/__init__.py b/zksnark/py_pairing/py_pairing/__init__.py deleted file mode 100644 index 32209d53..00000000 --- a/zksnark/py_pairing/py_pairing/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .optimized_curve import * -from .optimized_field_elements import * -from .optimized_pairing import * diff --git a/zksnark/py_pairing/py_pairing/bn128_curve.py b/zksnark/py_pairing/py_pairing/bn128_curve.py deleted file mode 100644 index 0e7c15ce..00000000 --- a/zksnark/py_pairing/py_pairing/bn128_curve.py +++ /dev/null @@ -1,119 +0,0 @@ -from bn128_field_elements import field_modulus, FQ -from optimized_field_elements import FQ2, FQ12 -# from bn128_field_elements import FQ2, FQ12 - -curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 - -# Curve order should be prime -assert pow(2, curve_order, curve_order) == 2 -# Curve order should be a factor of field_modulus**12 - 1 -assert (field_modulus ** 12 - 1) % curve_order == 0 - -# Curve is y**2 = x**3 + 3 -b = FQ(3) -# Twisted curve over FQ**2 -b2 = FQ2([3, 0]) / FQ2([9, 1]) -# Extension curve over FQ**12; same b value as over FQ -b12 = FQ12([3] + [0] * 11) - -# Generator for curve over FQ -G1 = (FQ(1), FQ(2)) -# Generator for twisted curve over FQ2 -G2 = (FQ2([10857046999023057135944570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634]), - FQ2([8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531])) - -# Check that a point is on the curve defined by y**2 == x**3 + b -def is_on_curve(pt, b): - if pt is None: - return True - x, y = pt - return y**2 - x**3 == b - -assert is_on_curve(G1, b) -assert is_on_curve(G2, b2) - -# Elliptic curve doubling -def double(pt): - x, y = pt - l = 3 * x**2 / (2 * y) - newx = l**2 - 2 * x - newy = -l * newx + l * x - y - return newx, newy - -# Elliptic curve addition -def add(p1, p2): - if p1 is None or p2 is None: - return p1 if p2 is None else p2 - x1, y1 = p1 - x2, y2 = p2 - if x2 == x1 and y2 == y1: - return double(p1) - elif x2 == x1: - return None - else: - l = (y2 - y1) / (x2 - x1) - newx = l**2 - x1 - x2 - newy = -l * newx + l * x1 - y1 - assert newy == (-l * newx + l * x2 - y2) - return (newx, newy) - -# Elliptic curve point multiplication -def multiply(pt, n): - if n == 0: - return None - elif n == 1: - return pt - elif not n % 2: - return multiply(double(pt), n // 2) - else: - return add(multiply(double(pt), int(n // 2)), pt) - -# Check that the G1 curve works fine -assert add(add(double(G1), G1), G1) == double(double(G1)) -assert double(G1) != G1 -assert add(multiply(G1, 9), multiply(G1, 5)) == add(multiply(G1, 12), multiply(G1, 2)) -assert multiply(G1, curve_order) is None - -# Check that the G2 curve works fine -assert add(add(double(G2), G2), G2) == double(double(G2)) -assert double(G2) != G2 -assert add(multiply(G2, 9), multiply(G2, 5)) == add(multiply(G2, 12), multiply(G2, 2)) -assert multiply(G2, curve_order) is None -assert multiply(G2, 2 * field_modulus - curve_order) is not None -assert is_on_curve(multiply(G2, 9), b2) - -# "Twist" a point in E(FQ2) into a point in E(FQ12) -w = FQ12([0, 1] + [0] * 10) - -# Convert P => -P -def neg(pt): - if pt is None: - return None - x, y = pt - return (x, -y) - -def twist(pt): - if pt is None: - return None - _x, _y = pt - # Field isomorphism from Z[p] / x**2 to Z[p] / x**2 - 18*x + 82 - xcoeffs = [_x.coeffs[0] - _x.coeffs[1] * 9, _x.coeffs[1]] - ycoeffs = [_y.coeffs[0] - _y.coeffs[1] * 9, _y.coeffs[1]] - # Isomorphism into subfield of Z[p] / w**12 - 18 * w**6 + 82, - # where w**6 = x - nx = FQ12([xcoeffs[0]] + [0] * 5 + [xcoeffs[1]] + [0] * 5) - ny = FQ12([ycoeffs[0]] + [0] * 5 + [ycoeffs[1]] + [0] * 5) - # Divide x coord by w**2 and y coord by w**3 - return (nx * w **2, ny * w**3) - -# Check that the twist creates a point that is on the curve -assert is_on_curve(twist(G2), b12) - -# Check that the G12 curve works fine - -G12 = twist(G2) -assert add(add(double(G12), G12), G12) == double(double(G12)) -assert double(G12) != G12 -assert add(multiply(G12, 9), multiply(G12, 5)) == add(multiply(G12, 12), multiply(G12, 2)) -assert is_on_curve(multiply(G12, 9), b12) -assert multiply(G12, curve_order) is None diff --git a/zksnark/py_pairing/py_pairing/bn128_field_elements.py b/zksnark/py_pairing/py_pairing/bn128_field_elements.py deleted file mode 100644 index 9dff5ceb..00000000 --- a/zksnark/py_pairing/py_pairing/bn128_field_elements.py +++ /dev/null @@ -1,272 +0,0 @@ -import sys -sys.setrecursionlimit(10000) - -# python3 compatibility -try: - foo = long -except: - long = int - -# The prime modulus of the field -field_modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583 -# See, it's prime! -assert pow(2, field_modulus, field_modulus) == 2 - -# The modulus of the polynomial in this representation of FQ12 -FQ12_modulus_coeffs = [82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0] # Implied + [1] - -# Extended euclidean algorithm to find modular inverses for -# integers -def inv(a, n): - if a == 0: - return 0 - lm, hm = 1, 0 - low, high = a % n, n - while low > 1: - r = high//low - nm, new = hm-lm*r, high-low*r - lm, low, hm, high = nm, new, lm, low - return lm % n - -# A class for field elements in FQ. Wrap a number in this class, -# and it becomes a field element. -class FQ(): - def __init__(self, n): - if isinstance(n, self.__class__): - self.n = n.n - else: - self.n = n % field_modulus - assert isinstance(self.n, (int, long)) - - def __add__(self, other): - on = other.n if isinstance(other, FQ) else other - return FQ((self.n + on) % field_modulus) - - def __mul__(self, other): - on = other.n if isinstance(other, FQ) else other - return FQ((self.n * on) % field_modulus) - - def __rmul__(self, other): - return self * other - - def __radd__(self, other): - return self + other - - def __rsub__(self, other): - on = other.n if isinstance(other, FQ) else other - return FQ((on - self.n) % field_modulus) - - def __sub__(self, other): - on = other.n if isinstance(other, FQ) else other - return FQ((self.n - on) % field_modulus) - - def __div__(self, other): - on = other.n if isinstance(other, FQ) else other - assert isinstance(on, (int, long)) - return FQ(self.n * inv(on, field_modulus) % field_modulus) - - def __truediv__(self, other): - return self.__div__(other) - - def __rdiv__(self, other): - on = other.n if isinstance(other, FQ) else other - assert isinstance(on, (int, long)), on - return FQ(inv(self.n, field_modulus) * on % field_modulus) - - def __rtruediv__(self, other): - return self.__rdiv__(other) - - def __pow__(self, other): - if other == 0: - return FQ(1) - elif other == 1: - return FQ(self.n) - elif other % 2 == 0: - return (self * self) ** (other // 2) - else: - return ((self * self) ** int(other // 2)) * self - - def __eq__(self, other): - if isinstance(other, FQ): - return self.n == other.n - else: - return self.n == other - - def __ne__(self, other): - return not self == other - - def __neg__(self): - return FQ(-self.n) - - def __repr__(self): - return repr(self.n) - - @classmethod - def one(cls): - return cls(1) - - @classmethod - def zero(cls): - return cls(0) - -# Check that the field works fine -assert FQ(2) * FQ(2) == FQ(4) -assert FQ(2) / FQ(7) + FQ(9) / FQ(7) == FQ(11) / FQ(7) -assert FQ(2) * FQ(7) + FQ(9) * FQ(7) == FQ(11) * FQ(7) -assert FQ(9) ** field_modulus == FQ(9) - -# Utility methods for polynomial math -def deg(p): - d = len(p) - 1 - while p[d] == 0 and d: - d -= 1 - return d - -def poly_rounded_div(a, b): - dega = deg(a) - degb = deg(b) - temp = [x for x in a] - o = [0 for x in a] - for i in range(dega - degb, -1, -1): - o[i] += temp[degb + i] / b[degb] - for c in range(degb + 1): - temp[c + i] -= o[c] - return o[:deg(o)+1] - -# A class for elements in polynomial extension fields -class FQP(): - def __init__(self, coeffs, modulus_coeffs): - assert len(coeffs) == len(modulus_coeffs) - self.coeffs = [FQ(c) for c in coeffs] - # The coefficients of the modulus, without the leading [1] - self.modulus_coeffs = modulus_coeffs - # The degree of the extension field - self.degree = len(self.modulus_coeffs) - - def __add__(self, other): - assert isinstance(other, self.__class__) - return self.__class__([x+y for x,y in zip(self.coeffs, other.coeffs)]) - - def __sub__(self, other): - assert isinstance(other, self.__class__) - return self.__class__([x-y for x,y in zip(self.coeffs, other.coeffs)]) - - def __mul__(self, other): - if isinstance(other, (FQ, int, long)): - return self.__class__([c * other for c in self.coeffs]) - else: - assert isinstance(other, self.__class__) - b = [FQ(0) for i in range(self.degree * 2 - 1)] - for i in range(self.degree): - for j in range(self.degree): - b[i + j] += self.coeffs[i] * other.coeffs[j] - while len(b) > self.degree: - exp, top = len(b) - self.degree - 1, b.pop() - for i in range(self.degree): - b[exp + i] -= top * FQ(self.modulus_coeffs[i]) - return self.__class__(b) - - def __rmul__(self, other): - return self * other - - def __div__(self, other): - if isinstance(other, (FQ, int, long)): - return self.__class__([c / other for c in self.coeffs]) - else: - assert isinstance(other, self.__class__) - return self * other.inv() - - def __truediv__(self, other): - return self.__div__(other) - - def __pow__(self, other): - if other == 0: - return self.__class__([1] + [0] * (self.degree - 1)) - elif other == 1: - return self.__class__(self.coeffs) - elif other % 2 == 0: - return (self * self) ** (other // 2) - else: - return ((self * self) ** int(other // 2)) * self - - # Extended euclidean algorithm used to find the modular inverse - def inv(self): - lm, hm = [1] + [0] * self.degree, [0] * (self.degree + 1) - low, high = self.coeffs + [0], self.modulus_coeffs + [1] - while deg(low): - r = poly_rounded_div(high, low) - r += [0] * (self.degree + 1 - len(r)) - nm = [x for x in hm] - new = [x for x in high] - assert len(lm) == len(hm) == len(low) == len(high) == len(nm) == len(new) == self.degree + 1 - for i in range(self.degree + 1): - for j in range(self.degree + 1 - i): - nm[i+j] -= lm[i] * r[j] - new[i+j] -= low[i] * r[j] - lm, low, hm, high = nm, new, lm, low - return self.__class__(lm[:self.degree]) / low[0] - - def __repr__(self): - return repr(self.coeffs) - - def __eq__(self, other): - assert isinstance(other, self.__class__) - for c1, c2 in zip(self.coeffs, other.coeffs): - if c1 != c2: - return False - return True - - def __ne__(self, other): - return not self == other - - def __neg__(self): - return self.__class__([-c for c in self.coeffs]) - - @classmethod - def one(cls): - return cls([1] + [0] * (cls.degree - 1)) - - @classmethod - def zero(cls): - return cls([0] * cls.degree) - -# The quadratic extension field -class FQ2(FQP): - def __init__(self, coeffs): - self.coeffs = [FQ(c) for c in coeffs] - self.modulus_coeffs = [1, 0] - self.degree = 2 - self.__class__.degree = 2 - -x = FQ2([1, 0]) -f = FQ2([1, 2]) -fpx = FQ2([2, 2]) -one = FQ2.one() - -# Check that the field works fine -assert x + f == fpx -assert f / f == one -assert one / f + x / f == (one + x) / f -assert one * f + x * f == (one + x) * f -assert x ** (field_modulus ** 2 - 1) == one - -# The 12th-degree extension field -class FQ12(FQP): - def __init__(self, coeffs): - self.coeffs = [FQ(c) for c in coeffs] - self.modulus_coeffs = FQ12_modulus_coeffs - self.degree = 12 - self.__class__.degree = 12 - -x = FQ12([1] + [0] * 11) -f = FQ12([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) -fpx = FQ12([2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) -one = FQ12.one() - -# Check that the field works fine -assert x + f == fpx -assert f / f == one -assert one / f + x / f == (one + x) / f -assert one * f + x * f == (one + x) * f -# This check takes too long -# assert x ** (field_modulus ** 12 - 1) == one diff --git a/zksnark/py_pairing/py_pairing/bn128_pairing.py b/zksnark/py_pairing/py_pairing/bn128_pairing.py deleted file mode 100644 index 2924f2af..00000000 --- a/zksnark/py_pairing/py_pairing/bn128_pairing.py +++ /dev/null @@ -1,72 +0,0 @@ -from bn128_curve import double, add, multiply, is_on_curve, neg, twist, b, b2, b12, curve_order, G1, G2, G12 -from bn128_field_elements import field_modulus, FQ -from optimized_field_elements import FQ2, FQ12 - -ate_loop_count = 29793968203157093288 -log_ate_loop_count = 63 - -# Create a function representing the line between P1 and P2, -# and evaluate it at T -def linefunc(P1, P2, T): - assert P1 and P2 and T # No points-at-infinity allowed, sorry - x1, y1 = P1 - x2, y2 = P2 - xt, yt = T - if x1 != x2: - m = (y2 - y1) / (x2 - x1) - return m * (xt - x1) - (yt - y1) - elif y1 == y2: - m = 3 * x1**2 / (2 * y1) - return m * (xt - x1) - (yt - y1) - else: - return xt - x1 - -def cast_point_to_fq12(pt): - if pt is None: - return None - x, y = pt - return (FQ12([x.n] + [0] * 11), FQ12([y.n] + [0] * 11)) - -# Check consistency of the "line function" -one, two, three = G1, double(G1), multiply(G1, 3) -negone, negtwo, negthree = multiply(G1, curve_order - 1), multiply(G1, curve_order - 2), multiply(G1, curve_order - 3) - -assert linefunc(one, two, one) == FQ(0) -assert linefunc(one, two, two) == FQ(0) -assert linefunc(one, two, three) != FQ(0) -assert linefunc(one, two, negthree) == FQ(0) -assert linefunc(one, negone, one) == FQ(0) -assert linefunc(one, negone, negone) == FQ(0) -assert linefunc(one, negone, two) != FQ(0) -assert linefunc(one, one, one) == FQ(0) -assert linefunc(one, one, two) != FQ(0) -assert linefunc(one, one, negtwo) == FQ(0) - -# Main miller loop -def miller_loop(Q, P): - if Q is None or P is None: - return FQ12.one() - R = Q - f = FQ12.one() - for i in range(log_ate_loop_count, -1, -1): - f = f * f * linefunc(R, R, P) - R = double(R) - if ate_loop_count & (2**i): - f = f * linefunc(R, Q, P) - R = add(R, Q) - # assert R == multiply(Q, ate_loop_count) - Q1 = (Q[0] ** field_modulus, Q[1] ** field_modulus) - # assert is_on_curve(Q1, b12) - nQ2 = (Q1[0] ** field_modulus, -Q1[1] ** field_modulus) - # assert is_on_curve(nQ2, b12) - f = f * linefunc(R, Q1, P) - R = add(R, Q1) - f = f * linefunc(R, nQ2, P) - # R = add(R, nQ2) This line is in many specifications but it technically does nothing - return f ** ((field_modulus ** 12 - 1) // curve_order) - -# Pairing computation -def pairing(Q, P): - assert is_on_curve(Q, b2) - assert is_on_curve(P, b) - return miller_loop(twist(Q), cast_point_to_fq12(P)) diff --git a/zksnark/py_pairing/py_pairing/optimized_curve.py b/zksnark/py_pairing/py_pairing/optimized_curve.py deleted file mode 100644 index 1e78d684..00000000 --- a/zksnark/py_pairing/py_pairing/optimized_curve.py +++ /dev/null @@ -1,143 +0,0 @@ -from .bn128_field_elements import field_modulus, FQ -from .optimized_field_elements import FQ2, FQ12 -# from bn128_field_elements import FQ2, FQ12 - -curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 - -# Curve order should be prime -assert pow(2, curve_order, curve_order) == 2 -# Curve order should be a factor of field_modulus**12 - 1 -assert (field_modulus ** 12 - 1) % curve_order == 0 - -# Curve is y**2 = x**3 + 3 -b = FQ(3) -# Twisted curve over FQ**2 -b2 = FQ2([3, 0]) / FQ2([9, 1]) -# Extension curve over FQ**12; same b value as over FQ -b12 = FQ12([3] + [0] * 11) - -# Generator for curve over FQ -G1 = (FQ(1), FQ(2), FQ(1)) -# Generator for twisted curve over FQ2 -G2 = (FQ2([10857046999023057135944570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634]), - FQ2([8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531]), FQ2.one()) - -# Check that a point is on the curve defined by y**2 == x**3 + b -def is_on_curve(pt, b): - if pt[-1] == pt[-1].__class__.zero(): - return True - x, y, z = pt - return y**2 * z - x**3 == b * z**3 - -assert is_on_curve(G1, b) -assert is_on_curve(G2, b2) - -# Elliptic curve doubling -def double(pt): - x, y, z = pt - W = 3 * x * x - S = y * z - B = x * y * S - H = W * W - 8 * B - S_squared = S * S - newx = 2 * H * S - newy = W * (4 * B - H) - 8 * y * y * S_squared - newz = 8 * S * S_squared - return newx, newy, newz - -# Elliptic curve addition -def add(p1, p2): - one, zero = p1[0].__class__.one(), p1[0].__class__.zero() - if p1[2] == zero or p2[2] == zero: - return p1 if p2[2] == zero else p2 - x1, y1, z1 = p1 - x2, y2, z2 = p2 - U1 = y2 * z1 - U2 = y1 * z2 - V1 = x2 * z1 - V2 = x1 * z2 - if V1 == V2 and U1 == U2: - return double(p1) - elif V1 == V2: - return (one, one, zero) - U = U1 - U2 - V = V1 - V2 - V_squared = V * V - V_squared_times_V2 = V_squared * V2 - V_cubed = V * V_squared - W = z1 * z2 - A = U * U * W - V_cubed - 2 * V_squared_times_V2 - newx = V * A - newy = U * (V_squared_times_V2 - A) - V_cubed * U2 - newz = V_cubed * W - return (newx, newy, newz) - -# Elliptic curve point multiplication -def multiply(pt, n): - if n == 0: - return (pt[0].__class__.one(), pt[0].__class__.one(), pt[0].__class__.zero()) - elif n == 1: - return pt - elif not n % 2: - return multiply(double(pt), n // 2) - else: - return add(multiply(double(pt), int(n // 2)), pt) - -def eq(p1, p2): - x1, y1, z1 = p1 - x2, y2, z2 = p2 - return x1 * z2 == x2 * z1 and y1 * z2 == y2 * z1 - -def normalize(pt): - x, y, z = pt - return (x / z, y / z) - -# Check that the G1 curve works fine -assert eq(add(add(double(G1), G1), G1), double(double(G1))) -assert not eq(double(G1), G1) -assert eq(add(multiply(G1, 9), multiply(G1, 5)), add(multiply(G1, 12), multiply(G1, 2))) -assert eq(multiply(G1, curve_order), (1, 1, 0)) - -# Check that the G2 curve works fine -assert eq(add(add(double(G2), G2), G2), double(double(G2))) -assert not eq(double(G2), G2) -assert eq(add(multiply(G2, 9), multiply(G2, 5)), add(multiply(G2, 12), multiply(G2, 2))) -assert eq(multiply(G2, curve_order), (1, 1, 0)) -assert not eq(multiply(G2, 2 * field_modulus - curve_order), (1, 1, 0)) -assert is_on_curve(multiply(G2, 9), b2) - -# "Twist" a point in E(FQ2) into a point in E(FQ12) -w = FQ12([0, 1] + [0] * 10) - -# Convert P => -P -def neg(pt): - if pt is None: - return None - x, y, z = pt - return (x, -y, z) - -def twist(pt): - if pt is None: - return None - _x, _y, _z = pt - # Field isomorphism from Z[p] / x**2 to Z[p] / x**2 - 18*x + 82 - xcoeffs = [_x.coeffs[0] - _x.coeffs[1] * 9, _x.coeffs[1]] - ycoeffs = [_y.coeffs[0] - _y.coeffs[1] * 9, _y.coeffs[1]] - zcoeffs = [_z.coeffs[0] - _z.coeffs[1] * 9, _z.coeffs[1]] - x, y, z = _x - _y * 9, _y, _z - nx = FQ12([xcoeffs[0]] + [0] * 5 + [xcoeffs[1]] + [0] * 5) - ny = FQ12([ycoeffs[0]] + [0] * 5 + [ycoeffs[1]] + [0] * 5) - nz = FQ12([zcoeffs[0]] + [0] * 5 + [zcoeffs[1]] + [0] * 5) - return (nx * w **2, ny * w**3, nz) - -# Check that the twist creates a point that is on the curve -assert is_on_curve(twist(G2), b12) - -# Check that the G12 curve works fine - -G12 = twist(G2) -assert eq(add(add(double(G12), G12), G12), double(double(G12))) -assert not eq(double(G12), G12) -assert eq(add(multiply(G12, 9), multiply(G12, 5)), add(multiply(G12, 12), multiply(G12, 2))) -assert is_on_curve(multiply(G12, 9), b12) -assert eq(multiply(G12, curve_order), (1, 1, 0)) diff --git a/zksnark/py_pairing/py_pairing/optimized_field_elements.py b/zksnark/py_pairing/py_pairing/optimized_field_elements.py deleted file mode 100644 index e3b25b39..00000000 --- a/zksnark/py_pairing/py_pairing/optimized_field_elements.py +++ /dev/null @@ -1,197 +0,0 @@ -field_modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583 -FQ12_modulus_coeffs = [82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0] # Implied + [1] -FQ12_mc_tuples = [(i, c) for i, c in enumerate(FQ12_modulus_coeffs) if c] - -# python3 compatibility -try: - foo = long -except: - long = int - -# Extended euclidean algorithm to find modular inverses for -# integers -def prime_field_inv(a, n): - if a == 0: - return 0 - lm, hm = 1, 0 - low, high = a % n, n - while low > 1: - r = high//low - nm, new = hm-lm*r, high-low*r - lm, low, hm, high = nm, new, lm, low - return lm % n - -# Utility methods for polynomial math -def deg(p): - d = len(p) - 1 - while p[d] == 0 and d: - d -= 1 - return d - -def poly_rounded_div(a, b): - dega = deg(a) - degb = deg(b) - temp = [x for x in a] - o = [0 for x in a] - for i in range(dega - degb, -1, -1): - o[i] = (o[i] + temp[degb + i] * prime_field_inv(b[degb], field_modulus)) - for c in range(degb + 1): - temp[c + i] = (temp[c + i] - o[c]) - return [x % field_modulus for x in o[:deg(o)+1]] - -def karatsuba(a, b, c, d): - L = len(a) - EXTENDED_LEN = L * 2 - 1 - # phi = (a+b)(c+d) - # psi = (a-b)(c-d) - phi, psi, bd2 = [0] * EXTENDED_LEN, [0] * EXTENDED_LEN, [0] * EXTENDED_LEN - for i in range(L): - for j in range(L): - phi[i + j] += (a[i] + b[i]) * (c[j] + d[j]) - psi[i + j] += (a[i] - b[i]) * (c[j] - d[j]) - bd2[i + j] += b[i] * d[j] * 2 - o = [0] * (L * 4 - 1) - # L = (phi + psi - bd2) / 2 - # M = (phi - psi) / 2 - # H = bd2 / 2 - for i in range(L * 2 - 1): - o[i] += phi[i] + psi[i] - bd2[i] - o[i + L] += phi[i] - psi[i] - o[i + L * 2] += bd2[i] - inv_2 = (field_modulus + 1) // 2 - return [a * inv_2 if a % 2 else a // 2 for a in o] - -o = karatsuba([1, 3], [3, 1], [1, 3], [3, 1]) -assert [x % field_modulus for x in o] == [1, 6, 15, 20, 15, 6, 1] - -# A class for elements in polynomial extension fields -class FQP(): - def __init__(self, coeffs, modulus_coeffs): - assert len(coeffs) == len(modulus_coeffs) - self.coeffs = coeffs - # The coefficients of the modulus, without the leading [1] - self.modulus_coeffs = modulus_coeffs - # The degree of the extension field - self.degree = len(self.modulus_coeffs) - - def __add__(self, other): - assert isinstance(other, self.__class__) - return self.__class__([(x+y) % field_modulus for x,y in zip(self.coeffs, other.coeffs)]) - - def __sub__(self, other): - assert isinstance(other, self.__class__) - return self.__class__([(x-y) % field_modulus for x,y in zip(self.coeffs, other.coeffs)]) - - def __mul__(self, other): - if isinstance(other, (int, long)): - return self.__class__([c * other % field_modulus for c in self.coeffs]) - else: - # assert isinstance(other, self.__class__) - b = [0] * (self.degree * 2 - 1) - inner_enumerate = list(enumerate(other.coeffs)) - for i, eli in enumerate(self.coeffs): - for j, elj in inner_enumerate: - b[i + j] += eli * elj - # MID = len(self.coeffs) // 2 - # b = karatsuba(self.coeffs[:MID], self.coeffs[MID:], other.coeffs[:MID], other.coeffs[MID:]) - for exp in range(self.degree - 2, -1, -1): - top = b.pop() - for i, c in self.mc_tuples: - b[exp + i] -= top * c - return self.__class__([x % field_modulus for x in b]) - - def __rmul__(self, other): - return self * other - - def __div__(self, other): - if isinstance(other, (int, long)): - return self.__class__([c * prime_field_inv(other, field_modulus) % field_modulus for c in self.coeffs]) - else: - assert isinstance(other, self.__class__) - return self * other.inv() - - def __truediv__(self, other): - return self.__div__(other) - - def __pow__(self, other): - o = self.__class__([1] + [0] * (self.degree - 1)) - t = self - while other > 0: - if other & 1: - o = o * t - other >>= 1 - t = t * t - return o - - # Extended euclidean algorithm used to find the modular inverse - def inv(self): - lm, hm = [1] + [0] * self.degree, [0] * (self.degree + 1) - low, high = self.coeffs + [0], self.modulus_coeffs + [1] - while deg(low): - r = poly_rounded_div(high, low) - r += [0] * (self.degree + 1 - len(r)) - nm = [x for x in hm] - new = [x for x in high] - # assert len(lm) == len(hm) == len(low) == len(high) == len(nm) == len(new) == self.degree + 1 - for i in range(self.degree + 1): - for j in range(self.degree + 1 - i): - nm[i+j] -= lm[i] * r[j] - new[i+j] -= low[i] * r[j] - nm = [x % field_modulus for x in nm] - new = [x % field_modulus for x in new] - lm, low, hm, high = nm, new, lm, low - return self.__class__(lm[:self.degree]) / low[0] - - def __repr__(self): - return repr(self.coeffs) - - def __eq__(self, other): - assert isinstance(other, self.__class__) - for c1, c2 in zip(self.coeffs, other.coeffs): - if c1 != c2: - return False - return True - - def __ne__(self, other): - return not self == other - - def __neg__(self): - return self.__class__([-c for c in self.coeffs]) - - @classmethod - def one(cls): - return cls([1] + [0] * (cls.degree - 1)) - - @classmethod - def zero(cls): - return cls([0] * cls.degree) - -# The quadratic extension field -class FQ2(FQP): - def __init__(self, coeffs): - self.coeffs = coeffs - self.modulus_coeffs = [1, 0] - self.mc_tuples = [(0, 1)] - self.degree = 2 - self.__class__.degree = 2 - -x = FQ2([1, 0]) -f = FQ2([1, 2]) -fpx = FQ2([2, 2]) -one = FQ2.one() - -# Check that the field works fine -assert x + f == fpx -assert f / f == one -assert one / f + x / f == (one + x) / f -assert one * f + x * f == (one + x) * f -assert x ** (field_modulus ** 2 - 1) == one - -# The 12th-degree extension field -class FQ12(FQP): - def __init__(self, coeffs): - self.coeffs = coeffs - self.modulus_coeffs = FQ12_modulus_coeffs - self.mc_tuples = FQ12_mc_tuples - self.degree = 12 - self.__class__.degree = 12 diff --git a/zksnark/py_pairing/py_pairing/optimized_pairing.py b/zksnark/py_pairing/py_pairing/optimized_pairing.py deleted file mode 100644 index f05dba49..00000000 --- a/zksnark/py_pairing/py_pairing/optimized_pairing.py +++ /dev/null @@ -1,114 +0,0 @@ -from .optimized_curve import double, add, multiply, is_on_curve, neg, twist, b, b2, b12, curve_order, G1, G2, G12, normalize -from .bn128_field_elements import field_modulus, FQ -from .optimized_field_elements import FQ2, FQ12 - -ate_loop_count = 29793968203157093288 -log_ate_loop_count = 63 -pseudo_binary_encoding = [0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, - 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, - 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, - 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1] - -assert sum([e * 2**i for i, e in enumerate(pseudo_binary_encoding)]) == ate_loop_count - - -def normalize1(p): - x, y = normalize(p) - return x, y, x.__class__.one() - -# Create a function representing the line between P1 and P2, -# and evaluate it at T. Returns a numerator and a denominator -# to avoid unneeded divisions -def linefunc(P1, P2, T): - zero = P1[0].__class__.zero() - x1, y1, z1 = P1 - x2, y2, z2 = P2 - xt, yt, zt = T - # points in projective coords: (x / z, y / z) - # hence, m = (y2/z2 - y1/z1) / (x2/z2 - x1/z1) - # multiply numerator and denominator by z1z2 to get values below - m_numerator = y2 * z1 - y1 * z2 - m_denominator = x2 * z1 - x1 * z2 - if m_denominator != zero: - # m * ((xt/zt) - (x1/z1)) - ((yt/zt) - (y1/z1)) - return m_numerator * (xt * z1 - x1 * zt) - m_denominator * (yt * z1 - y1 * zt), \ - m_denominator * zt * z1 - elif m_numerator == zero: - # m = 3(x/z)^2 / 2(y/z), multiply num and den by z**2 - m_numerator = 3 * x1 * x1 - m_denominator = 2 * y1 * z1 - return m_numerator * (xt * z1 - x1 * zt) - m_denominator * (yt * z1 - y1 * zt), \ - m_denominator * zt * z1 - else: - return xt * z1 - x1 * zt, z1 * zt - -def cast_point_to_fq12(pt): - if pt is None: - return None - x, y, z = pt - return (FQ12([x.n] + [0] * 11), FQ12([y.n] + [0] * 11), FQ12([z.n] + [0] * 11)) - -# Check consistency of the "line function" -one, two, three = G1, double(G1), multiply(G1, 3) -negone, negtwo, negthree = multiply(G1, curve_order - 1), multiply(G1, curve_order - 2), multiply(G1, curve_order - 3) - -assert linefunc(one, two, one)[0] == FQ(0) -assert linefunc(one, two, two)[0] == FQ(0) -assert linefunc(one, two, three)[0] != FQ(0) -assert linefunc(one, two, negthree)[0] == FQ(0) -assert linefunc(one, negone, one)[0] == FQ(0) -assert linefunc(one, negone, negone)[0] == FQ(0) -assert linefunc(one, negone, two)[0] != FQ(0) -assert linefunc(one, one, one)[0] == FQ(0) -assert linefunc(one, one, two)[0] != FQ(0) -assert linefunc(one, one, negtwo)[0] == FQ(0) - -# Main miller loop -def miller_loop(Q, P, final_exponentiate=True): - if Q is None or P is None: - return FQ12.one() - R = Q - f_num, f_den = FQ12.one(), FQ12.one() - for b in pseudo_binary_encoding[63::-1]: - #for i in range(log_ate_loop_count, -1, -1): - _n, _d = linefunc(R, R, P) - f_num = f_num * f_num * _n - f_den = f_den * f_den * _d - R = double(R) - #if ate_loop_count & (2**i): - if b == 1: - _n, _d = linefunc(R, Q, P) - f_num = f_num * _n - f_den = f_den * _d - R = add(R, Q) - elif b == -1: - nQ = neg(Q) - _n, _d = linefunc(R, nQ, P) - f_num = f_num * _n - f_den = f_den * _d - R = add(R, nQ) - # assert R == multiply(Q, ate_loop_count) - Q1 = (Q[0] ** field_modulus, Q[1] ** field_modulus, Q[2] ** field_modulus) - # assert is_on_curve(Q1, b12) - nQ2 = (Q1[0] ** field_modulus, -Q1[1] ** field_modulus, Q1[2] ** field_modulus) - # assert is_on_curve(nQ2, b12) - _n1, _d1 = linefunc(R, Q1, P) - R = add(R, Q1) - _n2, _d2 = linefunc(R, nQ2, P) - f = f_num * _n1 * _n2 / (f_den * _d1 * _d2) - # R = add(R, nQ2) This line is in many specifications but it technically does nothing - if final_exponentiate: - return f ** ((field_modulus ** 12 - 1) // curve_order) - else: - return f - -# Pairing computation -def pairing(Q, P, final_exponentiate=True): - assert is_on_curve(Q, b2) - assert is_on_curve(P, b) - if P[-1] == P[-1].__class__.zero() or Q[-1] == Q[-1].__class__.zero(): - return FQ12.one() - return miller_loop(twist(Q), cast_point_to_fq12(P), final_exponentiate=final_exponentiate) - -def final_exponentiate(p): - return p ** ((field_modulus ** 12 - 1) // curve_order) diff --git a/zksnark/py_pairing/setup.py b/zksnark/py_pairing/setup.py deleted file mode 100644 index b16e4f4e..00000000 --- a/zksnark/py_pairing/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -from setuptools import setup, find_packages - - -with open('README.md') as f: - readme = f.read() - -with open('LICENSE') as f: - license = f.read() - -setup( - name='py_pairing', - version='0.0.1', - description='Optimal ate pairings over alt_bn128', - long_description=readme, - author='Vitalik Buterin', - author_email='', - url='https://github.com/ethereum/research', - license=license, - packages=find_packages(exclude=('tests', 'docs')), - install_requires=[ - 'ethereum == 1.3.7', - 'nose', - ], -) diff --git a/zksnark/py_pairing/tests/test.py b/zksnark/py_pairing/tests/test.py deleted file mode 100644 index dc50dede..00000000 --- a/zksnark/py_pairing/tests/test.py +++ /dev/null @@ -1,29 +0,0 @@ -from py_pairing.optimized_pairing import pairing, neg, G2, G1, multiply, FQ12, curve_order -# from bn128_pairing import pairing, neg, G2, G1, multiply, FQ12, curve_order -import time - -a = time.time() -print('Starting tests') -p1 = pairing(G2, G1) -pn1 = pairing(G2, neg(G1)) -assert p1 * pn1 == FQ12.one() -print('Pairing check against negative in G1 passed') -np1 = pairing(neg(G2), G1) -assert p1 * np1 == FQ12.one() -assert pn1 == np1 -print('Pairing check against negative in G2 passed') -assert p1 ** curve_order == FQ12.one() -print('Pairing output has correct order') -p2 = pairing(G2, multiply(G1, 2)) -assert p1 * p1 == p2 -print('Pairing bilinearity in G1 passed') -assert p1 != p2 and p1 != np1 and p2 != np1 -print('Pairing is non-degenerate') -po2 = pairing(multiply(G2, 2), G1) -assert p1 * p1 == po2 -print('Pairing bilinearity in G2 passed') -p3 = pairing(multiply(G2, 27), multiply(G1, 37)) -po3 = pairing(G2, multiply(G1, 999)) -assert p3 == po3 -print('Composite check passed') -print('Total time: %.3f' % (time.time() - a))