From b331ee836a106ffc55ecb3a57c1684ada5db7ad3 Mon Sep 17 00:00:00 2001 From: zebra-lucky Date: Fri, 12 Jul 2019 05:05:20 +0300 Subject: [PATCH] add cython ext modules, version 0.1.6 --- .gitignore | 2 + .travis.yml | 105 ++ MANIFEST.in | 2 +- bls_py/ec.py | 526 +++---- bls_py/fields.py | 181 +-- bls_py/fields_t.py | 1145 +++++++++++--- bls_py/keys.py | 2 +- bls_py/pairing.py | 123 +- contrib/build_wheels_linux.sh | 32 + contrib/install_linux.sh | 10 + contrib/install_osx.sh | 24 + contrib/install_win.sh | 21 + contrib/script_linux.sh | 6 + contrib/script_osx.sh | 21 + contrib/script_win.sh | 85 ++ contrib/version_env.sh | 9 + extmod/bls_py/__init__.py | 0 extmod/bls_py/fields_t_c.pxd | 53 + extmod/bls_py/fields_t_c.pyx | 2699 +++++++++++++++++++++++++++++++++ extmod/bls_py/mpz.pxd | 195 +++ extmod/bls_py/types.pxd | 33 + setup.py | 36 +- 22 files changed, 4571 insertions(+), 739 deletions(-) create mode 100644 .travis.yml create mode 100755 contrib/build_wheels_linux.sh create mode 100755 contrib/install_linux.sh create mode 100755 contrib/install_osx.sh create mode 100755 contrib/install_win.sh create mode 100755 contrib/script_linux.sh create mode 100755 contrib/script_osx.sh create mode 100755 contrib/script_win.sh create mode 100755 contrib/version_env.sh create mode 100644 extmod/bls_py/__init__.py create mode 100644 extmod/bls_py/fields_t_c.pxd create mode 100644 extmod/bls_py/fields_t_c.pyx create mode 100644 extmod/bls_py/mpz.pxd create mode 100644 extmod/bls_py/types.pxd diff --git a/.gitignore b/.gitignore index 10afe0d..23b512d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ __pycache__/ *.py[cod] *$py.class +# C sources +extmod/bls_py/*.c # C extensions *.so diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fc0c4e8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,105 @@ +matrix: + include: + - if: tag =~ .+ + os: windows + language: sh + - if: tag =~ .+ + os: osx + osx_image: xcode8 + env: PYTHON_VERSION=3.7.4 + - if: tag =~ .+ + os: osx + osx_image: xcode8 + env: PYTHON_VERSION=3.6.8 + - if: tag =~ .+ + os: linux + sudo: required + addons: + apt: + packages: + lzip + services: + - docker + env: PLAT=manylinux2010_x86_64 + - if: tag =~ .+ + os: linux + sudo: required + addons: + apt: + packages: + lzip + services: + - docker + env: PLAT=manylinux1_x86_64 + - if: tag =~ .+ + os: linux + sudo: required + addons: + apt: + packages: + lzip + services: + - docker + env: PLAT=manylinux1_i686 PRE_CMD=linux32 +install: +- source contrib/version_env.sh +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'windows' ]]; then + ./contrib/install_win.sh; + fi +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'osx' ]]; then + ./contrib/install_osx.sh; + fi +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]]; then + ./contrib/install_linux.sh; + fi +script: +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'windows' ]]; then + ./contrib/script_win.sh; + fi +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'osx' ]]; then + ./contrib/script_osx.sh; + fi +- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]]; then + ./contrib/script_linux.sh; + fi +deploy: +- provider: releases + skip_cleanup: true + api_key: + secure: DV+4M/nOTmQzrKo12V9YuVlxJRBHeXNbcWyh4ERSaTkeX0btXmZlZQcD2Xpc1bDcugzO73knm4dc+z3k7SgAk/v9iZPphRQ1deaULyo67b4IIMZurKzZNNcccKXKwXanVN9LpDkfn/FwFlHXMYRdOBvIorvs19OUI0ULXXgpz9Xm6tkg9kqotGmrOQZPmibGnT7Aaqq7eYMXiP45wSMjKJsrLG2GJCYlMCvA21zcICwBcxiiSfFfqFzImLxdW6pHKaKbb6233j+f6T5HRl4i4T0DsW4FGm6z+wS+/XnQdso9VbHJVyQz11Y7ZEDpURqbd9DJUfO7YMtBp4DWMVMuB1bRNvsDdv3a8LNzKARmI2Ugw9/QcKs2bG9JREa2xRyuIDLM9cAx+xIuXC6pqx1TGQBSKWFsRj6jy/gDJAlWuFJTKXcRF1nOiT7+gIMZVvrJpbCOv6MpFoeY1tRZBfLhwitX81T6HYK6UbgJ683jaDYGzijY7qOXbue4Et/ahilU+0FZqvpFGgLEUAd+UgjDVGrc9B7/52zyVhg/JR5jOEO2E0pCqKsI/gFV5zN/PBMEfn5fDYdcMo7cwo+AFhcKRqZVxp2UPKzy6180S3CWIqaLiSkXP3T0banRKHRxCbzf47l8Aq5xvrM4GTIiMcqa+t9BmC5Z1oGSlmCAvbHiRQ0= + file: + - dist/python_bls-$PKG_VERSION-cp36-cp36m-win32.whl + - dist/python_bls-$PKG_VERSION-cp36-cp36m-win_amd64.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-win32.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-win_amd64.whl + on: + repo: zebra-lucky/python-bls + tags: true + condition: "$TRAVIS_OS_NAME = windows" +- provider: releases + skip_cleanup: true + api_key: + secure: DV+4M/nOTmQzrKo12V9YuVlxJRBHeXNbcWyh4ERSaTkeX0btXmZlZQcD2Xpc1bDcugzO73knm4dc+z3k7SgAk/v9iZPphRQ1deaULyo67b4IIMZurKzZNNcccKXKwXanVN9LpDkfn/FwFlHXMYRdOBvIorvs19OUI0ULXXgpz9Xm6tkg9kqotGmrOQZPmibGnT7Aaqq7eYMXiP45wSMjKJsrLG2GJCYlMCvA21zcICwBcxiiSfFfqFzImLxdW6pHKaKbb6233j+f6T5HRl4i4T0DsW4FGm6z+wS+/XnQdso9VbHJVyQz11Y7ZEDpURqbd9DJUfO7YMtBp4DWMVMuB1bRNvsDdv3a8LNzKARmI2Ugw9/QcKs2bG9JREa2xRyuIDLM9cAx+xIuXC6pqx1TGQBSKWFsRj6jy/gDJAlWuFJTKXcRF1nOiT7+gIMZVvrJpbCOv6MpFoeY1tRZBfLhwitX81T6HYK6UbgJ683jaDYGzijY7qOXbue4Et/ahilU+0FZqvpFGgLEUAd+UgjDVGrc9B7/52zyVhg/JR5jOEO2E0pCqKsI/gFV5zN/PBMEfn5fDYdcMo7cwo+AFhcKRqZVxp2UPKzy6180S3CWIqaLiSkXP3T0banRKHRxCbzf47l8Aq5xvrM4GTIiMcqa+t9BmC5Z1oGSlmCAvbHiRQ0= + file: + - dist/python_bls-$PKG_VERSION-cp36-cp36m-macosx_10_6_intel.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-macosx_10_6_intel.whl + on: + repo: zebra-lucky/python-bls + tags: true + condition: "$TRAVIS_OS_NAME = osx" +- provider: releases + skip_cleanup: true + api_key: + secure: DV+4M/nOTmQzrKo12V9YuVlxJRBHeXNbcWyh4ERSaTkeX0btXmZlZQcD2Xpc1bDcugzO73knm4dc+z3k7SgAk/v9iZPphRQ1deaULyo67b4IIMZurKzZNNcccKXKwXanVN9LpDkfn/FwFlHXMYRdOBvIorvs19OUI0ULXXgpz9Xm6tkg9kqotGmrOQZPmibGnT7Aaqq7eYMXiP45wSMjKJsrLG2GJCYlMCvA21zcICwBcxiiSfFfqFzImLxdW6pHKaKbb6233j+f6T5HRl4i4T0DsW4FGm6z+wS+/XnQdso9VbHJVyQz11Y7ZEDpURqbd9DJUfO7YMtBp4DWMVMuB1bRNvsDdv3a8LNzKARmI2Ugw9/QcKs2bG9JREa2xRyuIDLM9cAx+xIuXC6pqx1TGQBSKWFsRj6jy/gDJAlWuFJTKXcRF1nOiT7+gIMZVvrJpbCOv6MpFoeY1tRZBfLhwitX81T6HYK6UbgJ683jaDYGzijY7qOXbue4Et/ahilU+0FZqvpFGgLEUAd+UgjDVGrc9B7/52zyVhg/JR5jOEO2E0pCqKsI/gFV5zN/PBMEfn5fDYdcMo7cwo+AFhcKRqZVxp2UPKzy6180S3CWIqaLiSkXP3T0banRKHRxCbzf47l8Aq5xvrM4GTIiMcqa+t9BmC5Z1oGSlmCAvbHiRQ0= + file: + - dist/python_bls-$PKG_VERSION-cp36-cp36m-manylinux1_i686.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-manylinux1_i686.whl + - dist/python_bls-$PKG_VERSION-cp36-cp36m-manylinux1_x86_64.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-manylinux1_x86_64.whl + - dist/python_bls-$PKG_VERSION-cp36-cp36m-manylinux2010_x86_64.whl + - dist/python_bls-$PKG_VERSION-cp37-cp37m-manylinux2010_x86_64.whl + - dist/python-bls-$PKG_VERSION.tar.gz + on: + repo: zebra-lucky/python-bls + tags: true + condition: "$TRAVIS_OS_NAME = linux" diff --git a/MANIFEST.in b/MANIFEST.in index 8e1ba40..41cc7ea 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ include README.md LICENSE -include *.py +recursive-include extmod *.pxd *.pyx *.py diff --git a/bls_py/ec.py b/bls_py/ec.py index 7c7e722..1127a6a 100644 --- a/bls_py/ec.py +++ b/bls_py/ec.py @@ -1,11 +1,9 @@ +import logging from collections import namedtuple from copy import deepcopy from . import bls12381 -from .fields import (FieldExtBase, Fq, Fq2, Fq6, Fq12, - fq2_add_fq, fq2_sub_fq, fq2_mul_fq2, fq2_mul_fq, - fq_sub_fq2, fq2_add_fq2, fq2_sub_fq2, fq12_mul_fq12, - fq12_mul_fq2, fq12_mul_fq, fq12_add_fq12, fq12_sub_fq12) +from .fields import Fq, Fq2, Fq12 from .util import hash256, hash512 @@ -19,13 +17,15 @@ class AffinePoint: """ - Elliptic curve point, can represent any curve, and use Fq or Fq2 - coordinates. + Elliptic curve point, can represent only bls12-381 curve (a=0 or a=0,0 + for twisted curve), and use Fq, Fq2 or Fq12 coordinates. """ def __init__(self, x, y, infinity, ec=default_ec): - if (not isinstance(x, Fq) and not isinstance(x, FieldExtBase) or - (not isinstance(y, Fq) and not isinstance(y, FieldExtBase)) or - type(x) != type(y)): + type_x = type(x) + type_y = type(y) + if (type_x != type_y + or not type_x in (Fq, Fq2, Fq12) + or not type_y in (Fq, Fq2, Fq12)): raise Exception("x,y should be field elements") self.FE = type(x) self.x = x @@ -37,17 +37,12 @@ def is_on_curve(self): """ Check that y^2 = x^3 + ax + b """ - if self.infinity: - return True - left = self.y * self.y - right = self.x * self.x * self.x + self.ec.a * self.x + self.ec.b - - return left == right + return is_on_curve_affine(self, self.ec, self.FE) def __add__(self, other): if other == 0: return self - if not isinstance(other, AffinePoint): + if not type(other) == AffinePoint: raise Exception("Incorrect object") return add_points(self, other, self.ec, self.FE) @@ -72,7 +67,7 @@ def __repr__(self): ", i=" + str(self.infinity) + ")\n") def __eq__(self, other): - if not isinstance(other, AffinePoint): + if not type(other) == AffinePoint: return False return (self.x == other.x and self.y == other.y and @@ -82,7 +77,7 @@ def __ne__(self, other): return not self.__eq__(other) def __mul__(self, c): - if not isinstance(c, (Fq, int)): + if not type(c) in (Fq, int): raise ValueError("Error, must be int or Fq") return scalar_mult_jacobian(c, self.to_jacobian(), self.ec).to_affine() @@ -93,8 +88,7 @@ def __rmul__(self, c): return self.__mul__(c) def to_jacobian(self): - return JacobianPoint(self.x, self.y, self.FE.one(self.ec.q), - self.infinity, self.ec) + return to_jacobian(self, self.ec, self.FE) # Lexicographically greater than the negation def lex_gt_neg(self): @@ -125,14 +119,17 @@ def __deepcopy__(self, memo): class JacobianPoint: """ - Elliptic curve point, can represent any curve, and use Fq or Fq2 - coordinates. Uses Jacobian coordinates so that point addition - does not require slow inversion. + Elliptic curve point, can represent only bls12-381 curve (a=0 or a=0,0 + for twisted curve), and use Fq, Fq2 or Fq12 coordinates. Uses Jacobian + coordinates so that point addition does not require slow inversion. """ def __init__(self, x, y, z, infinity, ec=default_ec): - if (not isinstance(x, Fq) and not isinstance(x, FieldExtBase) or - (not isinstance(y, Fq) and not isinstance(y, FieldExtBase)) or - (not isinstance(z, Fq) and not isinstance(z, FieldExtBase))): + type_x = type(x) + type_y = type(y) + type_z = type(z) + if (type_x not in (Fq, Fq2, Fq12) + or type_y not in (Fq, Fq2, Fq12) + or type_z not in (Fq, Fq2, Fq12)): raise Exception("x,y should be field elements") self.FE = type(x) self.x = x @@ -142,14 +139,12 @@ def __init__(self, x, y, z, infinity, ec=default_ec): self.ec = ec def is_on_curve(self): - if self.infinity: - return True - return self.to_affine().is_on_curve() + return is_on_curve_jacobian(self, self.ec, self.FE) def __add__(self, other): if other == 0: return self - if not isinstance(other, JacobianPoint): + if not type(other) == JacobianPoint: raise ValueError("Incorrect object") return add_points_jacobian(self, other, self.ec, self.FE) @@ -164,7 +159,7 @@ def __str__(self): ", i=" + str(self.infinity) + ")\n") def __eq__(self, other): - if not isinstance(other, JacobianPoint): + if not type(other) == JacobianPoint: return False return self.to_affine() == other.to_affine() @@ -172,7 +167,7 @@ def __ne__(self, other): return not self.__eq__(other) def __mul__(self, c): - if not isinstance(c, (Fq, int)): + if not type(c) in (Fq, int): raise ValueError("Error, must be int or Fq") return scalar_mult_jacobian(c, self, self.ec) @@ -180,12 +175,7 @@ def __rmul__(self, c): return self.__mul__(c) def to_affine(self): - if self.infinity: - return AffinePoint(Fq.zero(self.ec.q), Fq.zero(self.ec.q), - self.infinity, self.ec) - new_x = self.x / pow(self.z, 2) - new_y = self.y / pow(self.z, 3) - return AffinePoint(new_x, new_y, self.infinity, self.ec) + return to_affine(self, self.ec, self.FE) def serialize(self): return self.to_affine().serialize() @@ -198,14 +188,80 @@ def __deepcopy__(self, memo): self.ec) +def is_on_curve_affine(p, ec, FE): + Q = ec.q + px = p.x + py = p.y + pinf = p.infinity + if FE == Fq: + return fq_is_on_curve_affine(px.Z, py.Z, pinf) + elif FE == Fq2: + return fq2_is_on_curve_affine(px.ZT, py.ZT, pinf) + elif FE == Fq12: + return fq12_is_on_curve_affine(px.ZT, py.ZT, pinf) + else: + raise ValueError('FE must be Fq, Fq2 or Fq12') + + +def is_on_curve_jacobian(p, ec, FE): + Q = ec.q + px = p.x + py = p.y + pz = p.z + pinf = p.infinity + if FE == Fq: + return fq_is_on_curve_jacobian(px.Z, py.Z, pz.Z, pinf) + elif FE == Fq2: + return fq2_is_on_curve_jacobian(px.ZT, py.ZT, pz.ZT, pinf) + elif FE == Fq12: + return fq12_is_on_curve_jacobian(px.ZT, py.ZT, pz.ZT, pinf) + else: + raise ValueError('FE must be Fq, Fq2 or Fq12') + + +def to_affine(p, ec, FE): + Q = ec.q + px = p.x + py = p.y + pz = p.z + pinf = p.infinity + if FE == Fq: + xr, yr, infr = fq_to_affine(px.Z, py.Z, pz.Z, pinf) + elif FE == Fq2: + xr, yr, infr = fq2_to_affine(px.ZT, py.ZT, pz.ZT, pinf) + elif FE == Fq12: + xr, yr, infr = fq12_to_affine(px.ZT, py.ZT, pz.ZT, pinf) + else: + raise ValueError('FE must be Fq, Fq2 or Fq12') + return AffinePoint(FE(Q, xr), FE(Q, yr), infr, ec) + + +def to_jacobian(p, ec, FE): + Q = ec.q + px = p.x + py = p.y + pinf = p.infinity + if FE == Fq: + xr, yr, zr, infr = fq_to_jacobian(px.Z, py.Z, pinf) + elif FE == Fq2: + xr, yr, zr, infr = fq2_to_jacobian(px.ZT, py.ZT, pinf) + elif FE == Fq12: + xr, yr, zr, infr = fq12_to_jacobian(px.ZT, py.ZT, pinf) + else: + raise ValueError('FE must be Fq, Fq2 or Fq12') + return JacobianPoint(FE(Q, xr), FE(Q, yr), FE(Q, zr), infr, ec) + + def y_for_x(x, ec=default_ec, FE=Fq): """ Solves y = sqrt(x^3 + ax + b) for both valid ys """ - if not isinstance(x, FE): + if not type(x) == FE: x = FE(ec.q, x) - u = x * x * x + ec.a * x + ec.b + # u = x * x * x + ec.a * x + ec.b + # a is 0 for bls12-381 + u = x * x * x + ec.b y = u.modsqrt() if y == 0 or not AffinePoint(x, y, False, ec).is_on_curve(): @@ -213,169 +269,47 @@ def y_for_x(x, ec=default_ec, FE=Fq): return [y, ec.q - y] -def double_point(p1, ec=default_ec, FE=Fq): +def double_point(p, ec, FE): """ Basic elliptic curve point doubling """ - x, y = p1.x, p1.y - left = 3 * x * x - left = left + ec.a - s = left / (2 * y) - new_x = s * s - x - x - new_y = s * (x - new_x) - y - return AffinePoint(new_x, new_y, False, ec) + Q = ec.q + px = p.x + py = p.y + pinf = p.infinity + if FE == Fq: + xr, yr, infr = fq_double_point(px.Z, py.Z, pinf) + elif FE == Fq2: + xr, yr, infr = fq2_double_point(px.ZT, py.ZT, pinf) + elif FE == Fq12: + xr, yr, infr = fq12_double_point(px.ZT, py.ZT, pinf) + else: + raise ValueError('FE must be Fq, Fq2 or Fq12', FE) + return AffinePoint(FE(Q, xr), FE(Q, yr), infr, ec) def add_points(p1, p2, ec=default_ec, FE=Fq): """ Basic elliptic curve point addition """ - assert(p1.is_on_curve()) - assert(p2.is_on_curve()) if p1.infinity: - return p2 - if p2.infinity: - return p1 - if p1 == p2: - return double_point(p1, ec, FE) - if p1.x == p2.x: - return AffinePoint(FE.zero(), FE.zero(), True, ec) - - x1, y1 = p1.x, p1.y - x2, y2 = p2.x, p2.y - s = (y2 - y1) / (x2 - x1) - new_x = s * s - x1 - x2 - new_y = s * (x1 - new_x) - y1 - return AffinePoint(new_x, new_y, False, ec) - - -def double_point_jacobian(p1, ec=default_ec, FE=Fq): - """ - Jacobian elliptic curve point doubling - http://www.hyperelliptic.org/EFD/oldefd/jacobian.html - """ - X, Y, Z = p1.x, p1.y, p1.z - if Y == FE.zero(ec.q) or p1.infinity: - return JacobianPoint(FE.one(ec.q), FE.one(ec.q), - FE.zero(ec.q), True, ec) + ec = p2.ec Q = ec.q - if FE == Fq2: - xr, yr, zr = double_point_jacobian_fq2(X.ZT, Y.ZT, Z.ZT, ec) - return JacobianPoint(Fq2(Q, xr), Fq2(Q, yr), Fq2(Q, zr), False, ec) - elif FE == Fq and ec == default_ec: - xr, yr, zr = double_point_jacobian_fq(X.Z, Y.Z, Z.Z, ec) - return JacobianPoint(Fq(Q, xr), Fq(Q, yr), Fq(Q, zr), False, ec) - elif FE == Fq and ec == default_ec_twist: - xr, yr, zr = double_point_jacobian_fq_twist(X.Z, Y.Z, Z.Z, ec) - return JacobianPoint(Fq2(Q, xr), Fq2(Q, yr), Fq2(Q, zr), False, ec) + x1 = p1.x + y1 = p1.y + inf1 = p1.infinity + x2 = p2.x + y2 = p2.y + inf2 = p2.infinity + if FE == Fq: + xr, yr, infr = fq_add_points(x1.Z, y1.Z, inf1, x2.Z, y2.Z, inf2) + elif FE == Fq2: + xr, yr, infr = fq2_add_points(x1.ZT, y1.ZT, inf1, x2.ZT, y2.ZT, inf2) elif FE == Fq12: - xr, yr, zr = double_point_jacobian_fq12(X.ZT, Y.ZT, Z.ZT, ec) - return JacobianPoint(Fq12(Q, xr), Fq12(Q, yr), Fq12(Q, zr), False, ec) - else: - raise ValueError('FE must be Fq, Fq2 or Fq12') - - -def double_point_jacobian_fq(X, Y, Z, ec): - '''dobule point with fq int X, Y, Z, returning tuple''' - P = ec.q - ec_a = ec.a.Z - # S = 4*X*Y^2 - S = 4*X*Y*Y % P - - Z_sq = Z*Z % P - Z_4th = Z_sq*Z_sq % P - Y_sq = Y*Y % P - Y_4th = Y_sq*Y_sq % P - - # M = 3*X^2 + a*Z^4 - M = (3*X*X % P + ec_a*Z_4th % P) % P - - # X' = M^2 - 2*S - X_p = (M*M % P - 2*S % P) % P - # Y' = M*(S - X') - 8*Y^4 - Y_p = (M*((S - X_p) % P) % P - 8*Y_4th % P) % P - # Z' = 2*Y*Z - Z_p = 2*Y*Z % P - return X_p, Y_p, Z_p - - -def double_point_jacobian_fq_twist(X, Y, Z, ec): - '''dobule point with fq int X, Y, Z, returning tuple''' - P = ec.q - ec_a = ec.a.ZT - addi_f = fq2_add_fq - subi_f = fq2_sub_fq - muli_f = fq2_mul_fq - mul_f = fq2_mul_fq2 - - # S = 4*X*Y^2 - S = 4*X*Y*Y % P - - Z_sq = Z*Z % P - Z_4th = Z_sq*Z_sq % P - Y_sq = Y*Y % P - Y_4th = Y_sq*Y_sq % P - - # M = 3*X^2 + a*Z^4 - M = addi_f(P, muli_f(P, ec_a, Z_4th), 3*X*X % P) - - # X' = M^2 - 2*S - X_p = subi_f(P, mul_f(P, M, M), 2*S % P) - # Y' = M*(S - X') - 8*Y^4 - Y_p = subi_f(P, mul_f(P, M, fq_sub_fq2(P, S, X_p)), 8*Y_4th % P) - # Z' = 2*Y*Z - Z_p = addi_f(P, (0, 0), 2*Y*Z % P) - return X_p, Y_p, Z_p - - -def double_point_jacobian_fq2(X, Y, Z, ec): - '''dobule point with fq2 tuples X, Y, Z, returning tuple of tuples''' - if ec == default_ec_twist: - mul_ec_a = fq2_mul_fq2 - ec_a = ec.a.ZT - else: - mul_ec_a = fq2_mul_fq - ec_a = ec.a.Z - func_t = (fq2_mul_fq2, fq2_mul_fq, mul_ec_a, fq2_add_fq2, fq2_sub_fq2) - return double_point_jacobian_fqx_t(func_t, X, Y, Z, ec.q, ec_a) - - -def double_point_jacobian_fq12(X, Y, Z, ec): - '''dobule point with fq12 tuples X, Y, Z, returning tuple of tuples''' - if ec == default_ec_twist: - mul_ec_a = fq12_mul_fq2 - ec_a = ec.a.ZT + xr, yr, infr = fq12_add_points(x1.ZT, y1.ZT, inf1, x2.ZT, y2.ZT, inf2) else: - mul_ec_a = fq12_mul_fq - ec_a = ec.a.Z - func_t = (fq12_mul_fq12, fq12_mul_fq, mul_ec_a, - fq12_add_fq12, fq12_sub_fq12) - return double_point_jacobian_fqx_t(func_t, X, Y, Z, ec.q, ec_a) - - -def double_point_jacobian_fqx_t(func_t, X, Y, Z, P, ec_a): - '''dobule point with tuples X, Y, Z, returning tuple of tuples, - using func_t functions tuple for operations''' - mul_f, mul_i_f, mul_ec_a, add_f, sub_f = func_t - # S = 4*X*Y^2 - S = mul_f(P, mul_f(P, mul_i_f(P, X, 4), Y), Y) - - Z_sq = mul_f(P, Z, Z) - Z_4th = mul_f(P, Z_sq, Z_sq) - Y_sq = mul_f(P, Y, Y) - Y_4th = mul_f(P, Y_sq, Y_sq) - - # M = 3*X^2 + a*Z^4 - M = mul_f(P, mul_i_f(P, X, 3), X) - M = add_f(P, mul_ec_a(P, Z_4th, ec_a), M) - - # X' = M^2 - 2*S - X_p = sub_f(P, mul_f(P, M, M), mul_i_f(P, S, 2)) - # Y' = M*(S - X') - 8*Y^4 - Y_p = sub_f(P, mul_f(P, M, sub_f(P, S, X_p)), mul_i_f(P, Y_4th, 8)) - # Z' = 2*Y*Z - Z_p = mul_f(P, mul_i_f(P, Y, 2), Z) - return X_p, Y_p, Z_p + raise ValueError('FE must be Fq, Fq2 or Fq12', FE) + return AffinePoint(FE(Q, xr), FE(Q, yr), infr, ec) def add_points_jacobian(p1, p2, ec=default_ec, FE=Fq): @@ -384,120 +318,28 @@ def add_points_jacobian(p1, p2, ec=default_ec, FE=Fq): http://www.hyperelliptic.org/EFD/oldefd/jacobian.html """ if p1.infinity: - return p2 - if p2.infinity: - return p1 - + ec = p2.ec + Q = ec.q + x1 = p1.x + y1 = p1.y + z1 = p1.z + inf1 = p1.infinity + x2 = p2.x + y2 = p2.y + z2 = p2.z + inf2 = p2.infinity if FE == Fq: - U1, U2, S1, S2 = calc_u1_u2_s1_s2_fq(p1.x.Z, p1.y.Z, p1.z.Z, - p2.x.Z, p2.y.Z, p2.z.Z, - ec) + xr, yr, zr, infr = fq_add_points_jacobian(x1.Z, y1.Z, z1.Z, inf1, + x2.Z, y2.Z, z2.Z, inf2) elif FE == Fq2: - U1, U2, S1, S2 = calc_u1_u2_s1_s2_fqx_t(fq2_mul_fq2, - p1.x.ZT, p1.y.ZT, p1.z.ZT, - p2.x.ZT, p2.y.ZT, p2.z.ZT, - ec) + xr, yr, zr, infr = fq2_add_points_jacobian(x1.ZT, y1.ZT, z1.ZT, inf1, + x2.ZT, y2.ZT, z2.ZT, inf2) elif FE == Fq12: - U1, U2, S1, S2 = calc_u1_u2_s1_s2_fqx_t(fq12_mul_fq12, - p1.x.ZT, p1.y.ZT, p1.z.ZT, - p2.x.ZT, p2.y.ZT, p2.z.ZT, - ec) - else: - raise ValueError('FE must be Fq, Fq2 or Fq12') - - if U1 == U2: - if S1 != S2: - return JacobianPoint(FE.one(ec.q), FE.one(ec.q), - FE.zero(ec.q), True, ec) - else: - return double_point_jacobian(p1, ec, FE) - - type_u1 = type(U1) - if type_u1 == int: - return calc_jp_on_fq_us(U1, U2, S1, S2, p1.z.Z, p2.z.Z, ec) - elif type_u1 == tuple and len(U1) == 2: - func_t = (fq2_mul_fq2, fq2_sub_fq2, fq2_mul_fq) - return calc_jp_on_fqx_t_us(func_t, U1, U2, S1, S2, - p1.z.ZT, p2.z.ZT, ec) - elif type_u1 == tuple and len(U1) == 12: - func_t = (fq12_mul_fq12, fq12_sub_fq12, fq12_mul_fq) - return calc_jp_on_fqx_t_us(func_t, U1, U2, S1, S2, - p1.z.ZT, p2.z.ZT, ec) + xr, yr, zr, infr = fq12_add_points_jacobian(x1.ZT, y1.ZT, z1.ZT, inf1, + x2.ZT, y2.ZT, z2.ZT, inf2) else: raise ValueError('FE must be Fq, Fq2 or Fq12') - - -def calc_u1_u2_s1_s2_fq(x1, y1, z1, x2, y2, z2, ec): - '''x, y, z inputs of type int, returning tuple of int''' - P = ec.q - # U1 = X1*Z2^2 - U1 = x1*z2*z2 % P - # U2 = X2*Z1^2 - U2 = x2*z1*z1 % P - # S1 = Y1*Z2^3 - S1 = y1*z2*z2*z2 % P - # S2 = Y2*Z1^3 - S2 = y2*z1*z1*z1 % P - return(U1, U2, S1, S2) - - -def calc_u1_u2_s1_s2_fqx_t(mul_f, x1_t, y1_t, z1_t, x2_t, y2_t, z2_t, ec): - '''x, y, z inputs of type fq2, returning tuple of fq2 tuples''' - P = ec.q - # U1 = X1*Z2^2 - U1 = mul_f(P, mul_f(P, x1_t, z2_t), z2_t) - # U2 = X2*Z1^2 - U2 = mul_f(P, mul_f(P, x2_t, z1_t), z1_t) - # S1 = Y1*Z2^3 - S1 = mul_f(P, mul_f(P, mul_f(P, y1_t, z2_t), z2_t), z2_t) - # S2 = Y2*Z1^3 - S2 = mul_f(P, mul_f(P, mul_f(P, y2_t, z1_t), z1_t), z1_t) - return(U1, U2, S1, S2) - - -def calc_jp_on_fq_us(U1, U2, S1, S2, Z1, Z2, ec): - '''calc jacobian point with int U1, U2, S1, S2, Z1, Z2''' - P = ec.q - # H = U2 - U1 - H = (U2-U1) % P - # R = S2 - S1 - R = (S2-S1) % P - H_sq = H*H % P - H_cu = H*H_sq % P - # X3 = R^2 - H^3 - 2*U1*H^2 - X3 = (R*R % P - H_cu - 2*U1*H_sq % P) % P - # Y3 = R*(U1*H^2 - X3) - S1*H^3 - Y3 = (R*(U1*H_sq % P - X3) % P - S1*H_cu % P) % P - # Z3 = H*Z1*Z2 - Z3 = H*Z1*Z2 % P - return JacobianPoint(Fq(P, X3), Fq(P, Y3), Fq(P, Z3), False, ec) - - -def calc_jp_on_fqx_t_us(func_t, U1, U2, S1, S2, Z1, Z2, ec): - '''calc jacobian point with tuples U1, U2, S1, S2, Z1, Z2, - using func_t functions tuple for operations''' - P = ec.q - mul_f, sub_f, muli_f = func_t - # H = U2 - U1 - H = sub_f(P, U2, U1) - # R = S2 - S1 - R = sub_f(P, S2, S1) - H_sq = mul_f(P, H, H) - H_cu = mul_f(P, H, H_sq) - # X3 = R^2 - H^3 - 2*U1*H^2 - X3 = sub_f(P, - sub_f(P, mul_f(P, R, R), H_cu), - mul_f(P, H_sq, muli_f(P, U1, 2))) - # Y3 = R*(U1*H^2 - X3) - S1*H^3 - Y3 = sub_f(P, - mul_f(P, R, sub_f(P, mul_f(P, U1, H_sq), X3)), - mul_f(P, S1, H_cu)) - # Z3 = H*Z1*Z2 - Z3 = mul_f(P, mul_f(P, Z1, Z2), H) - if len(U1) == 2: - return JacobianPoint(Fq2(P, X3), Fq2(P, Y3), Fq2(P, Z3), False, ec) - else: - return JacobianPoint(Fq12(P, X3), Fq12(P, Y3), Fq12(P, Z3), False, ec) + return JacobianPoint(FE(Q, xr), FE(Q, yr), FE(Q, zr), infr, ec) def scalar_mult(c, p1, ec=default_ec, FE=Fq): @@ -525,21 +367,28 @@ def scalar_mult_jacobian(c, p1, ec=default_ec, FE=Fq): Double and add: https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication """ - if p1.infinity or c % ec.q == 0: - return JacobianPoint(FE.one(ec.q), FE.one(ec.q), - FE.zero(ec.q), True, ec) - if isinstance(c, FE): + Q = ec.q + if type(c) == FE: c = c.Z - result = JacobianPoint(FE.one(ec.q), FE.one(ec.q), - FE.zero(ec.q), True, ec) - addend = p1 - while c > 0: - if c & 1: - result += addend - # double point - addend += addend - c = c >> 1 - return result + px = p1.x + py = p1.y + pz = p1.z + pinf = p1.infinity + type_p = type(px) + if type_p == Fq: + xr, yr, zr, infr = fq_scalar_mult_jacobian(c, + px.Z, py.Z, pz.Z, pinf) + return JacobianPoint(Fq(Q, xr), Fq(Q, yr), Fq(Q, zr), infr, ec) + elif type_p == Fq2: + xr, yr, zr, infr = fq2_scalar_mult_jacobian(c, + px.ZT, py.ZT, pz.ZT, pinf) + return JacobianPoint(Fq2(Q, xr), Fq2(Q, yr), Fq2(Q, zr), infr, ec) + elif type_p == Fq12: + xr, yr, zr, infr = fq12_scalar_mult_jacobian(c, + px.ZT, py.ZT, pz.ZT, pinf) + return JacobianPoint(Fq12(Q, xr), Fq12(Q, yr), Fq12(Q, zr), infr, ec) + else: + raise Exception("point should be Fq, Fq2 or Fq12 elements") def generator_Fq(ec=default_ec): @@ -556,10 +405,17 @@ def untwist(point, ec=default_ec): coordinates back from Fq2 to Fq12. See Craig Costello book, look up twists. """ - f = Fq12.one(ec.q) - wsq = Fq12(ec.q, f.root, Fq6.zero(ec.q)) - wcu = Fq12(ec.q, Fq6.zero(ec.q), f.root) - return AffinePoint(point.x / wsq, point.y / wcu, False, ec) + Q = ec.q + x = point.x + y = point.y + type_x = type(x) + if type_x == Fq2: + x_t, y_t = fq2_untwist(x.ZT, y.ZT) + elif type_x == Fq12: + x_t, y_t = fq12_untwist(x.ZT, y.ZT) + else: + raise Exception("point should be Fq2 or Fq12 elements") + return AffinePoint(Fq12(Q, x_t), Fq12(Q, y_t), False, ec) def twist(point, ec=default_ec_twist): @@ -568,12 +424,17 @@ def twist(point, ec=default_ec_twist): coordinates to a point on the twisted curve. See Craig Costello book, look up twists. """ - f = Fq12.one(ec.q) - wsq = Fq12(ec.q, f.root, Fq6.zero(ec.q)) - wcu = Fq12(ec.q, Fq6.zero(ec.q), f.root) - new_x = (point.x * wsq) - new_y = (point.y * wcu) - return AffinePoint(new_x, new_y, False, ec) + Q = ec.q + x = point.x + y = point.y + type_x = type(x) + if type_x == Fq2: + x_t, y_t = fq2_twist(x.ZT, y.ZT) + elif type_x == Fq12: + x_t, y_t = fq12_twist(x.ZT, y.ZT) + else: + raise Exception("point should be Fq2 or Fq12 elements") + return AffinePoint(Fq12(Q, x_t), Fq12(Q, y_t), False, ec) def psi(P, ec=default_ec): @@ -694,6 +555,25 @@ def hash_to_point_Fq2(m, ec=default_ec_twist): return hash_to_point_prehashed_Fq2(h, ec) +try: + from .fields_t import ( + fq_is_on_curve_affine, fq2_is_on_curve_affine, fq12_is_on_curve_affine, + fq_is_on_curve_jacobian, fq2_is_on_curve_jacobian, + fq12_is_on_curve_jacobian, fq_to_jacobian, fq2_to_jacobian, + fq12_to_jacobian, fq_to_affine, fq2_to_affine, fq12_to_affine, + fq_double_point, fq2_double_point, fq12_double_point, + fq_add_points, fq2_add_points, fq12_add_points, + fq2_twist, fq12_twist, fq2_untwist, fq12_untwist, + fq_scalar_mult_jacobian, fq2_scalar_mult_jacobian, + fq12_scalar_mult_jacobian, fq_add_points_jacobian, + fq2_add_points_jacobian, fq12_add_points_jacobian, + fq_double_point_jacobian, fq2_double_point_jacobian, + fq12_double_point_jacobian + ) +except ImportError as e: + logging.error(f'Can not import from fields_t_c: {e}') + + """ Copyright 2018 Chia Network Inc diff --git a/bls_py/fields.py b/bls_py/fields.py index 1388488..4dcbdf9 100644 --- a/bls_py/fields.py +++ b/bls_py/fields.py @@ -1,18 +1,21 @@ # -*- coding: utf-8 -*- -from .fields_t import (fq_invert, fq_pow, fq_floordiv, fq2_neg, fq2_invert, - fq2_pow, fq2_qi_pow, fq2_mul_by_nonresidue, fq2_add_fq2, - fq2_add_fq, fq2_sub_fq2, fq2_sub_fq, fq_sub_fq2, - fq2_mul_fq2, fq2_mul_fq, fq12_mul_fq2, fq12_invert, +from .fields_t import (fq_invert, fq_floordiv, fq_pow, + fq2_neg, fq2_invert, fq2_floordiv, + fq2_pow, fq2_qi_pow, fq2_mul_by_nonresidue, + fq2_add, fq2_mul, + fq2_add_fq, fq2_sub, fq2_sub_fq, fq_sub_fq2, + fq2_mul_fq, fq12_mul_fq2, fq12_invert, + fq6_add, fq6_mul, fq6_floordiv, fq6_mul_fq2, fq6_neg, fq6_invert, fq6_pow, fq6_qi_pow, - fq6_mul_by_nonresidue, fq6_add_fq6, fq6_add_fq2, - fq6_add_fq, fq6_sub_fq6, fq6_sub_fq2, fq6_sub_fq, - fq2_sub_fq6, fq_sub_fq6, fq6_mul_fq6, fq6_mul_fq, - fq12_mul_fq6, fq12_neg, fq12_pow, fq12_qi_pow, - fq12_add_fq12, fq12_add_fq, fq12_add_fq6, fq12_add_fq2, - fq12_sub_fq12, fq12_sub_fq, fq12_sub_fq6, fq12_sub_fq2, - fq_sub_fq12, fq6_sub_fq12, fq2_sub_fq12, fq12_mul_fq12, - fq12_mul_fq) + fq6_mul_by_nonresidue, fq6_add_fq2, + fq6_add_fq, fq6_sub, fq6_sub_fq2, fq6_sub_fq, + fq2_sub_fq6, fq_sub_fq6, fq6_mul_fq, fq12_floordiv, + fq12_pow, fq12_mul_fq, fq12_add, fq12_mul, + fq12_mul_fq6, fq12_neg, fq12_qi_pow, + fq12_add_fq, fq12_add_fq6, fq12_add_fq2, + fq12_sub, fq12_sub_fq, fq12_sub_fq6, fq12_sub_fq2, + fq_sub_fq12, fq6_sub_fq12, fq2_sub_fq12) bls12381_q = int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf' @@ -370,13 +373,13 @@ def __repr__(self): return ('Fq2(Q, %s)' % ', '.join(repr(fq) for fq in self)) def __neg__(self): - return Fq2(self.Q, fq2_neg(self.Q, self.ZT)) + return Fq2(self.Q, fq2_neg(self.ZT)) def __invert__(self): - return Fq2(self.Q, fq2_invert(self.Q, self.ZT)) + return Fq2(self.Q, fq2_invert(self.ZT)) def __pow__(self, e): - return Fq2(self.Q, fq2_pow(self.Q, self.ZT, e)) + return Fq2(self.Q, fq2_pow(self.ZT, e)) def qi_power(self, i): global bls12381_q @@ -385,21 +388,21 @@ def qi_power(self, i): i %= 2 if i == 0: return self - return Fq2(self.Q, fq2_qi_pow(self.Q, self.ZT, i)) + return Fq2(self.Q, fq2_qi_pow(self.ZT, i)) def mul_by_nonresidue(self): # multiply by u + 1 - return Fq2(self.Q, fq2_mul_by_nonresidue(self.Q, self.ZT)) + return Fq2(self.Q, fq2_mul_by_nonresidue(self.ZT)) def __add__(self, other): Q = self.Q tx = type(other) if tx == Fq2: - return Fq2(Q, fq2_add_fq2(Q, self.ZT, other.ZT)) + return Fq2(Q, fq2_add(self.ZT, other.ZT)) elif tx == int: - return Fq2(Q, fq2_add_fq(Q, self.ZT, other)) + return Fq2(Q, fq2_add_fq(self.ZT, other)) elif tx == Fq: - return Fq2(Q, fq2_add_fq(Q, self.ZT, other.Z)) + return Fq2(Q, fq2_add_fq(self.ZT, other.Z)) else: return NotImplemented @@ -407,11 +410,11 @@ def __sub__(self, other): Q = self.Q tx = type(other) if tx == Fq2: - return Fq2(Q, fq2_sub_fq2(Q, self.ZT, other.ZT)) + return Fq2(Q, fq2_sub(self.ZT, other.ZT)) elif tx == int: - return Fq2(Q, fq2_sub_fq(Q, self.ZT, other)) + return Fq2(Q, fq2_sub_fq(self.ZT, other)) elif tx == Fq: - return Fq2(Q, fq2_sub_fq(Q, self.ZT, other.Z)) + return Fq2(Q, fq2_sub_fq(self.ZT, other.Z)) else: return NotImplemented @@ -419,11 +422,11 @@ def __rsub__(self, other): Q = self.Q tx = type(other) if tx == Fq2: - return Fq2(Q, fq2_sub_fq2(Q, other.ZT, self.ZT)) + return Fq2(Q, fq2_sub(other.ZT, self.ZT)) elif tx == int: - return Fq2(Q, fq_sub_fq2(Q, other, self.ZT)) + return Fq2(Q, fq_sub_fq2(other, self.ZT)) elif tx == Fq: - return Fq2(Q, fq_sub_fq2(Q, other.Z, self.ZT)) + return Fq2(Q, fq_sub_fq2(other.Z, self.ZT)) else: return NotImplemented @@ -431,11 +434,11 @@ def __mul__(self, other): Q = self.Q tx = type(other) if tx == Fq2: - return Fq2(Q, fq2_mul_fq2(Q, self.ZT, other.ZT)) + return Fq2(Q, fq2_mul(self.ZT, other.ZT)) elif tx == int: - return Fq2(Q, fq2_mul_fq(Q, self.ZT, other)) + return Fq2(Q, fq2_mul_fq(self.ZT, other)) elif tx == Fq: - return Fq2(Q, fq2_mul_fq(Q, self.ZT, other.Z)) + return Fq2(Q, fq2_mul_fq(self.ZT, other.Z)) else: return NotImplemented @@ -443,15 +446,15 @@ def __floordiv__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_mul_fq2(Q, fq12_invert(Q, other.ZT), self.ZT)) + return Fq12(Q, fq12_mul_fq2(fq12_invert(other.ZT), self.ZT)) elif tx == Fq6: - return Fq6(Q, fq6_mul_fq2(Q, fq2_invert(Q, other.ZT), self.ZT)) + return Fq6(Q, fq6_mul_fq2(fq2_invert(other.ZT), self.ZT)) elif tx == Fq2: - return Fq2(Q, fq2_mul_fq2(Q, self.ZT, fq2_invert(Q, other.ZT))) + return Fq2(Q, fq2_floordiv(self.ZT, other.ZT)) elif tx == int: - return Fq2(Q, fq2_mul_fq(Q, self.ZT, fq_invert(Q, other))) + return Fq2(Q, fq2_mul_fq(self.ZT, fq_invert(Q, other))) elif tx == Fq: - return Fq2(Q, fq2_mul_fq(Q, self.ZT, fq_invert(Q, other.Z))) + return Fq2(Q, fq2_mul_fq(self.ZT, fq_invert(Q, other.Z))) else: return NotImplemented @@ -522,13 +525,13 @@ def __repr__(self): return ('Fq6(Q, %s)' % ', '.join(repr(fq2) for fq2 in self)) def __neg__(self): - return Fq6(self.Q, fq6_neg(self.Q, self.ZT)) + return Fq6(self.Q, fq6_neg(self.ZT)) def __invert__(self): - return Fq6(self.Q, fq6_invert(self.Q, self.ZT)) + return Fq6(self.Q, fq6_invert(self.ZT)) def __pow__(self, e): - return Fq6(self.Q, fq6_pow(self.Q, self.ZT, e)) + return Fq6(self.Q, fq6_pow(self.ZT, e)) def qi_power(self, i): global bls12381_q @@ -537,23 +540,23 @@ def qi_power(self, i): i %= 6 if i == 0: return self - return Fq6(self.Q, fq6_qi_pow(self.Q, self.ZT, i)) + return Fq6(self.Q, fq6_qi_pow(self.ZT, i)) def mul_by_nonresidue(self): # multiply by v - return Fq6(self.Q, fq6_mul_by_nonresidue(self.Q, self.ZT)) + return Fq6(self.Q, fq6_mul_by_nonresidue(self.ZT)) def __add__(self, other): Q = self.Q tx = type(other) if tx == Fq6: - return Fq6(Q, fq6_add_fq6(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_add(self.ZT, other.ZT)) elif tx == Fq2: - return Fq6(Q, fq6_add_fq2(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_add_fq2(self.ZT, other.ZT)) elif tx == Fq: - return Fq6(Q, fq6_add_fq(Q, self.ZT, other.Z)) + return Fq6(Q, fq6_add_fq(self.ZT, other.Z)) elif tx == int: - return Fq6(Q, fq6_add_fq(Q, self.ZT, other)) + return Fq6(Q, fq6_add_fq(self.ZT, other)) else: return NotImplemented @@ -561,13 +564,13 @@ def __sub__(self, other): Q = self.Q tx = type(other) if tx == Fq6: - return Fq6(Q, fq6_sub_fq6(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_sub(self.ZT, other.ZT)) elif tx == Fq2: - return Fq6(Q, fq6_sub_fq2(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_sub_fq2(self.ZT, other.ZT)) elif tx == Fq: - return Fq6(Q, fq6_sub_fq(Q, self.ZT, other.Z)) + return Fq6(Q, fq6_sub_fq(self.ZT, other.Z)) elif tx == int: - return Fq6(Q, fq6_sub_fq(Q, self.ZT, other)) + return Fq6(Q, fq6_sub_fq(self.ZT, other)) else: return NotImplemented @@ -575,13 +578,13 @@ def __rsub__(self, other): Q = self.Q tx = type(other) if tx == Fq6: - return Fq6(Q, fq6_sub_fq6(Q, other.ZT, self.ZT)) + return Fq6(Q, fq6_sub(other.ZT, self.ZT)) elif tx == Fq2: - return Fq6(Q, fq2_sub_fq6(Q, other.ZT, self.ZT)) + return Fq6(Q, fq2_sub_fq6(other.ZT, self.ZT)) elif tx == Fq: - return Fq6(Q, fq_sub_fq6(Q, other.Z, self.ZT)) + return Fq6(Q, fq_sub_fq6(other.Z, self.ZT)) elif tx == int: - return Fq6(Q, fq_sub_fq6(Q, other, self.ZT)) + return Fq6(Q, fq_sub_fq6(other, self.ZT)) else: return NotImplemented @@ -589,13 +592,13 @@ def __mul__(self, other): Q = self.Q tx = type(other) if tx == Fq6: - return Fq6(Q, fq6_mul_fq6(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_mul(self.ZT, other.ZT)) elif tx == Fq2: - return Fq6(Q, fq6_mul_fq2(Q, self.ZT, other.ZT)) + return Fq6(Q, fq6_mul_fq2(self.ZT, other.ZT)) elif tx == Fq: - return Fq6(Q, fq6_mul_fq(Q, self.ZT, other.Z)) + return Fq6(Q, fq6_mul_fq(self.ZT, other.Z)) elif tx == int: - return Fq6(Q, fq6_mul_fq(Q, self.ZT, other)) + return Fq6(Q, fq6_mul_fq(self.ZT, other)) else: return NotImplemented @@ -603,15 +606,15 @@ def __floordiv__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_mul_fq6(Q, fq12_invert(Q, other.ZT), self.ZT)) + return Fq12(Q, fq12_mul_fq6(fq12_invert(other.ZT), self.ZT)) elif tx == Fq6: - return Fq6(Q, fq6_mul_fq6(Q, self.ZT, fq6_invert(Q, other.ZT))) + return Fq6(Q, fq6_floordiv(self.ZT, other.ZT)) elif tx == Fq2: - return Fq6(Q, fq6_mul_fq2(Q, self.ZT, fq2_invert(Q, other.ZT))) + return Fq6(Q, fq6_mul_fq2(self.ZT, fq2_invert(other.ZT))) elif tx == Fq: - return Fq6(Q, fq6_mul_fq(Q, self.ZT, fq_invert(Q, other.Z))) + return Fq6(Q, fq6_mul_fq(self.ZT, fq_invert(Q, other.Z))) elif tx == int: - return Fq6(Q, fq6_mul_fq(Q, self.ZT, fq_invert(Q, other))) + return Fq6(Q, fq6_mul_fq(self.ZT, fq_invert(Q, other))) else: return NotImplemented @@ -661,13 +664,13 @@ def __repr__(self): return ('Fq12(Q, %s)' % ', '.join(repr(fq6) for fq6 in self)) def __neg__(self): - return Fq12(self.Q, fq12_neg(self.Q, self.ZT)) + return Fq12(self.Q, fq12_neg(self.ZT)) def __invert__(self): - return Fq12(self.Q, fq12_invert(self.Q, self.ZT)) + return Fq12(self.Q, fq12_invert(self.ZT)) def __pow__(self, e): - return Fq12(self.Q, fq12_pow(self.Q, self.ZT, e)) + return Fq12(self.Q, fq12_pow(self.ZT, e)) def qi_power(self, i): global bls12381_q @@ -676,21 +679,21 @@ def qi_power(self, i): i %= 12 if i == 0: return self - return Fq12(self.Q, fq12_qi_pow(self.Q, self.ZT, i)) + return Fq12(self.Q, fq12_qi_pow(self.ZT, i)) def __add__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_add_fq12(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_add(self.ZT, other.ZT)) elif tx == Fq: - return Fq12(Q, fq12_add_fq(Q, self.ZT, other.Z)) + return Fq12(Q, fq12_add_fq(self.ZT, other.Z)) elif tx == Fq6: - return Fq12(Q, fq12_add_fq6(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_add_fq6(self.ZT, other.ZT)) elif tx == Fq2: - return Fq12(Q, fq12_add_fq2(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_add_fq2(self.ZT, other.ZT)) elif tx == int: - return Fq12(Q, fq12_add_fq(Q, self.ZT, other)) + return Fq12(Q, fq12_add_fq(self.ZT, other)) else: return NotImplemented @@ -698,15 +701,15 @@ def __sub__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_sub_fq12(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_sub(self.ZT, other.ZT)) elif tx == Fq: - return Fq12(Q, fq12_sub_fq(Q, self.ZT, other.Z)) + return Fq12(Q, fq12_sub_fq(self.ZT, other.Z)) elif tx == Fq6: - return Fq12(Q, fq12_sub_fq6(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_sub_fq6(self.ZT, other.ZT)) elif tx == Fq2: - return Fq12(Q, fq12_sub_fq2(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_sub_fq2(self.ZT, other.ZT)) elif tx == int: - return Fq12(Q, fq12_sub_fq(Q, self.ZT, other)) + return Fq12(Q, fq12_sub_fq(self.ZT, other)) else: return NotImplemented @@ -714,15 +717,15 @@ def __rsub__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_sub_fq12(Q, other.ZT, self.ZT)) + return Fq12(Q, fq12_sub(other.ZT, self.ZT)) elif tx == Fq: - return Fq12(Q, fq_sub_fq12(Q, other.Z, self.ZT)) + return Fq12(Q, fq_sub_fq12(other.Z, self.ZT)) elif tx == Fq6: - return Fq12(Q, fq6_sub_fq12(Q, other.ZT, self.ZT)) + return Fq12(Q, fq6_sub_fq12(other.ZT, self.ZT)) elif tx == Fq2: - return Fq12(Q, fq2_sub_fq12(Q, other.ZT, self.ZT)) + return Fq12(Q, fq2_sub_fq12(other.ZT, self.ZT)) elif tx == int: - return Fq12(Q, fq_sub_fq12(Q, other, self.ZT)) + return Fq12(Q, fq_sub_fq12(other, self.ZT)) else: return NotImplemented @@ -730,15 +733,15 @@ def __mul__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_mul_fq12(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_mul(self.ZT, other.ZT)) elif tx == int: - return Fq12(Q, fq12_mul_fq(Q, self.ZT, other)) + return Fq12(Q, fq12_mul_fq(self.ZT, other)) elif tx == Fq: - return Fq12(Q, fq12_mul_fq(Q, self.ZT, other.Z)) + return Fq12(Q, fq12_mul_fq(self.ZT, other.Z)) elif tx == Fq2: - return Fq12(Q, fq12_mul_fq2(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_mul_fq2(self.ZT, other.ZT)) elif tx == Fq6: - return Fq12(Q, fq12_mul_fq6(Q, self.ZT, other.ZT)) + return Fq12(Q, fq12_mul_fq6(self.ZT, other.ZT)) else: return NotImplemented @@ -746,15 +749,15 @@ def __floordiv__(self, other): Q = self.Q tx = type(other) if tx == Fq12: - return Fq12(Q, fq12_mul_fq12(Q, self.ZT, fq12_invert(Q, other.ZT))) + return Fq12(Q, fq12_floordiv(self.ZT, other.ZT)) elif tx == int: - return Fq12(Q, fq12_mul_fq12(Q, self.ZT, fq_invert(Q, other))) + return Fq12(Q, fq12_mul(self.ZT, fq_invert(Q, other))) elif tx == Fq: - return Fq12(Q, fq12_mul_fq12(Q, self.ZT, fq_invert(Q, other.Z))) + return Fq12(Q, fq12_mul(self.ZT, fq_invert(Q, other.Z))) elif tx == Fq2: - return Fq12(Q, fq12_mul_fq2(Q, self.ZT, fq2_invert(Q, other.ZT))) + return Fq12(Q, fq12_mul_fq2(self.ZT, fq2_invert(other.ZT))) elif tx == Fq6: - return Fq12(Q, fq12_mul_fq6(Q, self.ZT, fq6_invert(Q, other.ZT))) + return Fq12(Q, fq12_mul_fq6(self.ZT, fq6_invert(other.ZT))) else: return NotImplemented diff --git a/bls_py/fields_t.py b/bls_py/fields_t.py index 9fc3665..67b4d85 100644 --- a/bls_py/fields_t.py +++ b/bls_py/fields_t.py @@ -14,11 +14,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -bls12381_q = int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf' - '6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab', 16) +import logging -FQ2_ROOT = -1 % bls12381_q +bls12381_q = Q = int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf' + '6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab', 16) +bls12381_n = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +bls12381_b = 0x4 +bls12381_x = -0xd201000000010000 +bls12381_nx = 0xd201000000010000 + + +# twist/untwist inverse constants +tw1 = int('0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895' + 'fb39869507b587b120f55ffff58a9ffffdcff7fffffffd556', 16) +tw2 = int('0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895' + 'fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555', 16) + + +FQ2_ROOT = -1 % Q FQ2_ONE_TUPLE = (1, 0) FQ2_ZERO_TUPLE = (0, 0) FQ6_ROOT_TUPLE = (1, 1) @@ -27,6 +41,7 @@ FQ12_ROOT_TUPLE = (0, 0, 1, 0, 0, 0) FQ12_ONE_TUPLE = (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) FQ12_ZERO_TUPLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +FINAL_EXP_E = (pow(Q, 4) - pow(Q, 2) + 1) // bls12381_n def fq_invert(P, a): @@ -57,477 +72,1060 @@ def fq_floordiv(P, a, X): return a * fq_invert(P, X) % P -def fq2_neg(P, t_a): +def fq2_neg(t_a): '''Neg tuple t_a returning tuple''' a, b = t_a - return (-a % P, -b % P) + return (-a % Q, -b % Q) -def fq2_invert(P, t_a): +def fq2_invert(t_a): '''Invert tuple t_a returning tuple''' a, b = t_a - factor = fq_invert(P, a * a + b * b) - return ((a*factor) % P, (-b*factor) % P) + factor = fq_invert(Q, a * a + b * b) + return ((a*factor) % Q, (-b*factor) % Q) + +def fq2_floordiv(t_a, t_x): + return fq2_mul(t_a, fq2_invert(t_x)) -def fq2_pow(P, t_a, e): + +def fq2_pow(t_a, e): '''Pow tuple t_a returning tuple''' m, n = t_a a, b = 1, 0 - fq2r = FQ2_ROOT while e: if e & 1: - a, b = (a*m + b*n*fq2r) % P, (a*n + b*m) % P - m, n = (m*m + n*n*fq2r) % P, (m*n + n*m) % P + a, b = (a*m - b*n) % Q, (a*n + b*m) % Q + m, n = (m*m - n*n) % Q, (m*n + n*m) % Q e >>= 1 return (a, b) -def fq2_qi_pow(P, t_x, i): +def fq2_qi_pow(t_x, i): '''Calc qi_power on t_x tuple returning tuple''' - global bls12381_q, frob_coeffs - if P != bls12381_q: - raise NotImplementedError + global frob_coeffs i %= 2 if i == 0: return t_x - return (t_x[0], t_x[1]*frob_coeffs[2, i, 1] % P) + return (t_x[0], t_x[1]*frob_coeffs[2, i, 1] % Q) -def fq2_mul_by_nonresidue(P, t_a): +def fq2_mul_by_nonresidue(t_a): '''Mul by nonresidue on tuple t_a returning tuple''' a, b = t_a - return ((a-b) % P, (a+b) % P) + return ((a-b) % Q, (a+b) % Q) -def fq2_add_fq(P, t_a, m): +def fq2_add_fq(t_a, m): '''Add tuple t_a and int m returning tuple''' a, b = t_a - return ((a+m) % P, b) + return ((a+m) % Q, b) -def fq2_add_fq2(P, t_a, t_m): +def fq2_add(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b = t_a m, n = t_m - return ((a+m) % P, (b+n) % P) + return ((a+m) % Q, (b+n) % Q) -def fq_sub_fq2(P, a, t_m): +def fq_sub_fq2(a, t_m): '''Sub tuple t_m from int a returning tuple''' m, n = t_m - return ((a-m) % P, -n % P) + return ((a-m) % Q, -n % Q) -def fq2_sub_fq(P, t_a, m): +def fq2_sub_fq(t_a, m): '''Sub int m from tuple t_a returning tuple''' a, b = t_a - return ((a-m) % P, b) + return ((a-m) % Q, b) -def fq2_sub_fq2(P, t_a, t_m): +def fq2_sub(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b = t_a m, n = t_m - return ((a-m) % P, (b-n) % P) + return ((a-m) % Q, (b-n) % Q) -def fq2_mul_fq(P, t_a, m): +def fq2_mul_fq(t_a, m): '''Multiple tuple t_a on int m returning tuple''' a, b = t_a - return (a*m % P, b*m % P) + return (a*m % Q, b*m % Q) -def fq2_mul_fq2(P, t_a, t_m): +def fq2_mul(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b = t_a m, n = t_m - return ((a*m + b*n*FQ2_ROOT) % P, (a*n + b*m) % P) + return ((a*m - b*n) % Q, (a*n + b*m) % Q) -def fq6_neg(P, t_a): +def fq6_neg(t_a): '''Neg tuple t_a returning tuple''' a, b, c, d, e, f = t_a - return (-a % P, -b % P, -c % P, -d % P, -e % P, -f % P) + return (-a % Q, -b % Q, -c % Q, -d % Q, -e % Q, -f % Q) -def fq6_invert(P, t_x): +def fq6_invert(t_x): '''Invert tuple t_a returning tuple''' a, b, c = t_x[:2], t_x[2:4], t_x[4:] - g0 = fq2_mul_fq2(P, a, a) - g0 = fq2_sub_fq2(P, g0, fq2_mul_fq2(P, b, fq2_mul_by_nonresidue(P, c))) - g1 = fq2_sub_fq2(P, fq2_mul_by_nonresidue(P, fq2_mul_fq2(P, c, c)), - fq2_mul_fq2(P, a, b)) - g2 = fq2_sub_fq2(P, fq2_mul_fq2(P, b, b), fq2_mul_fq2(P, a, c)) - g0a = fq2_mul_fq2(P, g0, a) - g1cpg2b = fq2_add_fq2(P, fq2_mul_fq2(P, g1, c), fq2_mul_fq2(P, g2, b)) - factor = fq2_invert(P, fq2_add_fq2(P, g0a, - fq2_mul_by_nonresidue(P, g1cpg2b))) - ar, br = fq2_mul_fq2(P, g0, factor) - cr, dr = fq2_mul_fq2(P, g1, factor) - er, fr = fq2_mul_fq2(P, g2, factor) - return (ar % P, br % P, cr % P, dr % P, er % P, fr % P) - - -def fq6_pow(P, t_a, e): + g0 = fq2_mul(a, a) + g0 = fq2_sub(g0, fq2_mul(b, fq2_mul_by_nonresidue(c))) + g1 = fq2_sub(fq2_mul_by_nonresidue(fq2_mul(c, c)), + fq2_mul(a, b)) + g2 = fq2_sub(fq2_mul(b, b), fq2_mul(a, c)) + g0a = fq2_mul(g0, a) + g1cpg2b = fq2_add(fq2_mul(g1, c), fq2_mul(g2, b)) + factor = fq2_invert(fq2_add(g0a, fq2_mul_by_nonresidue(g1cpg2b))) + ar, br = fq2_mul(g0, factor) + cr, dr = fq2_mul(g1, factor) + er, fr = fq2_mul(g2, factor) + return (ar % Q, br % Q, cr % Q, dr % Q, er % Q, fr % Q) + + +def fq6_floordiv(t_a, t_x): + return fq6_mul(t_a, fq6_invert(t_x)) + + +def fq6_pow(t_a, e): '''Pow tuple t_a returning tuple''' t_ans = FQ6_ONE_TUPLE while e: if e & 1: - t_ans = fq6_mul_fq6(P, t_ans, t_a) - t_a = fq6_mul_fq6(P, t_a, t_a) + t_ans = fq6_mul(t_ans, t_a) + t_a = fq6_mul(t_a, t_a) e >>= 1 a, b, c, d, e, f = t_ans - return (a % P, b % P, c % P, d % P, e % P, f % P) + return (a % Q, b % Q, c % Q, d % Q, e % Q, f % Q) -def fq6_qi_pow(P, t_x, i): +def fq6_qi_pow(t_x, i): '''Calc qi_power on t_x tuple returning tuple''' - global bls12381_q, frob_coeffs - if P != bls12381_q: - raise NotImplementedError + global frob_coeffs i %= 6 if i == 0: return t_x - a, b = fq2_qi_pow(P, t_x[:2], i) - c, d = fq2_mul_fq2(P, fq2_qi_pow(P, t_x[2:4], i), frob_coeffs[6, i, 1]) - e, f = fq2_mul_fq2(P, fq2_qi_pow(P, t_x[4:6], i), frob_coeffs[6, i, 2]) + a, b = fq2_qi_pow(t_x[:2], i) + c, d = fq2_mul(fq2_qi_pow(t_x[2:4], i), frob_coeffs[6, i, 1]) + e, f = fq2_mul(fq2_qi_pow(t_x[4:6], i), frob_coeffs[6, i, 2]) return (a, b, c, d, e, f) -def fq6_mul_by_nonresidue(P, t_x): +def fq6_mul_by_nonresidue(t_x): '''Mul by nonresidue on tuple t_a returning tuple''' - ar, br = fq2_mul_fq2(P, t_x[4:], FQ6_ROOT_TUPLE) + ar, br = fq2_mul(t_x[4:], FQ6_ROOT_TUPLE) cr, dr = t_x[:2] er, fr = t_x[2:4] return (ar, br, cr, dr, er, fr) -def fq6_add_fq(P, t_a, m): +def fq6_add_fq(t_a, m): '''Add tuple t_a and int m returning tuple''' a, b, c, d, e, f = t_a - return ((a+m) % P, b, c, d, e, f) + return ((a+m) % Q, b, c, d, e, f) -def fq6_add_fq2(P, t_a, t_m): +def fq6_add_fq2(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b, c, d, e, f = t_a m, n = t_m - return ((a+m) % P, (b+n) % P, c, d, e, f) + return ((a+m) % Q, (b+n) % Q, c, d, e, f) -def fq6_add_fq6(P, t_a, t_m): +def fq6_add(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b, c, d, e, f = t_a m, n, o, p, q, r = t_m - return ((a+m) % P, (b+n) % P, (c+o) % P, - (d+p) % P, (e+q) % P, (f+r) % P) + return ((a+m) % Q, (b+n) % Q, (c+o) % Q, + (d+p) % Q, (e+q) % Q, (f+r) % Q) -def fq_sub_fq6(P, a, t_m): +def fq_sub_fq6(a, t_m): '''Sub tuple t_m from int a returning tuple''' m, n, o, p, q, r = t_m - return ((a-m) % P, -n % P, -o % P, -p % P, -q % P, -r % P) + return ((a-m) % Q, -n % Q, -o % Q, -p % Q, -q % Q, -r % Q) -def fq6_sub_fq(P, t_a, m): +def fq6_sub_fq(t_a, m): '''Sub int m from tuple t_a returning tuple''' a, b, c, d, e, f = t_a - return ((a-m) % P, b, c, d, e, f) + return ((a-m) % Q, b, c, d, e, f) -def fq2_sub_fq6(P, t_a, t_m): +def fq2_sub_fq6(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b = t_a m, n, o, p, q, r = t_m - return ((a-m) % P, (b-n) % P, -o % P, -p % P, -q % P, -r % P) + return ((a-m) % Q, (b-n) % Q, -o % Q, -p % Q, -q % Q, -r % Q) -def fq6_sub_fq2(P, t_a, t_m): +def fq6_sub_fq2(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f = t_a m, n = t_m - return ((a-m) % P, (b-n) % P, c, d, e, f) + return ((a-m) % Q, (b-n) % Q, c, d, e, f) -def fq6_sub_fq6(P, t_a, t_m): +def fq6_sub(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f = t_a m, n, o, p, q, r = t_m - return ((a-m) % P, (b-n) % P, (c-o) % P, - (d-p) % P, (e-q) % P, (f-r) % P) + return ((a-m) % Q, (b-n) % Q, (c-o) % Q, + (d-p) % Q, (e-q) % Q, (f-r) % Q) -def fq6_mul_fq(P, t_a, m): +def fq6_mul_fq(t_a, m): '''Multiple tuple t_a on int m returning tuple''' a, b, c, d, e, f = t_a - return (a*m % P, b*m % P, c*m % P, d*m % P, e*m % P, f*m % P) + return (a*m % Q, b*m % Q, c*m % Q, d*m % Q, e*m % Q, f*m % Q) -def fq6_mul_fq2(P, t_a, t_m): +def fq6_mul_fq2(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b, c, d, e, f = t_a m, n = t_m - fq2r = FQ2_ROOT - return ((a*m + b*n*fq2r) % P, (a*n + b*m) % P, - (c*m + d*n*fq2r) % P, (c*n + d*m) % P, - (e*m + f*n*fq2r) % P, (e*n + f*m) % P) + return ((a*m - b*n) % Q, (a*n + b*m) % Q, + (c*m - d*n) % Q, (c*n + d*m) % Q, + (e*m - f*n) % Q, (e*n + f*m) % Q) -def fq6_mul_fq6(P, t_a, t_m): +def fq6_mul(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b, c, d, e, f = t_a m, n, o, p, q, r = t_m - fq2r = FQ2_ROOT - dnfq2r = d*n*fq2r; drfq2r = d*r*fq2r - fpfq2r = f*p*fq2r; frfq2r = f*r*fq2r - cq = c*q; cr = c*r; dq = d*q; eo = e*o; ep = e*p; fo = f*o - cm = c*m; cn = c*n; dm = d*m; eq = e*q; er = e*r; fq = f*q - mul_a = (a*m + b*n*fq2r + cq + drfq2r + (cr + dq)*fq2r + - eo + fpfq2r + (ep + fo)*fq2r) - mul_b = (a*n + b*m + cq + drfq2r + cr + dq + eo + fpfq2r + ep + fo) - mul_c = (a*o + b*p*fq2r + cm + dnfq2r + eq + frfq2r + (er + fq)*fq2r) - mul_d = (a*p + b*o + cn + dm + eq + frfq2r + er + fq) - mul_e = (a*q + b*r*fq2r + c*o + d*p*fq2r + e*m + f*n*fq2r) - mul_f = (a*r + b*q + c*p + d*o + e*n + f*m) - return (mul_a % P, mul_b % P, mul_c % P, mul_d % P, mul_e % P, mul_f % P) - - -def fq12_neg(P, t_a): + #0 am - bn + cq - cr - dr - dq + eo - ep - fp - fo + #1 an + bm + cq + cr - dr + dq + eo + ep - fp + fo + #2 ao - bp + cm - dn + eq - er - fr - fq + #3 ap + bo + cn + dm + eq + er - fr + fq + #4 aq - br + co - dp + em - fn + #5 ar + bq + cp + do + en + fm + + am = a*m; an = a*n; ao = a*o; ap = a*p; aq = a*q; ar = a*r; + bn = b*n; bm = b*m; bp = b*p; bo = b*o; br = b*r; bq = b*q; + cq = c*q; cm = c*m; cn = c*n; co = c*o; cp = c*p; cr = c*r; + dn = d*n; dm = d*m; dp = d*p; do = d*o; dr = d*r; dq = d*q; + eq = e*q; em = e*m; en = e*n; eo = e*o; ep = e*p; er = e*r; + fn = f*n; fm = f*m; fq = f*q; fp = f*p; fo = f*o; fr = f*r + + r0 = am - bn + cq - cr - dr - dq + eo - ep - fp - fo + r1 = an + bm + cq + cr - dr + dq + eo + ep - fp + fo + r2 = ao - bp + cm - dn + eq - er - fr - fq + r3 = ap + bo + cn + dm + eq + er - fr + fq + r4 = aq - br + co - dp + em - fn + r5 = ar + bq + cp + do + en + fm + + return (r0 % Q, r1 % Q, r2 % Q, r3 % Q, r4 % Q, r5 % Q) + + +def fq12_neg(t_a): '''Neg tuple t_a returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a - return (-a % P, -b % P, -c % P, -d % P, -e % P, -f % P, - -g % P, -h % P, -i % P, -j % P, -k % P, -l % P) + return (-a % Q, -b % Q, -c % Q, -d % Q, -e % Q, -f % Q, + -g % Q, -h % Q, -i % Q, -j % Q, -k % Q, -l % Q) -def fq12_invert(P, t_x): +def fq12_invert(t_x): '''Invert tuple t_a returning tuple''' a, b = t_x[:6], t_x[6:12] - aa = fq6_mul_fq6(P, a, a) - bb = fq6_mul_fq6(P, b, b) - factor = fq6_invert(P, fq6_sub_fq6(P, aa, fq6_mul_by_nonresidue(P, bb))) - ar, br, cr, dr, er, fr = fq6_mul_fq6(P, a, factor) - gr, hr, ir, jr, kr, lr = fq6_mul_fq6(P, fq6_neg(P, b), factor) - return (ar % P, br % P, cr % P, dr % P, er % P, fr % P, - gr % P, hr % P, ir % P, jr % P, kr % P, lr % P) + aa = fq6_mul(a, a) + bb = fq6_mul(b, b) + factor = fq6_invert(fq6_sub(aa, fq6_mul_by_nonresidue(bb))) + ar, br, cr, dr, er, fr = fq6_mul(a, factor) + gr, hr, ir, jr, kr, lr = fq6_mul(fq6_neg(b), factor) + return (ar % Q, br % Q, cr % Q, dr % Q, er % Q, fr % Q, + gr % Q, hr % Q, ir % Q, jr % Q, kr % Q, lr % Q) + +def fq12_floordiv(t_a, t_x): + return fq12_mul(t_a, fq12_invert(t_x)) -def fq12_pow(P, t_a, e): + +def fq12_pow(t_a, e): '''Pow tuple t_a returning tuple''' t_ans = FQ12_ONE_TUPLE while e: if e & 1: - t_ans = fq12_mul_fq12(P, t_ans, t_a) - t_a = fq12_mul_fq12(P, t_a, t_a) + t_ans = fq12_mul(t_ans, t_a) + t_a = fq12_mul(t_a, t_a) e >>= 1 return t_ans -def fq12_qi_pow(P, t_x, i): +def fq12_qi_pow(t_x, i): '''Calc qi_power on t_x tuple returning tuple''' - global bls12381_q, frob_coeffs - if P != bls12381_q: - raise NotImplementedError + global frob_coeffs i %= 12 if i == 0: return t_x - a, b, c, d, e, f = fq6_qi_pow(P, t_x[:6], i) - g, h, i, j, k, l = fq6_mul_fq6(P, fq6_qi_pow(P, t_x[6:12], i), + a, b, c, d, e, f = fq6_qi_pow(t_x[:6], i) + g, h, i, j, k, l = fq6_mul(fq6_qi_pow(t_x[6:12], i), frob_coeffs[12, i, 1]) return (a, b, c, d, e, f, g, h, i, j, k, l) -def fq12_add_fq(P, t_a, m): +def fq12_add_fq(t_a, m): '''Add tuple t_a and int m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a - return ((a+m) % P, b, c, d, e, f, g, h, i, j, k, l) + return ((a+m) % Q, b, c, d, e, f, g, h, i, j, k, l) -def fq12_add_fq2(P, t_a, t_m): +def fq12_add_fq2(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n = t_m - return ((a+m) % P, (b+n) % P, c, d, e, f, g, h, i, j, k, l) + return ((a+m) % Q, (b+n) % Q, c, d, e, f, g, h, i, j, k, l) -def fq12_add_fq6(P, t_a, t_m): +def fq12_add_fq6(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r = t_m - return ((a+m) % P, (b+n) % P, (c+o) % P, (d+p) % P, (e+q) % P, (f+r) % P, + return ((a+m) % Q, (b+n) % Q, (c+o) % Q, (d+p) % Q, (e+q) % Q, (f+r) % Q, g, h, i, j, k, l) -def fq12_add_fq12(P, t_a, t_m): +def fq12_add(t_a, t_m): '''Add tuple t_a and tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r, s, t, u, v, w, x = t_m - return ((a+m) % P, (b+n) % P, (c+o) % P, (d+p) % P, (e+q) % P, (f+r) % P, - (g+s) % P, (h+t) % P, (i+u) % P, (j+v) % P, (k+w) % P, (l+x) % P) + return ((a+m) % Q, (b+n) % Q, (c+o) % Q, (d+p) % Q, (e+q) % Q, (f+r) % Q, + (g+s) % Q, (h+t) % Q, (i+u) % Q, (j+v) % Q, (k+w) % Q, (l+x) % Q) -def fq12_sub_fq(P, t_a, m): +def fq12_sub_fq(t_a, m): '''Sub int m from tuple t_a returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a - return ((a-m) % P, b, c, d, e, f, g, h, i, j, k, l) + return ((a-m) % Q, b, c, d, e, f, g, h, i, j, k, l) -def fq_sub_fq12(P, a, t_m): +def fq_sub_fq12(a, t_m): '''Sub tuple t_m from int a returning tuple''' m, n, o, p, q, r, s, t, u, v, w, x = t_m - return ((a-m) % P, -n % P, -o % P, -p % P, -q % P, -r % P, - -s % P, -t % P, -u % P, -v % P, -w % P, -x % P) + return ((a-m) % Q, -n % Q, -o % Q, -p % Q, -q % Q, -r % Q, + -s % Q, -t % Q, -u % Q, -v % Q, -w % Q, -x % Q) -def fq12_sub_fq2(P, t_a, t_m): +def fq12_sub_fq2(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n = t_m - return ((a-m) % P, (b-n) % P, c, d, e, f, g, h, i, j, k, l) + return ((a-m) % Q, (b-n) % Q, c, d, e, f, g, h, i, j, k, l) -def fq2_sub_fq12(P, t_a, t_m): +def fq2_sub_fq12(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b = t_a m, n, o, p, q, r, s, t, u, v, w, x = t_m - return ((a-m) % P, (b-n) % P, -o % P, -p % P, -q % P, -r % P, - -s % P, -t % P, -u % P, -v % P, -w % P, -x % P) + return ((a-m) % Q, (b-n) % Q, -o % Q, -p % Q, -q % Q, -r % Q, + -s % Q, -t % Q, -u % Q, -v % Q, -w % Q, -x % Q) -def fq12_sub_fq6(P, t_a, t_m): +def fq12_sub_fq6(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r = t_m - return ((a-m) % P, (b-n) % P, (c-o) % P, (d-p) % P, (e-q) % P, (f-r) % P, + return ((a-m) % Q, (b-n) % Q, (c-o) % Q, (d-p) % Q, (e-q) % Q, (f-r) % Q, g, h, i, j, k, l) -def fq6_sub_fq12(P, t_a, t_m): +def fq6_sub_fq12(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f = t_a m, n, o, p, q, r, s, t, u, v, w, x = t_m - return ((a-m) % P, (b-n) % P, (c-o) % P, (d-p) % P, (e-q) % P, (f-r) % P, - -s % P, -t % P, -u % P, -v % P, -w % P, -x % P) + return ((a-m) % Q, (b-n) % Q, (c-o) % Q, (d-p) % Q, (e-q) % Q, (f-r) % Q, + -s % Q, -t % Q, -u % Q, -v % Q, -w % Q, -x % Q) -def fq12_sub_fq12(P, t_a, t_m): +def fq12_sub(t_a, t_m): '''Sub tuple t_m from tuple t_a returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r, s, t, u, v, w, x = t_m - return ((a-m) % P, (b-n) % P, (c-o) % P, (d-p) % P, (e-q) % P, (f-r) % P, - (g-s) % P, (h-t) % P, (i-u) % P, (j-v) % P, (k-w) % P, (l-x) % P) + return ((a-m) % Q, (b-n) % Q, (c-o) % Q, (d-p) % Q, (e-q) % Q, (f-r) % Q, + (g-s) % Q, (h-t) % Q, (i-u) % Q, (j-v) % Q, (k-w) % Q, (l-x) % Q) -def fq12_mul_fq(P, t_a, m): +def fq12_mul_fq(t_a, m): '''Multiple tuple t_a on int m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a - return (a*m % P, b*m % P, c*m % P, d*m % P, e*m % P, f*m % P, - g*m % P, h*m % P, i*m % P, j*m % P, k*m % P, l*m % P) + return (a*m % Q, b*m % Q, c*m % Q, d*m % Q, e*m % Q, f*m % Q, + g*m % Q, h*m % Q, i*m % Q, j*m % Q, k*m % Q, l*m % Q) -def fq12_mul_fq2(P, t_a, t_m): +def fq12_mul_fq2(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n = t_m - fq2r = FQ2_ROOT - mul_a = a*m + b*n*fq2r; mul_b = a*n + b*m - mul_c = c*m + d*n*fq2r; mul_d = c*n + d*m - mul_e = e*m + f*n*fq2r; mul_f = e*n + f*m - mul_g = g*m + h*n*fq2r; mul_h = g*n + h*m - mul_i = i*m + j*n*fq2r; mul_j = i*n + j*m - mul_k = k*m + l*n*fq2r; mul_l = k*n + l*m - return (mul_a % P, mul_b % P, mul_c % P, mul_d % P, mul_e % P, mul_f % P, - mul_g % P, mul_h % P, mul_i % P, mul_j % P, mul_k % P, mul_l % P) - - -def fq12_mul_fq6(P, t_a, t_m): + mul_a = a*m - b*n; mul_b = a*n + b*m + mul_c = c*m - d*n; mul_d = c*n + d*m + mul_e = e*m - f*n; mul_f = e*n + f*m + mul_g = g*m - h*n; mul_h = g*n + h*m + mul_i = i*m - j*n; mul_j = i*n + j*m + mul_k = k*m - l*n; mul_l = k*n + l*m + return (mul_a % Q, mul_b % Q, mul_c % Q, mul_d % Q, mul_e % Q, mul_f % Q, + mul_g % Q, mul_h % Q, mul_i % Q, mul_j % Q, mul_k % Q, mul_l % Q) + + +def fq12_mul_fq6(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r = t_m - fq2r = FQ2_ROOT - drfq2r = d*r*fq2r; fpfq2r = f*p*fq2r; frfq2r = f*r*fq2r - jrfq2r = j*r*fq2r; lpfq2r = l*p*fq2r; lrfq2r = l*r*fq2r - cq = c*q; cr = c*r; dq = d*q; eo = e*o; ep = e*p - fo = f*o; eq = e*q; er = e*r; fq = f*q - iq = i*q; ir = i*r; jq = j*q; ko = k*o; kp = k*p - lo = l*o; kq = k*q; kr = k*r; lq = l*q - mul_a = (a*m + b*n*fq2r + cq + drfq2r + (cr + dq)*fq2r + eo + - fpfq2r + (ep + fo)*fq2r) - mul_b = a*n + b*m + cq + drfq2r + cr + dq + eo + fpfq2r + ep + fo - mul_c = (a*o + b*p*fq2r + c*m + d*n*fq2r + eq + frfq2r + - (er + fq)*fq2r) - mul_d = a*p + b*o + c*n + d*m + eq + frfq2r + er + fq - mul_e = a*q + b*r*fq2r + c*o + d*p*fq2r + e*m + f*n*fq2r - mul_f = a*r + b*q + c*p + d*o + e*n + f*m - mul_g = (g*m + h*n*fq2r + iq + jrfq2r + (ir + jq)*fq2r + ko + - lpfq2r + (kp + lo)*fq2r) - mul_h = g*n + h*m + iq + jrfq2r + ir + jq + ko + lpfq2r + kp + lo - mul_i = (g*o + h*p*fq2r + i*m + j*n*fq2r + kq + lrfq2r + - (kr + lq)*fq2r) - mul_j = g*p + h*o + i*n + j*m + kq + lrfq2r + kr + lq - mul_k = g*q + h*r*fq2r + i*o + j*p*fq2r + k*m + l*n*fq2r - mul_l = g*r + h*q + i*p + j*o + k*n + l*m - return (mul_a % P, mul_b % P, mul_c % P, mul_d % P, mul_e % P, mul_f % P, - mul_g % P, mul_h % P, mul_i % P, mul_j % P, mul_k % P, mul_l % P) - - -def fq12_mul_fq12(P, t_a, t_m): + + am = a*m; an = a*n; ao = a*o; ap = a*p; aq = a*q; ar = a*r; + bm = b*m; bn = b*n; bo = b*o; bp = b*p; bq = b*q; br = b*r; + cm = c*m; cn = c*n; co = c*o; cp = c*p; cq = c*q; cr = c*r; + dm = d*m; dn = d*n; do = d*o; dp = d*p; dq = d*q; dr = d*r; + em = e*m; en = e*n; eo = e*o; ep = e*p; eq = e*q; er = e*r; + fm = f*m; fn = f*n; fo = f*o; fp = f*p; fq = f*q; fr = f*r; + gm = g*m; gn = g*n; go = g*o; gp = g*p; gq = g*q; gr = g*r; + hm = h*m; hn = h*n; ho = h*o; hp = h*p; hq = h*q; hr = h*r; + im = i*m; in_ = i*n; io = i*o; ip = i*p; iq = i*q; ir = i*r; + jm = j*m; jn = j*n; jo = j*o; jp = j*p; jq = j*q; jr = j*r; + km = k*m; kn = k*n; ko = k*o; kp = k*p; kq = k*q; kr = k*r; + lm = l*m; ln = l*n; lo = l*o; lp = l*p; lq = l*q; lr = l*r; + + r0 = am - bn + cq - cr - dr - dq + eo - ep - fp - fo + r1 = an + bm + cq + cr - dr + dq + eo + ep - fp + fo + r2 = ao - bp + cm - dn + eq - fr - er - fq + r3 = ap + bo + cn + dm + eq - fr + er + fq + r4 = aq - br + co - dp + em - fn + r5 = ar + bq + cp + do + en + fm + r6 = gm - hn + iq - ir - jr - jq + ko - kp - lp - lo + r7 = gn + hm + iq + ir - jr + jq + ko + kp - lp + lo + r8 = go - hp + im - jn + kq - kr - lr - lq + r9 = gp + ho + in_ + jm + kq + kr - lr + lq + r10 = gq - hr + io - jp + km - ln + r11 = gr + hq + ip + jo + kn + lm + return (r0 % Q, r1 % Q, r2 % Q, r3 % Q, r4 % Q, r5 % Q, + r6 % Q, r7 % Q, r8 % Q, r9 % Q, r10 % Q, r11 % Q) + + +def fq12_mul(t_a, t_m): '''Multiple tuple t_a on tuple t_m returning tuple''' a, b, c, d, e, f, g, h, i, j, k, l = t_a m, n, o, p, q, r, s, t, u, v, w, x = t_m - fq2r = FQ2_ROOT - cq = c*q; cr = c*r; dq = d*q; drfq2r = d*r*fq2r - eo = e*o; ep = e*p; eq = e*q; er = e*r; fo = f*o - fpfq2r = f*p*fq2r; fq = f*q; frfq2r = f*r*fq2r - iw = i*w; ix = i*x; jw = j*w; jxfq2r = j*x*fq2r - ku = k*u; kv = k*v; kw = k*w; kx = k*x; lu = l*u - lvfq2r = l*v*fq2r; lw = l*w; lxfq2r = l*x*fq2r - cw = c*w; cx = c*x; dw = d*w; dxfq2r = d*x*fq2r - eu = e*u; ev = e*v; ew = e*w; ex = e*x; fu = f*u - fvfq2r = f*v*fq2r; fw = f*w; fxfq2r = f*x*fq2r - iq = i*q; ir = i*r; jq = j*q; jrfq2r = j*r*fq2r - ko = k*o; kp = k*p; kq = k*q; kr = k*r; lo = l*o - lpfq2r = l*p*fq2r; lq = l*q; lrfq2r = l*r*fq2r - mul_a1 = (a*m + b*n*fq2r + cq + drfq2r + (cr + dq)*fq2r + eo + - fpfq2r + (ep + fo)*fq2r) - mul_a2 = (g*w + h*x*fq2r + i*u + j*v*fq2r + k*s + l*t*fq2r + - (g*x + h*w + i*v + j*u + k*t + l*s)*fq2r) - mul_b1 = a*n + b*m + cq + drfq2r + cr + dq + eo + fpfq2r + ep + fo - mul_b2 = (g*w + h*x*fq2r + i*u + j*v*fq2r + k*s + l*t*fq2r + g*x + - h*w + i*v + j*u + k*t + l*s) - mul_c1 = (a*o + b*p*fq2r + c*m + d*n*fq2r + eq + frfq2r + - (er + fq)*fq2r) - mul_c2 = (g*s + h*t*fq2r + iw + jxfq2r + (ix + jw)*fq2r + ku + - lvfq2r + (kv + lu)*fq2r) - mul_d1 = a*p + b*o + c*n + d*m + eq + frfq2r + er + fq - mul_d2 = g*t + h*s + iw + jxfq2r + ix + jw + ku + lvfq2r + kv + lu - mul_e1 = a*q + b*r*fq2r + c*o + d*p*fq2r + e*m + f*n*fq2r - mul_e2 = (g*u + h*v*fq2r + i*s + j*t*fq2r + kw + lxfq2r + - (kx + lw)*fq2r) - mul_f1 = a*r + b*q + c*p + d*o + e*n + f*m - mul_f2 = g*v + h*u + i*t + j*s + kw + lxfq2r + kx + lw - mul_g1 = (a*s + b*t*fq2r + cw + dxfq2r + (cx + dw)*fq2r + eu + - fvfq2r + (ev + fu)*fq2r) - mul_g2 = (g*m + h*n*fq2r + iq + jrfq2r + (ir + jq)*fq2r + ko + - lpfq2r + (kp + lo)*fq2r) - mul_h1 = a*t + b*s + cw + dxfq2r + cx + dw + eu + fvfq2r + ev + fu - mul_h2 = g*n + h*m + iq + jrfq2r + ir + jq + ko + lpfq2r + kp + lo - mul_i1 = (a*u + b*v*fq2r + c*s + d*t*fq2r + ew + fxfq2r + - (ex + fw)*fq2r) - mul_i2 = (g*o + h*p*fq2r + i*m + j*n*fq2r + kq + lrfq2r + - (kr + lq)*fq2r) - mul_j1 = a*v + b*u + c*t + d*s + ew + fxfq2r + ex + fw - mul_j2 = g*p + h*o + i*n + j*m + kq + lrfq2r + kr + lq - mul_k1 = a*w + b*x*fq2r + c*u + d*v*fq2r + e*s + f*t*fq2r - mul_k2 = g*q + h*r*fq2r + i*o + j*p*fq2r + k*m + l*n*fq2r - mul_l1 = a*x + b*w + c*v + d*u + e*t + f*s - mul_l2 = g*r + h*q + i*p + j*o + k*n + l*m - return ((mul_a1 + mul_a2) % P, (mul_b1 + mul_b2) % P, - (mul_c1 + mul_c2) % P, (mul_d1 + mul_d2) % P, - (mul_e1 + mul_e2) % P, (mul_f1 + mul_f2) % P, - (mul_g1 + mul_g2) % P, (mul_h1 + mul_h2) % P, - (mul_i1 + mul_i2) % P, (mul_j1 + mul_j2) % P, - (mul_k1 + mul_k2) % P, (mul_l1 + mul_l2) % P) + + am = a*m; an = a*n; ao = a*o; ap = a*p; aq = a*q; ar = a*r; + as_ = a*s; at = a*t; au = a*u; av = a*v; aw = a*w; ax = a*x; + bm = b*m; bn = b*n; bo = b*o; bp = b*p; bq = b*q; br = b*r; + bs = b*s; bt = b*t; bu = b*u; bv = b*v; bw = b*w; bx = b*x; + cm = c*m; cn = c*n; co = c*o; cp = c*p; cq = c*q; cr = c*r; + cs = c*s; ct = c*t; cu = c*u; cv = c*v; cw = c*w; cx = c*x; + dm = d*m; dn = d*n; do = d*o; dp = d*p; dq = d*q; dr = d*r; + ds = d*s; dt = d*t; du = d*u; dv = d*v; dw = d*w; dx = d*x; + em = e*m; en = e*n; eo = e*o; ep = e*p; eq = e*q; er = e*r; + es = e*s; et = e*t; eu = e*u; ev = e*v; ew = e*w; ex = e*x; + fm = f*m; fn = f*n; fo = f*o; fp = f*p; fq = f*q; fr = f*r; + fs = f*s; ft = f*t; fu = f*u; fv = f*v; fw = f*w; fx = f*x; + gm = g*m; gn = g*n; go = g*o; gp = g*p; gq = g*q; gr = g*r; + gs = g*s; gt = g*t; gu = g*u; gv = g*v; gw = g*w; gx = g*x; + hm = h*m; hn = h*n; ho = h*o; hp = h*p; hq = h*q; hr = h*r; + hs = h*s; ht = h*t; hu = h*u; hv = h*v; hw = h*w; hx = h*x; + im = i*m; in_ = i*n; io = i*o; ip = i*p; iq = i*q; ir = i*r; + is_ = i*s; it = i*t; iu = i*u; iv = i*v; iw = i*w; ix = i*x; + jm = j*m; jn = j*n; jo = j*o; jp = j*p; jq = j*q; jr = j*r; + js = j*s; jt = j*t; ju = j*u; jv = j*v; jw = j*w; jx = j*x; + km = k*m; kn = k*n; ko = k*o; kp = k*p; kq = k*q; kr = k*r; + ks = k*s; kt = k*t; ku = k*u; kv = k*v; kw = k*w; kx = k*x; + lm = l*m; ln = l*n; lo = l*o; lp = l*p; lq = l*q; lr = l*r; + ls = l*s; lt = l*t; lu = l*u; lv = l*v; lw = l*w; lx = l*x; + + r0 = (am - bn + cq - cr - dr - dq + eo - ep - fp - fo + + gw - gx - hx - hw + iu - iv - jv - ju + ks - kt - lt - ls) + r1 = (an + bm + cq + cr - dr + dq + eo + ep - fp + fo + + gw + gx - hx + hw + iu + iv - jv + ju + ks + kt - lt + ls) + r2 = (ao - bp + cm - dn + eq - er - fr - fq + gs - ht + + iw - ix - jx - jw + ku - kv - lv - lu) + r3 = (ap + bo + cn + dm + eq + er - fr + fq + gt + hs + + iw + ix - jx + jw + ku + kv - lv + lu) + r4 = aq - br + co - dp + em - fn + gu - hv + is_ - jt + kw - kx - lx - lw + r5 = ar + bq + cp + do + en + fm + gv + hu + it + js + kw + kx - lx + lw + r6 = (as_ - bt + cw - cx - dx - dw + eu - ev - fv - fu + + gm - hn + iq - ir - jr - jq + ko - kp - lp - lo) + r7 = (at + bs + cw + cx - dx + dw + eu + ev - fv + fu + + gn + hm + iq + ir - jr + jq + ko + kp - lp + lo) + r8 = (au - bv + cs - dt + ew - ex - fx - fw + go - hp + + im - jn + kq - kr - lr - lq) + r9 = (av + bu + ct + ds + ew + ex - fx + fw + gp + ho + + in_ + jm + kq + kr - lr + lq) + r10 = aw - bx + cu - dv + es - ft + gq - hr + io - jp + km - ln + r11 = ax + bw + cv + du + et + fs + gr + hq + ip + jo + kn + lm + return (r0 % Q, r1 % Q, r2 % Q, r3 % Q, r4 % Q, r5 % Q, + r6 % Q, r7 % Q, r8 % Q, r9 % Q, r10 % Q, r11 % Q) + + +# ec.py methods +def fq_is_on_curve_affine(px, py, pinf): + if pinf: + return True + left = fq_pow(Q, py, 2) + right = (fq_pow(Q, px, 3) + bls12381_b) % Q + return left == right + + +def fq2_is_on_curve_affine(px, py, pinf): + if pinf: + return True + left = fq2_pow(py, 2) + right = fq2_add(fq2_pow(px, 3), (bls12381_b, )*2) + return left == right + + +def fq12_is_on_curve_affine(px, py, pinf): + if pinf: + return True + left = fq12_pow(py, 2) + right = fq12_add(fq12_pow(px, 3), (bls12381_b, )*12) + return left == right + + +def fq_is_on_curve_jacobian(px, py, pz, pinf): + xr, yr, infr = fq_to_affine(px, py, pz, pinf) + return fq_is_on_curve_affine(xr, yr, infr) + + +def fq2_is_on_curve_jacobian(px, py, pz, pinf): + xr, yr, infr = fq2_to_affine(px, py, pz, pinf) + return fq2_is_on_curve_affine(xr, yr, infr) + + +def fq12_is_on_curve_jacobian(px, py, pz, pinf): + xr, yr, infr = fq12_to_affine(px, py, pz, pinf) + return fq12_is_on_curve_affine(xr, yr, infr) + + +def fq_to_jacobian(px, py, pinf): + return px, py, 1, pinf + + +def fq2_to_jacobian(px, py, pinf): + return px, py, FQ2_ONE_TUPLE, pinf + + +def fq12_to_jacobian(px, py, pinf): + return px, py, FQ12_ONE_TUPLE, pinf + + +def fq_to_affine(px, py, pz, pinf): + if pinf: + return 0, 0, pinf + rx = px * fq_invert(Q, fq_pow(Q, pz, 2)) % Q + ry = py * fq_invert(Q, fq_pow(Q, pz, 3)) % Q + return rx, ry, pinf + + +def fq2_to_affine(px, py, pz, pinf): + if pinf: + return FQ2_ZERO_TUPLE, FQ2_ZERO_TUPLE, pinf + rx = fq2_mul(px, fq2_invert(fq2_pow(pz, 2))) + ry = fq2_mul(py, fq2_invert(fq2_pow(pz, 3))) + return rx, ry, pinf + + +def fq12_to_affine(px, py, pz, pinf): + if pinf: + return FQ12_ZERO_TUPLE, FQ12_ZERO_TUPLE, pinf + rx = fq12_mul(px, fq12_invert(fq12_pow(pz, 2))) + ry = fq12_mul(py, fq12_invert(fq12_pow(pz, 3))) + return rx, ry, pinf + + +def fq_double_point(px, py, pinf): + left = 3 * fq_pow(Q, px, 2) + s = left * fq_invert(Q, 2*py) + xr = (fq_pow(Q, s, 2) - 2*px) % Q + yr = (s * (px - xr) - py) % Q + return xr, yr, False + + +def fq2_double_point(px, py, pinf): + left = fq2_mul_fq(fq2_pow(px, 2), 3) + s = fq2_mul(left, fq2_invert(fq2_mul_fq(py, 2))) + xr = fq2_sub(fq2_pow(s, 2), fq2_mul_fq(px, 2)) + yr = fq2_sub(fq2_mul(s, fq2_sub(px, xr)), py) + return xr, yr, False + + +def fq12_double_point(px, py, pinf): + left = fq12_mul_fq(fq12_pow(px, 2), 3) + s = fq12_mul(left, fq12_invert(fq12_mul_fq(py, 2))) + xr = fq12_sub(fq12_pow(s, 2), fq12_mul_fq(px, 2)) + yr = fq12_sub(fq12_mul(s, fq12_sub(px, xr)), py) + return xr, yr, False + + +def fq_add_points(x1, y1, inf1, x2, y2, inf2): + if inf1: + return x2, y2, inf2 + if inf2: + return x1, y1, inf1 + if x1 == x2 and y1 == y2: + return fq_double_point(x1, y1, inf1) + if x1 == x2: + return 0, 0, True + + s = (y2 - y1) * fq_invert(Q, x2 - x1) + xr = (fq_pow(Q, s, 2) - x1 - x2) % Q + yr = (s * (x1 - xr) - y1) % Q + return xr, yr, False + + +def fq2_add_points(x1, y1, inf1, x2, y2, inf2): + if inf1: + return x2, y2, inf2 + if inf2: + return x1, y1, inf1 + if x1 == x2 and y1 == y2: + return fq2_double_point(x1, y1, inf1) + if x1 == x2: + return FQ2_ZERO_TUPLE, FQ2_ZERO_TUPLE, True + + s = fq2_mul(fq2_sub(y2, y1), fq2_invert(fq2_sub(x2, x1))) + xr = fq2_sub(fq2_sub(fq2_pow(s, 2), x1), x2) + yr = fq2_sub(fq2_mul(s, fq2_sub(x1, xr)), y1) + return xr, yr, False + + +def fq12_add_points(x1, y1, inf1, x2, y2, inf2): + if inf1: + return x2, y2, inf2 + if inf2: + return x1, y1, inf1 + if x1 == x2 and y1 == y2: + return fq12_double_point(x1, y1, inf1) + if x1 == x2: + return FQ12_ZERO_TUPLE, FQ12_ZERO_TUPLE, True + + s = fq12_mul(fq12_sub(y2, y1), fq2_invert(fq12_sub(x2, x1))) + xr = fq12_sub(fq12_sub(fq12_pow(s, 2), x1), x2) + yr = fq12_sub(fq12_mul(s, fq12_sub(x1, xr)), y1) + return xr, yr, False + + +def fq_scalar_mult_jacobian(c, x1, y1, z1, inf1): + xr = 1 + yr = 1 + zr = 0 + infr = True + if inf1 or c % Q == 0: + return xr, yr, zr, infr + # addend = p1 + while c > 0: + if c & 1: + # result += addend + xr, yr, zr, infr = fq_add_points_jacobian(xr, yr, zr, infr, + x1, y1, z1, inf1) + # double point + x1, y1, z1 = fq_double_point_jacobian(x1, y1, z1) + c = c >> 1 + return xr, yr, zr, infr + + +def fq2_scalar_mult_jacobian(c, x1, y1, z1, inf1): + xr = FQ2_ONE_TUPLE + yr = FQ2_ONE_TUPLE + zr = FQ2_ZERO_TUPLE + infr = True + if inf1 or c % Q == 0: + return xr, yr, zr, infr + # addend = p1 + while c > 0: + if c & 1: + # result += addend + xr, yr, zr, infr = fq2_add_points_jacobian(xr, yr, zr, infr, + x1, y1, z1, inf1) + # double point + x1, y1, z1 = fq2_double_point_jacobian(x1, y1, z1) + c = c >> 1 + return xr, yr, zr, infr + + +def fq12_scalar_mult_jacobian(c, x1, y1, z1, inf1): + xr = FQ12_ONE_TUPLE + yr = FQ12_ONE_TUPLE + zr = FQ12_ZERO_TUPLE + infr = True + if inf1 or c % Q == 0: + return xr, yr, zr, infr + # addend = p1 + while c > 0: + if c & 1: + # result += addend + xr, yr, zr, infr = fq12_add_points_jacobian(xr, yr, zr, infr, + x1, y1, z1, inf1) + # double point + x1, y1, z1 = fq12_double_point_jacobian(x1, y1, z1) + c = c >> 1 + return xr, yr, zr, infr + + +def fq_add_points_jacobian(x1, y1, z1, inf1, x2, y2, z2, inf2): + if inf1: + return x2, y2, z2, inf2 + if inf2: + return x1, y1, z1, inf1 + # u1 = x1*z2^2 + u1 = x1*z2*z2 % Q + # u2 = x2*z1^2 + u2 = x2*z1*z1 % Q + # s1 = y1*z2^3 + s1 = y1*z2*z2*z2 % Q + # s2 = y2*z1^3 + s2 = y2*z1*z1*z1 % Q + if u1 == u2: + if s1 != s2: + xr = yr = 1 + zr = 0 + infr = True + else: + xr, yr, zr = fq_double_point_jacobian(x1, y1, z1, Q) + infr = False + else: + # h = u2 - u1 + h = (u2-u1) % Q + # r = s2 - s1 + r = (s2-s1) % Q + h_sq = h*h % Q + h_cu = h*h_sq % Q + # xr = r^2 - h^3 - 2*u1*h^2 + xr = (r*r % Q - h_cu - 2*u1*h_sq % Q) % Q + # yr = r*(u1*h^2 - xr) - s1*h^3 + yr = (r*(u1*h_sq % Q - xr) % Q - s1*h_cu % Q) % Q + # zr = h*z1*z2 + zr = h*z1*z2 % Q + infr = False + return xr, yr, zr, infr + + +def fq2_add_points_jacobian(x1, y1, z1, inf1, x2, y2, z2, inf2): + if inf1: + return x2, y2, z2, inf2 + if inf2: + return x1, y1, z1, inf1 + u1, u2, s1, s2 = fqx_calc_u1_u2_s1_s2(fq2_mul, x1, y1, z1, + x2, y2, z2) + if u1 == u2: + if s1 != s2: + xr = yr = FQ2_ONE_TUPLE + zr = FQ2_ZERO_TUPLE + infr = True + else: + xr, yr, zr = fq2_double_point_jacobian(x1, y1, z1) + infr = False + else: + func_t = (fq2_mul, fq2_sub, fq2_mul_fq) + xr, yr, zr = fqx_calc_jp_on_us(func_t, u1, u2, s1, s2, z1, z2) + infr = False + return xr, yr, zr, infr + + +def fq12_add_points_jacobian(x1, y1, z1, inf1, x2, y2, z2, inf2): + if inf1: + return x2, y2, z2, inf2 + if inf2: + return x1, y1, z1, inf1 + u1, u2, s1, s2 = fqx_calc_u1_u2_s1_s2(fq12_mul, x1, y1, z1, + x2, y2, z2) + if u1 == u2: + if s1 != s2: + xr = yr = FQ12_ONE_TUPLE + zr = FQ12_ZERO_TUPLE + infr = True + else: + xr, yr, zr = fq12_double_point_jacobian(x1, y1, z1) + infr = False + else: + func_t = (fq12_mul, fq12_sub, fq12_mul_fq) + xr, yr, zr = fqx_calc_jp_on_us(func_t, u1, u2, s1, s2, z1, z2) + infr = False + return xr, yr, zr, infr + + +def fqx_calc_u1_u2_s1_s2(mul_f, x1_t, y1_t, z1_t, x2_t, y2_t, z2_t): + '''x, y, z inputs of type fq2, returning tuple of fq2 tuples''' + # u1 = x1*z2^2 + u1 = mul_f(mul_f(x1_t, z2_t), z2_t) + # u2 = x2*z1^2 + u2 = mul_f(mul_f(x2_t, z1_t), z1_t) + # s1 = y1*z2^3 + s1 = mul_f(mul_f(mul_f(y1_t, z2_t), z2_t), z2_t) + # s2 = y2*z1^3 + s2 = mul_f(mul_f(mul_f(y2_t, z1_t), z1_t), z1_t) + return u1, u2, s1, s2 + + +def fqx_calc_jp_on_us(func_t, u1, u2, s1, s2, z1, z2): + '''calc jacobian point with tuples u1, u2, s1, s2, z1, z2, + using func_t functions tuple for operations''' + mul_f, sub_f, muli_f = func_t + # h = u2 - u1 + h = sub_f(u2, u1) + # r = s2 - s1 + r = sub_f(s2, s1) + h_sq = mul_f(h, h) + h_cu = mul_f(h, h_sq) + # x3 = r^2 - h^3 - 2*u1*h^2 + x3 = sub_f(sub_f(mul_f(r, r), h_cu), + mul_f(h_sq, muli_f(u1, 2))) + # y3 = r*(u1*h^2 - x3) - s1*h^3 + y3 = sub_f(mul_f(r, sub_f(mul_f(u1, h_sq), x3)), + mul_f(s1, h_cu)) + # z3 = h*z1*z2 + z3 = mul_f(mul_f(z1, z2), h) + return x3, y3, z3 + + +def fq_double_point_jacobian(X, Y, Z): + '''dobule point with fq int X, Y, Z, returning tuple''' + # S = 4*X*Y^2 + S = 4*X*Y*Y % Q + + Z_sq = Z*Z % Q + Y_sq = Y*Y % Q + Y_4th = Y_sq*Y_sq % Q + + # M = 3*X^2 + a*Z^4 + # A is 0 for bls12-381 + M = 3*X*X % Q + + # X' = M^2 - 2*S + X_p = (M*M % Q - 2*S % Q) % Q + # Y' = M*(S - X') - 8*Y^4 + Y_p = (M*((S - X_p) % Q) % Q - 8*Y_4th % Q) % Q + # Z' = 2*Y*Z + Z_p = 2*Y*Z % Q + return X_p, Y_p, Z_p + + +def fq2_double_point_jacobian(X, Y, Z): + '''dobule point with fq2 tuples X, Y, Z, returning tuple of tuples''' + func_t = (fq2_mul, fq2_mul_fq, fq2_add, fq2_sub) + return fqx_double_point_jacobian(func_t, X, Y, Z) + + +def fq12_double_point_jacobian(X, Y, Z): + '''dobule point with fq12 tuples X, Y, Z, returning tuple of tuples''' + func_t = (fq12_mul, fq12_mul_fq, fq12_add, fq12_sub) + return fqx_double_point_jacobian(func_t, X, Y, Z) + + +def fqx_double_point_jacobian(func_t, X, Y, Z): + '''dobule point with tuples X, Y, Z, returning tuple of tuples, + using func_t functions tuple for operations''' + mul_f, mul_i_f, add_f, sub_f = func_t + # S = 4*X*Y^2 + S = mul_f(mul_f(mul_i_f(X, 4), Y), Y) + + Z_sq = mul_f(Z, Z) + Y_sq = mul_f(Y, Y) + Y_4th = mul_f(Y_sq, Y_sq) + + # M = 3*X^2 + a*Z^4 + # A is 0 for bls12-381 + M = mul_f(mul_i_f(X, 3), X) + + # X' = M^2 - 2*S + X_p = sub_f(mul_f(M, M), mul_i_f(S, 2)) + # Y' = M*(S - X') - 8*Y^4 + Y_p = sub_f(mul_f(M, sub_f(S, X_p)), mul_i_f(Y_4th, 8)) + # Z' = 2*Y*Z + Z_p = mul_f(mul_i_f(Y, 2), Z) + return X_p, Y_p, Z_p + + +def fq2_untwist(x_t, y_t): + m, n = x_t + new_x = (0, 0, 0, 0, (tw1*m - tw2*n) % Q, (tw1*n + tw2*m) % Q, + 0, 0, 0, 0, 0, 0) + m, n = y_t + new_y = (0, 0, 0, 0, 0, 0, + 0, 0, (tw1*m - tw2*n) % Q, (tw1*n + tw2*m) % Q, 0, 0) + return new_x, new_y + + +def fq12_untwist(x_t, y_t): + m, n, o, p, q, r, s, t, u, v, w, x = x_t + e = tw1 + f = tw2 + eo = e*o; ep = e*p; fp = f*p; fo = f*o; + eq = e*q; er = e*r; fr = f*r; fq = f*q; + em = e*m; fn = f*n; en = e*n; fm = f*m; + eu = e*u; ev = e*v; fv = f*v; fu = f*u; + ew = e*w; ex = e*x; fx = f*x; fw = f*w; + es = e*s; ft = f*t; et = e*t; fs = f*s; + #0 eo - ep - fp - fo + #1 eo + ep - fp + fo + #2 eq - er - fr - fq + #3 eq + er - fr + fq + #4 em - fn + #5 en + fm + #6 eu - ev - fv - fu + #7 eu + ev - fv + fu + #8 ew - ex - fx - fw + #9 ew + ex - fx + fw + #10 es - ft + #11 et + fs + new_x = ((eo - ep - fp - fo) % Q, + (eo + ep - fp + fo) % Q, + (eq - er - fr - fq) % Q, + (eq + er - fr + fq) % Q, + (em - fn) % Q, + (en + fm) % Q, + (eu - ev - fv - fu) % Q, + (eu + ev - fv + fu) % Q, + (ew - ex - fx - fw) % Q, + (ew + ex - fx + fw) % Q, + (es - ft) % Q, + (et + fs) % Q) + m, n, o, p, q, r, s, t, u, v, w, x = y_t + i = tw1 + j = tw2 + iu = i*u; iv = i*v; jv = j*v; ju = j*u; + iw = i*w; ix = i*x; jx = j*x; jw = j*w; + is_ = i*s; jt = j*t; it = i*t; js = j*s; + iq = i*q; ir = i*r; jr = j*r; jq = j*q; + im = i*m; jn = j*n; in_ = i*n; jm = j*m; + io = i*o; jp = j*p; ip = i*p; jo = j*o; + #0 iu - iv - jv - ju + #1 iu + iv - jv + ju + #2 iw - ix - jx - jw + #3 iw + ix - jx + jw + #4 is - jt + #5 it + js + #6 iq - ir - jr - jq + #7 iq + ir - jr + jq + #8 im - jn + #9 in + jm + #10 io - jp + #11 ip + jo + new_y = ((iu - iv - jv - ju) % Q, + (iu + iv - jv + ju) % Q, + (iw - ix - jx - jw) % Q, + (iw + ix - jx + jw) % Q, + (is_ - jt) % Q, + (it + js) % Q, + (iq - ir - jr - jq) % Q, + (iq + ir - jr + jq) % Q, + (im - jn) % Q, + (in_ + jm) % Q, + (io - jp) % Q, + (ip + jo) % Q) + return new_x, new_y + + +def fq2_twist(x_t, y_t): + m, n = x_t + new_x = (0, 0, m, n, 0, 0, 0, 0, 0, 0, 0, 0) + m, n = y_t + new_y = (0, 0, 0, 0, 0, 0, 0, 0, m, n, 0, 0) + return new_x, new_y + + +def fq12_twist(x_t, y_t): + m, n, o, p, q, r, s, t, u, v, w, x = x_t + new_x = ((q - r) % Q, (q + r) % Q, m, n, o, p, + (w - x) % Q, (w + x) % Q, s, t, u, v) + m, n, o, p, q, r, s, t, u, v, w, x = y_t + new_y = ((u - v) % Q, (u + v) % Q, (w - x) % Q, (w + x) % Q, s, t, + (q - r) % Q, (q + r) % Q, m, n, o, p) + return new_x, new_y + + +# pairing.py methods +def fq2_double_line_eval(rx_t, ry_t, px, py): + #R12 = untwist(R) + r12_x, r12_y = fq2_untwist(rx_t, ry_t) + + #slope = (3 * pow(R12.x, 2)) / (2 * R12.y) + slope = fq12_mul_fq(fq12_mul(r12_x, r12_x), 3) + slope = fq12_mul(slope, fq12_invert(fq12_mul_fq(r12_y, 2))) + + #v = R12.y - slope * R12.x + v_t = fq12_sub(r12_y, fq12_mul(slope, r12_x)) + + #res = P.y - P.x * slope - v + res_t = fq_sub_fq12(py, fq12_mul_fq(slope, px)) + res_t = fq12_sub(res_t, v_t) + return res_t + + +def fq2_add_line_eval(rx_t, ry_t, qx_t, qy_t, px, py): + #R12 = untwist(R) + #Q12 = untwist(Q) + r12x_t, r12y_t = fq2_untwist(rx_t, ry_t) + q12x_t, q12y_t = fq2_untwist(qx_t, qy_t) + + # This is the case of a vertical line, where the denominator + # will be 0. + #if R12 == Q12.negate(): + # return P.x - R12.x + nq12x_t = fq12_neg(q12x_t) + nq12y_t = fq12_neg(q12y_t) + if r12x_t == nq12x_t and r12y_t == nq12y_t: + return fq_sub_fq12(px, r12x_t) + + #slope = (Q12.y - R12.y) / (Q12.x - R12.x) + slope = fq12_mul(fq12_sub(q12y_t, r12y_t), + fq12_invert(fq12_sub(q12x_t, r12x_t))) + #v = (Q12.y * R12.x - R12.y * Q12.x) / (R12.x - Q12.x) + v_t = fq12_mul(fq12_sub(fq12_mul(q12y_t, r12x_t), + fq12_mul(r12y_t, q12x_t)), + fq12_invert(fq12_sub(r12x_t, q12x_t))) + + #res = P.y - P.x * slope - v + res_t = fq_sub_fq12(py, fq12_mul_fq(slope, px)) + res_t = fq12_sub(res_t, v_t) + return res_t + + +def int_to_bits(i): + if i < 1: + return [0] + bits = [] + while i != 0: + bits.append(i % 2) + i = i // 2 + return list(reversed(bits)) + + +def fq_miller_loop(px, py, pinf, qx_t, qy_t, qinf): + T = bls12381_nx + T_bits = int_to_bits(T) + rx_t = qx_t + ry_t = qy_t + rinf = qinf + f = FQ12_ONE_TUPLE + for i in range(1, len(T_bits)): + # Compute sloped line lrr + llr = fq2_double_line_eval(rx_t, ry_t, px, py) + f = fq12_mul(fq12_pow(f, 2), llr) + # R = 2 * R + rx_t, ry_t, rinf = fq2_double_point(rx_t, ry_t, rinf) + if T_bits[i] == 1: + # Compute sloped line lrq + lrq = fq2_add_line_eval(rx_t, ry_t, qx_t, qy_t, px, py) + f = fq12_mul(f, lrq) + # R = R + Q + rx_t, ry_t, rinf = fq2_add_points(rx_t, ry_t, rinf, + qx_t, qy_t, qinf) + return f + + +def fq_ate_pairing_multi(Ps, Qs): + prod = FQ12_ONE_TUPLE + for i in range(len(Qs)): + px, py, pinf = Ps[i] + qx, qy, qinf = Qs[i] + ml_res = fq_miller_loop(px, py, pinf, qx, qy, qinf) + prod = fq12_mul(prod, ml_res) + return fq12_final_exp(prod) + + +def fq12_final_exp(t_x): + ans = fq12_pow(t_x, FINAL_EXP_E) + ans = fq12_mul(fq12_qi_pow(ans, 2), ans) + ans = fq12_floordiv(fq12_qi_pow(ans, 6), ans) + return ans # Frobenius coefficients for raising elements to q**i -th powers @@ -616,3 +1214,52 @@ def fq12_mul_fq12(P, t_a, t_m): '60e77982d0db45f3536814f0bd5871c1908bd478' 'cd1ee605167ff82995', 16), 0, 0, 0, 0), } + +try: + from .fields_t_c import ( + fq_invert, + fq_floordiv, + fq_pow, + ) + from .fields_t_c import ( + fq2_invert, + fq2_floordiv, + fq2_qi_pow, + fq2_pow, + ) + from .fields_t_c import ( + fq6_invert, + fq6_floordiv, + fq6_qi_pow, + fq6_add, + fq6_mul, + ) + from .fields_t_c import ( + fq12_invert, + fq12_floordiv, + fq12_qi_pow, + fq12_pow, + fq12_mul_fq, + fq12_add, + fq12_mul, + ) + from .fields_t_c import ( + fq2_to_affine, + fq2_double_point, + fq2_add_points, + fq_double_point_jacobian, + fq2_double_point_jacobian, + fq12_double_point_jacobian, + fq_add_points_jacobian, + fq2_add_points_jacobian, + fq12_add_points_jacobian, + fq2_scalar_mult_jacobian, + fq2_double_line_eval, + fq2_add_line_eval, + fq2_untwist, + fq_miller_loop, + fq12_final_exp, + fq_ate_pairing_multi, + ) +except ImportError as e: + logging.error(f'Can not import from fields_t_c: {e}') diff --git a/bls_py/keys.py b/bls_py/keys.py index f652da6..f70a18b 100644 --- a/bls_py/keys.py +++ b/bls_py/keys.py @@ -41,7 +41,7 @@ def from_bytes(buffer): @staticmethod def from_g1(g1_el): - assert isinstance(g1_el, JacobianPoint) + assert type(g1_el) == JacobianPoint return PublicKey(g1_el) def get_fingerprint(self): diff --git a/bls_py/pairing.py b/bls_py/pairing.py index ac5519d..9181800 100644 --- a/bls_py/pairing.py +++ b/bls_py/pairing.py @@ -1,8 +1,8 @@ +import logging from collections import namedtuple from . import bls12381 -from .ec import untwist -from .fields import Fq12, FQ12_ONE_TUPLE, fq12_mul_fq12 +from .fields import Fq, Fq2, Fq12 # Struct for elliptic curve parameters @@ -13,28 +13,20 @@ default_ec_twist = EC(*bls12381.parameters()) -def int_to_bits(i): - if i < 1: - return [0] - bits = [] - while i != 0: - bits.append(i % 2) - i = i // 2 - return list(reversed(bits)) - - def double_line_eval(R, P, ec=default_ec): """ Creates an equation for a line tangent to R, and evaluates this at the point P. f(x) = y - sv - v. f(P). """ - R12 = untwist(R) - - slope = (3 * pow(R12.x, 2) + ec.a) / (2 * R12.y) - v = R12.y - slope * R12.x - - return P.y - P.x * slope - v + Q = ec.q + rx = R.x + ry = R.y + px = P.x + py = P.y + if type(rx) != Fq2 or type(px) != Fq: + raise Exception("invalid elements") + return Fq12(Q, fq2_double_line_eval(rx.ZT, ry.ZT, px.Z, py.Z)) def add_line_eval(R, Q, P, ec=default_ec): @@ -43,64 +35,49 @@ def add_line_eval(R, Q, P, ec=default_ec): and evaluates this at the point P. f(x) = y - sv - v. f(P). """ - R12 = untwist(R) - Q12 = untwist(Q) - - # This is the case of a vertical line, where the denominator - # will be 0. - if R12 == Q12.negate(): - return P.x - R12.x - - slope = (Q12.y - R12.y) / (Q12.x - R12.x) - v = (Q12.y * R12.x - R12.y * Q12.x) / (R12.x - Q12.x) - - return P.y - P.x * slope - v - - -def miller_loop(T, P, Q, ec=default_ec): + rx = R.x + ry = R.y + qx = Q.x + qy = Q.y + px = P.x + py = P.y + if type(rx) != Fq2 or type(qx) != Fq2 or type(px) != Fq: + raise Exception("invalid elements") + Q = ec.q + return Fq12(Q, fq2_add_line_eval(rx.ZT, ry.ZT, qx.ZT, qy.ZT, + px.Z, py.Z)) + + +def miller_loop(P, Q, ec=default_ec): """ Performs a double and add algorithm for the ate pairing. This algorithm is taken from Craig Costello's "Pairing for Beginners". """ - T_bits = int_to_bits(T) - R = Q - f = FQ12_ONE_TUPLE - for i in range(1, len(T_bits)): - # Compute sloped line lrr - lrr = double_line_eval(R, P, ec) - f = fq12_mul_fq12(ec.q, f, f) - f = fq12_mul_fq12(ec.q, f, lrr.ZT) - - R = 2 * R - if T_bits[i] == 1: - # Compute sloped line lrq - lrq = add_line_eval(R, Q, P, ec) - f = fq12_mul_fq12(ec.q, f, lrq.ZT) - R = R + Q - return Fq12(ec.q, f) - - -def final_exponentiation(element, ec=default_ec): + px = P.x + py = P.y + pinf = P.infinity + qx = Q.x + qy = Q.y + qinf = Q.infinity + if type(px) != Fq or type(qx) != Fq2: + raise Exception("invalid elements") + Q = ec.q + return Fq12(Q, fq_miller_loop(px.Z, py.Z, pinf, qx.ZT, qy.ZT, qinf)) + + +def final_exponentiation(element, ec): """ - Performs a final exponentiation to map the result of the miller - loop to a unique element of Fq12. + Performs a final exponentiation on bls12-381 curve to map + the result of the miller loop to a unique element of Fq12. """ - if ec.k == 12: - ans = pow(element, (pow(ec.q, 4) - pow(ec.q, 2) + 1) // ec.n) - ans = ans.qi_power(2) * ans - ans = ans.qi_power(6) / ans - return ans - else: - return pow(element, (pow(ec.q, ec.k) - 1) // ec.n) + return Fq12(ec.q, fq12_final_exp(element.ZT)) def ate_pairing(P, Q, ec=default_ec): """ Performs one ate pairing. """ - t = default_ec.x + 1 - T = abs(t - 1) - element = miller_loop(T, P, Q, ec) + element = miller_loop(P, Q, ec) return final_exponentiation(element, ec) @@ -110,13 +87,17 @@ def ate_pairing_multi(Ps, Qs, ec=default_ec): since we can multiply all the results of the miller loops, and perform just one final exponentiation. """ - t = default_ec.x + 1 - T = abs(t - 1) - prod = FQ12_ONE_TUPLE - for i in range(len(Qs)): - ml_res = miller_loop(T, Ps[i], Qs[i], ec) - prod = fq12_mul_fq12(ec.q, prod, ml_res.ZT) - return final_exponentiation(Fq12(ec.q, prod), ec) + Ps = tuple((ps.x.Z, ps.y.Z, ps.infinity) for ps in Ps) + Qs = tuple((qs.x.ZT, qs.y.ZT, qs.infinity) for qs in Qs) + return Fq12(ec.q, fq_ate_pairing_multi(Ps, Qs)) + + +try: + from .fields_t import (fq12_final_exp, fq2_double_line_eval, + fq2_add_line_eval, fq_miller_loop, + fq_ate_pairing_multi) +except ImportError as e: + logging.error(f'Can not import from fields_t_c: {e}') """ diff --git a/contrib/build_wheels_linux.sh b/contrib/build_wheels_linux.sh new file mode 100755 index 0000000..a258051 --- /dev/null +++ b/contrib/build_wheels_linux.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -ev + +cd /io/gmp-6.1.2 +./configure +make +make check +make install + +cd /io/ +mkdir tests +cp bls_py/tests.py tests/ + +for PYV in cp36-cp36m cp37-cp37m +do + cd /io + /opt/python/$PYV/bin/pip install Cython==0.29.13 + /opt/python/$PYV/bin/pip wheel . -w dist/ + auditwheel repair dist/python_bls-$PKG_VERSION-$PYV-linux*.whl --plat $PLAT -w dist/ + rm dist/python_bls-$PKG_VERSION-$PYV-linux*.whl + + # Tests + /opt/python/$PYV/bin/pip install pytest + /opt/python/$PYV/bin/pip install dist/python_bls-$PKG_VERSION-$PYV-$PLAT.whl + cd tests + /opt/python/$PYV/bin/pytest -vvv tests.py +done + +if [[ $PLAT == manylinux2010_x86_64 ]]; then + cd /io + /opt/python/cp36-cp36m/bin/python setup.py sdist +fi diff --git a/contrib/install_linux.sh b/contrib/install_linux.sh new file mode 100755 index 0000000..9b7660d --- /dev/null +++ b/contrib/install_linux.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -ev + +docker pull quay.io/pypa/$PLAT + +wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.lz +wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.lz.sig +gpg --recv-keys 28C67298 +gpg --verify gmp-6.1.2.tar.lz.sig +tar --lzip -xf gmp-6.1.2.tar.lz diff --git a/contrib/install_osx.sh b/contrib/install_osx.sh new file mode 100755 index 0000000..8ff723b --- /dev/null +++ b/contrib/install_osx.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -ev + + +PYPKG_NAME=python-$PYTHON_VERSION-macosx10.6.pkg +case $PYTHON_VERSION in + 3.6.8) + PY_SHA256=3c5fd87a231eca3ee138b0cdc2be6517a7ca428304d41901a86b51c6a22b910c + ;; + 3.7.4) + PY_SHA256=061c4006efd6374720613a7af1f4b66352900aedb7a374c63d300714ce1835ee + ;; +esac +echo "$PY_SHA256 $PYPKG_NAME" > $PYPKG_NAME.sha256 + +PYFTP=https://www.python.org/ftp/python/$PYTHON_VERSION +curl -O $PYFTP/$PYPKG_NAME +shasum -a256 -s -c $PYPKG_NAME.sha256 +sudo installer -pkg $PYPKG_NAME -target / +rm $PYPKG_NAME $PYPKG_NAME.sha256 + +mkdir gmp +cp /usr/local/Cellar/gmp/*/lib/libgmp.a gmp/ +cp /usr/local/Cellar/gmp/*/include/gmp.h gmp/ diff --git a/contrib/install_win.sh b/contrib/install_win.sh new file mode 100755 index 0000000..4ad25bc --- /dev/null +++ b/contrib/install_win.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -ev + +wget http://www.tortall.net/projects/yasm/releases/vsyasm-1.3.0-win64.zip +mkdir "/c/Program Files/yasm" +unzip -d "/c/Program Files/yasm" vsyasm-1.3.0-win64.zip +rm vsyasm-1.3.0-win64.zip +choco install -y vcredist2010 +export PATH="/c/Program Files/yasm:$PATH" + +choco install -y vcbuildtools +choco install -y python3 --version 3.6.8 + +export PATH="/c/Python36:/c/Python36/Scripts:$PATH" + +git clone https://github.com/BrianGladman/mpir/ +cd mpir +echo "1" | python ./msvc/mpir_config.py 15 +cd ./msvc/vs15 +./msbuild.bat gc lib x64 Release +./msbuild.bat gc lib Win32 Release diff --git a/contrib/script_linux.sh b/contrib/script_linux.sh new file mode 100755 index 0000000..1268694 --- /dev/null +++ b/contrib/script_linux.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ev + +docker run --rm -e PLAT=$PLAT -e PKG_VERSION=$PKG_VERSION \ + -v `pwd`:/io quay.io/pypa/$PLAT \ + $PRE_CMD /io/contrib/build_wheels_linux.sh diff --git a/contrib/script_osx.sh b/contrib/script_osx.sh new file mode 100755 index 0000000..be6cb93 --- /dev/null +++ b/contrib/script_osx.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -ev + +sudo pip3 install --upgrade pip wheel cython==0.29.13 +python3 setup.py build_ext +python3 setup.py bdist_wheel + +# Tests +sudo pip3 install pytest +case $PYTHON_VERSION in + 3.6.8) + sudo pip3 install dist/python_bls-$PKG_VERSION-cp36-cp36m-macosx_10_6_intel.whl + ;; + 3.7.4) + sudo pip3 install dist/python_bls-$PKG_VERSION-cp37-cp37m-macosx_10_6_intel.whl + ;; +esac +mkdir tests +cp bls_py/tests.py tests/ +cd tests +python3 -m pytest -vvv tests.py diff --git a/contrib/script_win.sh b/contrib/script_win.sh new file mode 100755 index 0000000..cb77b4f --- /dev/null +++ b/contrib/script_win.sh @@ -0,0 +1,85 @@ +#!/bin/bash +set -ev + +PATH_BACKUP=$PATH + +mkdir tests +cp bls_py/tests.py tests/ + +# build x64 wheels +export MPIR_DIR=mpir/lib/x64/Release + +# build python3.6 x64 wheel +export PATH="/c/Python36:/c/Python36/Scripts:$PATH_BACKUP" +python -m pip install --upgrade pip wheel cython==0.29.13 + +rm -rf build +python setup.py build_ext -I $MPIR_DIR -L $MPIR_DIR +python setup.py bdist_wheel + +# Tests +cd tests +python -m pip install pytest +python -m pip install ../dist/python_bls-$PKG_VERSION-cp36-cp36m-win_amd64.whl +pytest -vvv tests.py +cd .. + +# build python3.7 x64 wheel +choco uninstall -y python3 --version 3.6.8 +rm -rf /c/Python36/ +choco install -y python3 --version 3.7.4 + +export PATH="/c/Python37:/c/Python37/Scripts:$PATH_BACKUP" +python -m pip install --upgrade pip wheel cython==0.29.13 + +rm -rf build +python setup.py build_ext -I $MPIR_DIR -L $MPIR_DIR +python setup.py bdist_wheel + +# Tests +cd tests +python -m pip install pytest +python -m pip install ../dist/python_bls-$PKG_VERSION-cp37-cp37m-win_amd64.whl +pytest -vvv tests.py +cd .. + +# build win32 wheels +export MPIR_DIR=mpir/lib/win32/Release + +# build python3.6 x64 wheel +choco uninstall -y python3 --version 3.7.4 +rm -rf /c/Python37/ +choco install -y python3 --version 3.6.8 --x86 + +export PATH="/c/Python36:/c/Python36/Scripts:$PATH_BACKUP" +python -m pip install --upgrade pip wheel cython==0.29.13 + +rm -rf build +python setup.py build_ext -I $MPIR_DIR -L $MPIR_DIR +python setup.py bdist_wheel + +# Tests +cd tests +python -m pip install pytest +python -m pip install ../dist/python_bls-$PKG_VERSION-cp36-cp36m-win32.whl +pytest -vvv tests.py +cd .. + +# build python3.7 x64 wheel +choco uninstall -y python3 --version 3.6.8 +rm -rf /c/Python36/ +choco install -y python3 --version 3.7.4 --x86 + +export PATH="/c/Python37:/c/Python37/Scripts:$PATH_BACKUP" +python -m pip install --upgrade pip wheel cython==0.29.13 + +rm -rf build +python setup.py build_ext -I $MPIR_DIR -L $MPIR_DIR +python setup.py bdist_wheel + +# Tests +cd tests +python -m pip install pytest +python -m pip install ../dist/python_bls-$PKG_VERSION-cp37-cp37m-win32.whl +pytest -vvv tests.py +cd .. diff --git a/contrib/version_env.sh b/contrib/version_env.sh new file mode 100755 index 0000000..e40401a --- /dev/null +++ b/contrib/version_env.sh @@ -0,0 +1,9 @@ +#!/bin/bash + + +VERSION_LINE=(`grep 'version=' setup.py`) +if [[ $VERSION_LINE =~ version=\'([^\']+)\' ]] +then + export PKG_VERSION=${BASH_REMATCH[1]}; + echo set PKG_VERSION to $PKG_VERSION +fi diff --git a/extmod/bls_py/__init__.py b/extmod/bls_py/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extmod/bls_py/fields_t_c.pxd b/extmod/bls_py/fields_t_c.pxd new file mode 100644 index 0000000..544c9e0 --- /dev/null +++ b/extmod/bls_py/fields_t_c.pxd @@ -0,0 +1,53 @@ +# cython: language_level=3 +# -*- coding: utf-8 -*- + +from .types cimport * + + +cdef mp_bitcnt_t INIT_BITS = 320 + + +ctypedef mpz_t fq_t +ctypedef __mpz_struct fq2_t[2] +ctypedef __mpz_struct fq6_t[6] +ctypedef __mpz_struct fq12_t[12] + + +# fq queues +cdef mpz_ptr fq_t_get(int *pi) +cdef void fq_t_release(int x) +cdef void fq_t_alloc() + +cdef mpz_ptr fq2_t_get(int *pi) +cdef void fq2_t_release(int x) +cdef void fq2_t_alloc() + +cdef mpz_ptr fq6_t_get(int *pi) +cdef void fq6_t_release(int x) +cdef void fq6_t_alloc() + +cdef mpz_ptr fq12_t_get(int *pi) +cdef void fq12_t_release(int x) +cdef void fq12_t_alloc() + + +# curve q, n, and other constants +cdef mpz_t Q, B, N, NX, tw1, tw2 +cdef mpz_t mpz_final_exp_e +cdef fq_t fq_t_zero, fq_t_one, fq2_t_root +cdef fq2_t fq2_t_zero, fq2_t_one, fq6_t_root +cdef fq6_t fq6_t_zero, fq6_t_one, fq12_t_root +cdef fq12_t fq12_t_zero, fq12_t_one + +# mpz_t 2, 3, 4, 8 +cdef mpz_t mpz_n0, mpz_n2, mpz_n3, mpz_n4, mpz_n8 + +# frob coeffs +cdef fq2_t fc_6[5][2] +cdef fq6_t fc_12[11] + + +cdef str fq_t_get_pystr(fq_t x, base) +cdef str fq2_t_get_pystr(fq2_t x, base) +cdef str fq6_t_get_pystr(fq6_t x, base) +cdef str fq12_t_get_pystr(fq12_t x, base) diff --git a/extmod/bls_py/fields_t_c.pyx b/extmod/bls_py/fields_t_c.pyx new file mode 100644 index 0000000..17c64d8 --- /dev/null +++ b/extmod/bls_py/fields_t_c.pyx @@ -0,0 +1,2699 @@ +# cython: language_level=3 +# cython: profile=False +# -*- coding: utf-8 -*- + +import atexit +from queue import Queue + +from cpython.object cimport Py_SIZE +from cpython.long cimport PyLong_FromLong +from cpython.longintrepr cimport _PyLong_New, py_long, digit, PyLong_SHIFT +from libc.stdlib cimport malloc, free + +from .mpz cimport * +from .types cimport * + + +# Various functions to deal with conversion mpz <-> Python int/long +# AUTHORS: +# - Gonzalo Tornaria (2006): initial version +# - David Harvey (2007-08-18): added ``mpz_get_pyintlong`` function +# - Jeroen Demeyer (2015-02-24): moved from c_lib, rewritten using +# ``mpz_export`` and ``mpz_import`` +cdef extern from *: + Py_ssize_t* Py_SIZE_PTR "&Py_SIZE"(object) + int limb_bits "(8 * sizeof(mp_limb_t))" + + +# Unused bits in every PyLong digit +cdef size_t PyLong_nails = 8*sizeof(digit) - PyLong_SHIFT + + +cdef mpz_get_pylong_large(mpz_srcptr z): + """ + Convert a non-zero ``mpz`` to a Python ``long``. + """ + cdef size_t nbits = mpz_sizeinbase(z, 2) + cdef size_t pylong_size = (nbits + PyLong_SHIFT - 1) // PyLong_SHIFT + L = _PyLong_New(pylong_size) + mpz_export(L.ob_digit, NULL, + -1, sizeof(digit), 0, PyLong_nails, z) + if mpz_sgn(z) < 0: + # Set correct size (use a pointer to hack around Cython's + # non-support for lvalues). + sizeptr = Py_SIZE_PTR(L) + sizeptr[0] = -pylong_size + return L + + +cdef mpz_get_pylong(mpz_srcptr z): + """ + Convert an ``mpz`` to a Python ``long``. + """ + if mpz_fits_slong_p(z): + return PyLong_FromLong(mpz_get_si(z)) + return mpz_get_pylong_large(z) + + +cdef int mpz_set_pylong(mpz_ptr z, L) except -1: + """ + Convert a Python ``long`` `L` to an ``mpz``. + """ + cdef Py_ssize_t pylong_size = Py_SIZE(L) + if pylong_size < 0: + pylong_size = -pylong_size + mpz_import(z, pylong_size, -1, sizeof(digit), 0, PyLong_nails, + (L).ob_digit) + if Py_SIZE(L) < 0: + mpz_neg(z, z) + + +# utils +cdef str mpz_get_pystr(mpz_t x, base): + cdef char * res_char + cdef bytes res_b + res_char = mpz_get_str(NULL, base, x) + try: + res_b = res_char + finally: + free(res_char) + return res_b.decode('utf-8') + + +# fq_t operations +cdef void fq_t_init(fq_t rop): + mpz_init2(rop, INIT_BITS) + + +cdef void fq_t_init_set(fq_t rop, fq_t a): + mpz_init2(rop, INIT_BITS) + mpz_set(rop, a) + + +cdef int fq_t_init_set_pylong(fq_t rop, L) except -1: + mpz_init2(rop, INIT_BITS) + mpz_set_pylong(rop, L) + + +cdef int fq_t_init_set_pylong_mod(fq_t rop, mpz_t Q, L) except -1: + mpz_init2(rop, INIT_BITS) + mpz_set_pylong(rop, L) + mpz_fdiv_r(rop, rop, Q) + +cdef int fq_t_set_pylong(fq_t rop, L) except -1: + mpz_set_pylong(rop, L) + + +cdef fq_t_get_pylong(fq_t a): + return mpz_get_pylong(a) + + +cdef str fq_t_get_pystr(fq_t x, base): + return 'Fq(%s)' % mpz_get_pystr(x, base) + + +cdef unsigned int fq_t_eq(fq_t a, fq_t b): + if mpz_cmp(a, b) == 0: + return 1 + else: + return 0 + + +cdef void fq_t_invert(fq_t rop, fq_t a, mpz_t z): + mpz_invert(rop, a, z) + + +cdef void fq_t_floordiv(fq_t rop, fq_t a, fq_t x, mpz_t z): + cdef mpz_ptr res + cdef int _res + res = fq_t_get(&_res) + mpz_invert(res, x, z) + mpz_mul(res, res, a) + mpz_fdiv_r(rop, res, z) + fq_t_release(_res) + + +cdef void fq_t_pow(fq_t rop, fq_t a, fq_t e, mpz_t z): + mpz_powm(rop, a, e, z) + + +cdef void fqt_neg(fq_t rop, fq_t a): + mpz_neg(rop, a) + mpz_fdiv_r(rop, rop, Q) + + +cdef void fqt_add(fq_t rop, fq_t a, fq_t b): + mpz_add(rop, a, b) + mpz_fdiv_r(rop, rop, Q) + + +cdef void fqt_sub(fq_t rop, fq_t a, fq_t b): + mpz_sub(rop, a, b) + mpz_fdiv_r(rop, rop, Q) + + +cdef void fqt_mul(fq_t rop, fq_t a, fq_t b): + mpz_mul(rop, a, b) + mpz_fdiv_r(rop, rop, Q) + + +# fq2_t operations +cdef void fq2_t_init(fq2_t rop): + for i in range(2): + fq_t_init(&rop[i]) + + +cdef void fq2_t_set(fq2_t rop, fq2_t a): + for i in range(2): + mpz_set(&rop[i], &a[i]) + + +cdef void fq2_t_init_set_fq_t(fq2_t rop, fq_t a): + fq_t_init_set(&rop[0], a) + fq_t_init(&rop[1]) + + +cdef void fq2_t_init_set_fq2(fq2_t rop, a): + for i in range(2): + fq_t_init_set_pylong(&rop[i], a[i]) + + +cdef void fq2_t_set_fq2(fq2_t rop, a): + for i in range(2): + mpz_set_pylong(&rop[i], a[i]) + + +cdef tuple fq2_t_get_fq2(fq2_t a): + res = [] + for i in range(2): + res.append(mpz_get_pylong(&a[i])) + return tuple(res) + + +cdef str fq2_t_get_pystr(fq2_t x, base): + fq_str_list = [fq_t_get_pystr(&x[i], base) for i in range(2)] + return f'Fq2({", ".join(fq_str_list)})' + + +cdef unsigned int fq2_t_eq(fq2_t a, fq2_t b): + eq_cnt = 0 + for i in range(2): + if mpz_cmp(&a[i], &b[i]) == 0: + eq_cnt += 1 + if eq_cnt == 2: + return 1 + else: + return 0 + +cdef void fq2_t_invert(fq2_t rop, fq2_t x_op): + cdef mpz_ptr res + cdef int _res + res = fq2_t_get(&_res) + fq2_t_set(res, x_op) + # factor = inv(a*a + b*b) + mpz_mul(&res[0], &res[0], &res[0]) + mpz_mul(&res[1], &res[1], &res[1]) + mpz_add(&res[0], &res[0], &res[1]) + mpz_invert(&res[0], &res[0], Q) + # res0 = a*factor + mpz_mul(&rop[0], &x_op[0], &res[0]) + mpz_fdiv_r(&rop[0], &rop[0], Q) + # res1 = -b*factor + mpz_neg(&res[0], &res[0]) + mpz_mul(&rop[1], &x_op[1], &res[0]) + mpz_fdiv_r(&rop[1], &rop[1], Q) + fq2_t_release(_res) + + +cdef void fq2_t_floordiv(fq2_t rop, fq2_t a_op, fq2_t x_op): + cdef mpz_ptr res + cdef int _res + res = fq2_t_get(&_res) + fq2_t_invert(res, x_op) + fq2_t_mul(rop, a_op, res) + fq2_t_release(_res) + + +cdef void fq2_t_qi_pow(fq2_t rop, fq2_t x_op, unsigned int i): + i %= 2 + if i == 0: + fq2_t_set(rop, x_op) + return + mpz_mul(&rop[1], &x_op[1], fq2_t_root) # frob coeff equals to fq2_t_root + mpz_fdiv_r(&rop[1], &rop[1], Q) + + +cdef void fq2_t_pow(fq2_t rop, fq2_t a_op, mpz_t e_op): + cdef mpz_ptr res, tmul + cdef mp_bitcnt_t bits_left, bit_n + cdef int _tmul, _res + tmul = fq2_t_get(&_tmul) + res = fq2_t_get(&_res) + fq2_t_set(res, fq2_t_one) + fq2_t_set(tmul, a_op) + + bit_n = 0 + bits_left = mpz_popcount(e_op) + while bits_left > 0: + if mpz_tstbit(e_op, bit_n): + fq2_t_mul(res, res, tmul) + bits_left -= 1 + fq2_t_mul(tmul, tmul, tmul) + bit_n += 1 + + fq2_t_set(rop, res) + fq2_t_release(_tmul) + fq2_t_release(_res) + + +cdef void fq2_t_mul_by_nonresidue(fq2_t rop, fq2_t a_op): + '''(a - b) % Q, (a + b) % Q''' + cdef mpz_ptr res + cdef int _res + res = fq2_t_get(&_res) + + mpz_sub(&res[0], &a_op[0], &a_op[1]) + mpz_fdiv_r(&res[0], &res[0], Q) + mpz_add(&res[1], &a_op[0], &a_op[1]) + mpz_fdiv_r(&res[1], &res[1], Q) + + fq2_t_set(rop, res) + fq2_t_release(_res) + + +cdef void fq2_t_add(fq2_t rop, fq2_t a_op, fq2_t m_op): + for i in range(2): + fqt_add(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq2_t_sub(fq2_t rop, fq2_t a_op, fq2_t m_op): + for i in range(2): + fqt_sub(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq2_t_mul_fq_t(fq2_t rop, fq2_t a_op, fq_t m_op): + for i in range(2): + fqt_mul(&rop[i], &a_op[i], m_op) + + +cdef void fq2_t_mul(fq2_t rop, fq2_t a_op, fq2_t m_op): + '''(a, b)*(m, n) = (a*m - b*n) % Q, (a*n + b*m) % Q''' + cdef mpz_ptr res, tmul + cdef int _tmul, _res + tmul = fq_t_get(&_tmul) + res = fq2_t_get(&_res) + mpz_mul(&res[0], &a_op[0], &m_op[0]) + mpz_mul(tmul, &a_op[1], &m_op[1]) + mpz_sub(&res[0], &res[0], tmul) + mpz_fdiv_r(&res[0], &res[0], Q) + mpz_mul(&res[1], &a_op[0], &m_op[1]) + mpz_mul(tmul, &a_op[1], &m_op[0]) + mpz_add(&res[1], &res[1], tmul) + mpz_fdiv_r(&res[1], &res[1], Q) + fq2_t_set(rop, res) + fq_t_release(_tmul) + fq2_t_release(_res) + + +# fq6_t operations +cdef void fq6_t_init(fq6_t rop): + for i in range(6): + fq_t_init(&rop[i]) + + +cdef void fq6_t_set(fq6_t rop, fq6_t a): + for i in range(6): + mpz_set(&rop[i], &a[i]) + + +cdef void fq6_t_init_set_fq_t(fq6_t rop, fq_t a): + fq_t_init_set(&rop[0], a) + for i in range(1, 6): + fq_t_init(&rop[i]) + + +cdef void fq6_t_init_set_fq6(fq6_t rop, a): + for i in range(6): + fq_t_init_set_pylong(&rop[i], a[i]) + + +cdef void fq6_t_set_fq6(fq6_t rop, a): + for i in range(6): + mpz_set_pylong(&rop[i], a[i]) + + +cdef tuple fq6_t_get_fq6(fq6_t a): + res = [] + for i in range(6): + res.append(mpz_get_pylong(&a[i])) + return tuple(res) + + +cdef str fq6_t_get_pystr(fq6_t x, base): + fq2_str_list = [fq2_t_get_pystr(&x[i*2], base) for i in range(3)] + return f'Fq6({", ".join(fq2_str_list)})' + + +cdef void fq6_t_neg(fq6_t rop, fq6_t x_op): + for i in range(6): + mpz_neg(&rop[i], &x_op[i]) + mpz_fdiv_r(&rop[i], &rop[i], Q) + + +cdef void fq6_t_invert(fq6_t rop, fq6_t x_op): + cdef mpz_ptr tmul, res + cdef int _tmul, _res + tmul = fq2_t_get(&_tmul) + res = fq6_t_get(&_res) + # g0 = a*a - b*nor(c) + fq2_t_mul(&res[0], &x_op[0], &x_op[0]) + fq2_t_mul_by_nonresidue(tmul, &x_op[4]) + fq2_t_mul(tmul, tmul, &x_op[2]) + fq2_t_sub(&res[0], &res[0], tmul) + # g1 = nor(c*c) - a*b + fq2_t_mul(&res[2], &x_op[4], &x_op[4]) + fq2_t_mul_by_nonresidue(&res[2], &res[2]) + fq2_t_mul(tmul, &x_op[0], &x_op[2]) + fq2_t_sub(&res[2], &res[2], tmul) + # g2 = b*b - a*c + fq2_t_mul(&res[4], &x_op[2], &x_op[2]) + fq2_t_mul(tmul, &x_op[0], &x_op[4]) + fq2_t_sub(&res[4], &res[4], tmul) + # factor = inv(g0*a + nor(g1*c + g2*b)) + fq2_t_mul(&x_op[0], &x_op[0], &res[0]) + fq2_t_mul(&x_op[4], &x_op[4], &res[2]) + fq2_t_mul(&x_op[2], &x_op[2], &res[4]) + fq2_t_add(tmul, &x_op[4], &x_op[2]) + fq2_t_mul_by_nonresidue(tmul, tmul) + fq2_t_add(tmul, tmul, &x_op[0]) + fq2_t_invert(tmul, tmul) + # res0 = g0 * factor + # res1 = g1 * factor + # res2 = g2 * factor + fq2_t_mul(&rop[0], &res[0], tmul) + fq2_t_mul(&rop[2], &res[2], tmul) + fq2_t_mul(&rop[4], &res[4], tmul) + fq2_t_release(_tmul) + fq6_t_release(_res) + + +cdef void fq6_t_floordiv(fq6_t rop, fq6_t a_op, fq6_t x_op): + cdef mpz_ptr res + cdef int _res + res = fq6_t_get(&_res) + fq6_t_invert(res, x_op) + fq6_t_mul(rop, res, a_op) + fq6_t_release(_res) + + +cdef void fq6_t_qi_pow(fq6_t rop, fq6_t x_op, unsigned int i): + i %= 6 + if i == 0: + fq6_t_set(rop, x_op) + return + fq2_t_qi_pow(&rop[0], &x_op[0], i) + fq2_t_qi_pow(&rop[2], &x_op[2], i) + fq2_t_mul(&rop[2], &rop[2], fc_6[i-1][0]) + fq2_t_qi_pow(&rop[4], &x_op[4], i) + fq2_t_mul(&rop[4], &rop[4], fc_6[i-1][1]) + + +cdef void fq6_t_mul_by_nonresidue(fq6_t rop, fq6_t a_op): + '''(e - f) % Q, (e + f) %Q, a, b, c, d''' + cdef mpz_ptr res + cdef int _res + res = fq6_t_get(&_res) + + mpz_sub(&res[0], &a_op[4], &a_op[5]) + mpz_fdiv_r(&res[0], &res[0], Q) + mpz_add(&res[1], &a_op[4], &a_op[5]) + mpz_fdiv_r(&res[1], &res[1], Q) + mpz_set(&res[2], &a_op[0]) + mpz_set(&res[3], &a_op[1]) + mpz_set(&res[4], &a_op[2]) + mpz_set(&res[5], &a_op[3]) + + fq6_t_set(rop, res) + fq6_t_release(_res) + + +cdef void fq6_t_add(fq6_t rop, fq6_t a_op, fq6_t m_op): + for i in range(6): + fqt_add(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq6_t_sub(fq6_t rop, fq6_t a_op, fq6_t m_op): + for i in range(6): + fqt_sub(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq6_t_mul(fq6_t rop, fq6_t a_op, fq6_t m_op): + ''' + r0 = am - bn + cq - cr - dr - dq + eo - ep - fp - fo + r1 = an + bm + cq + cr - dr + dq + eo + ep - fp + fo + r2 = ao - bp + cm - dn + eq - er - fr - fq + r3 = ap + bo + cn + dm + eq + er - fr + fq + r4 = aq - br + co - dp + em - fn + r5 = ar + bq + cp + do + en + fm + ''' + cdef mpz_ptr a, b, c, d, e, f, m, n, o, p, q, r, r0, r1, r2, r3, r4, r5 + cdef mpz_ptr tmul, res + cdef int _tmul, _res + tmul = fq_t_get(&_tmul) + res = fq6_t_get(&_res) + + a = &a_op[0]; b = &a_op[1]; c = &a_op[2]; + d = &a_op[3]; e = &a_op[4]; f = &a_op[5]; + m = &m_op[0]; n = &m_op[1]; o = &m_op[2]; + p = &m_op[3]; q = &m_op[4]; r = &m_op[5]; + r0 = &res[0]; r1 = &res[1]; r2 = &res[2]; + r3 = &res[3]; r4 = &res[4]; r5 = &res[5]; + + mpz_mul(r0, a, m); mpz_mul(r1, a, n); mpz_mul(r2, a, o); + mpz_mul(r3, a, p); mpz_mul(r4, a, q); mpz_mul(r5, a, r); + + mpz_mul(tmul, b, n); mpz_sub(r0, r0, tmul); + mpz_mul(tmul, b, m); mpz_add(r1, r1, tmul); + mpz_mul(tmul, b, p); mpz_sub(r2, r2, tmul); + mpz_mul(tmul, b, o); mpz_add(r3, r3, tmul); + mpz_mul(tmul, b, r); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, b, q); mpz_add(r5, r5, tmul); + + mpz_mul(tmul, c, q); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, c, m); mpz_add(r2, r2, tmul); + mpz_mul(tmul, c, n); mpz_add(r3, r3, tmul); + mpz_mul(tmul, c, o); mpz_add(r4, r4, tmul); + mpz_mul(tmul, c, p); mpz_add(r5, r5, tmul); + + mpz_mul(tmul, c, r); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, d, n); mpz_sub(r2, r2, tmul); + mpz_mul(tmul, d, m); mpz_add(r3, r3, tmul); + mpz_mul(tmul, d, p); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, d, o); mpz_add(r5, r5, tmul); + + mpz_mul(tmul, d, r); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, e, q); mpz_add(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, e, m); mpz_add(r4, r4, tmul); + mpz_mul(tmul, e, n); mpz_add(r5, r5, tmul); + + mpz_mul(tmul, d, q); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, e, r); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, f, n); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, f, m); mpz_add(r5, r5, tmul); + + mpz_mul(tmul, e, o); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, f, r); mpz_sub(r3, r3, tmul); mpz_sub(r2, r2, tmul); + + mpz_mul(tmul, e, p); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, f, q); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + + mpz_mul(tmul, f, p); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, f, o); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + + mpz_fdiv_r(r0, r0, Q) + mpz_fdiv_r(r1, r1, Q) + mpz_fdiv_r(r2, r2, Q) + mpz_fdiv_r(r3, r3, Q) + mpz_fdiv_r(r4, r4, Q) + mpz_fdiv_r(r5, r5, Q) + + fq6_t_set(rop, res) + fq_t_release(_tmul) + fq6_t_release(_res) + + +# fq12_t operations +cdef void fq12_t_init(fq12_t rop): + for i in range(12): + fq_t_init(&rop[i]) + + +cdef void fq12_t_set(fq12_t rop, fq12_t a): + for i in range(12): + mpz_set(&rop[i], &a[i]) + + +cdef void fq12_t_init_set_fq_t(fq12_t rop, fq_t a): + fq_t_init_set(&rop[0], a) + for i in range(1, 12): + fq_t_init(&rop[i]) + + +cdef void fq12_t_set_fq12(fq12_t rop, a): + for i in range(12): + mpz_set_pylong(&rop[i], a[i]) + + +cdef tuple fq12_t_get_fq12(fq12_t a): + res = [] + for i in range(12): + res.append(mpz_get_pylong(&a[i])) + return tuple(res) + + +cdef str fq12_t_get_pystr(fq12_t x, base): + fq6_str_list = [fq6_t_get_pystr(&x[i*6], base) for i in range(2)] + return f'Fq12({", ".join(fq6_str_list)})' + + +cdef unsigned int fq12_t_eq(fq12_t a, fq12_t b): + eq_cnt = 0 + for i in range(12): + if mpz_cmp(&a[i], &b[i]) == 0: + eq_cnt += 1 + if eq_cnt == 12: + return 1 + else: + return 0 + + +cdef void fq12_t_neg(fq12_t rop, fq12_t a_op): + for i in range(12): + fqt_neg(&rop[i], &a_op[i]) + + +cdef void fq12_t_invert(fq12_t rop, fq12_t x_op): + cdef mpz_ptr res + cdef int _res + res = fq12_t_get(&_res) + # factor = inv(a*a - nor(b*b)) + fq12_t_set(res, x_op) + fq6_t_mul(&res[0], &res[0], &res[0]) + fq6_t_mul(&res[6], &res[6], &res[6]) + fq6_t_mul_by_nonresidue(&res[6], &res[6]) + fq6_t_sub(&res[0], &res[0], &res[6]) + fq6_t_invert(&res[0], &res[0]) + # res1 = a*factor + fq6_t_mul(&rop[0], &x_op[0], &res[0]) + # res2 = -b*factor + fq6_t_neg(&res[0], &res[0]) + fq6_t_mul(&rop[6], &x_op[6], &res[0]) + fq12_t_release(_res) + + +cdef void fq12_t_floordiv(fq12_t rop, fq12_t a_op, fq12_t x_op): + cdef mpz_ptr res + cdef int _res + res = fq12_t_get(&_res) + fq12_t_invert(res, x_op) + fq12_t_mul(rop, res, a_op) + fq12_t_release(_res) + + +cdef void fq12_t_qi_pow(fq12_t rop, fq12_t x_op, unsigned int i): + i %= 12 + if i == 0: + fq12_t_set(rop, x_op) + return + fq6_t_qi_pow(&rop[0], &x_op[0], i) + fq6_t_qi_pow(&rop[6], &x_op[6], i) + fq6_t_mul(&rop[6], &rop[6], fc_12[i-1]) + + +cdef void fq12_t_pow(fq12_t rop, fq12_t a_op, mpz_t e_op): + cdef mpz_ptr res, tmul + cdef mp_bitcnt_t bits_left, bit_n + cdef int _res, _tmul + res = fq12_t_get(&_res) + tmul = fq12_t_get(&_tmul) + fq12_t_set(res, fq12_t_one) + fq12_t_set(tmul, a_op) + + bit_n = 0 + bits_left = mpz_popcount(e_op) + while bits_left > 0: + if mpz_tstbit(e_op, bit_n): + fq12_t_mul(res, res, tmul) + bits_left -= 1 + fq12_t_mul(tmul, tmul, tmul) + bit_n += 1 + + fq12_t_set(rop, res) + fq12_t_release(_res) + fq12_t_release(_tmul) + + +cdef void fq12_t_add(fq12_t rop, fq12_t a_op, fq12_t m_op): + for i in range(12): + fqt_add(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq_t_sub_fq12_t(fq12_t rop, fq_t a_op, fq12_t m_op): + fqt_sub(&rop[0], a_op, &m_op[0]) + for i in range(1, 12): + fqt_neg(&rop[i], &m_op[i]) + + +cdef void fq12_t_sub(fq12_t rop, fq12_t a_op, fq12_t m_op): + for i in range(12): + fqt_sub(&rop[i], &a_op[i], &m_op[i]) + + +cdef void fq12_t_mul_fq_t(fq12_t rop, fq12_t a_op, fq_t m_op): + for i in range(12): + fqt_mul(&rop[i], &a_op[i], m_op) + + +cdef void fq12_t_mul(fq12_t rop, fq12_t a_op, fq12_t m_op): + ''' + r0 = (am - bn + cq - cr - dr - dq + eo - ep - fp - fo + + gw - gx - hx - hw + iu - iv - jv - ju + ks - kt - lt - ls) + r1 = (an + bm + cq + cr - dr + dq + eo + ep - fp + fo + + gw + gx - hx + hw + iu + iv - jv + ju + ks + kt - lt + ls) + r2 = (ao - bp + cm - dn + eq - er - fr - fq + gs - ht + + iw - ix - jx - jw + ku - kv - lv - lu) + r3 = (ap + bo + cn + dm + eq + er - fr + fq + gt + hs + + iw + ix - jx + jw + ku + kv - lv + lu) + r4 = (aq - br + co - dp + em - fn + gu - hv + is - jt + + kw - kx - lx - lw) + r5 = (ar + bq + cp + do + en + fm + gv + hu + it + js + + kw + kx - lx + lw) + r6 = (as - bt + cw - cx - dx - dw + eu - ev - fv - fu + + gm - hn + iq - ir - jr - jq + ko - kp - lp - lo) + r7 = (at + bs + cw + cx - dx + dw + eu + ev - fv + fu + + gn + hm + iq + ir - jr + jq + ko + kp - lp + lo) + r8 = (au - bv + cs - dt + ew - ex - fx - fw + go - hp + + im - jn + kq - kr - lr - lq) + r9 = (av + bu + ct + ds + ew + ex - fx + fw + gp + ho + + in + jm + kq + kr - lr + lq) + r10 = aw - bx + cu - dv + es - ft + gq - hr + io - jp + km - ln + r11 = ax + bw + cv + du + et + fs + gr + hq + ip + jo + kn + lm + ''' + cdef mpz_ptr a, b, c, d, e, f, g, h, i, j, k, l, r0, r1, r2, r3, r4, r5 + cdef mpz_ptr m, n, o, p, q, r, s, t, u, v, w, x, r6, r7, r8, r9, r10, r11 + cdef mpz_ptr tmul, res + cdef int _tmul, _res + res = fq12_t_get(&_res) + tmul = fq_t_get(&_tmul) + + a = &a_op[0]; b = &a_op[1]; c = &a_op[2]; + d = &a_op[3]; e = &a_op[4]; f = &a_op[5]; + g = &a_op[6]; h = &a_op[7]; i = &a_op[8]; + j = &a_op[9]; k = &a_op[10]; l = &a_op[11]; + m = &m_op[0]; n = &m_op[1]; o = &m_op[2]; + p = &m_op[3]; q = &m_op[4]; r = &m_op[5]; + s = &m_op[6]; t = &m_op[7]; u = &m_op[8]; + v = &m_op[9]; w = &m_op[10]; x = &m_op[11]; + r0 = &res[0]; r1 = &res[1]; r2 = &res[2]; + r3 = &res[3]; r4 = &res[4]; r5 = &res[5]; + r6 = &res[6]; r7 = &res[7]; r8 = &res[8]; + r9 = &res[9]; r10 = &res[10]; r11 = &res[11]; + + mpz_mul(r0, a, m); mpz_mul(r1, a, n); mpz_mul(r2, a, o); + mpz_mul(r3, a, p); mpz_mul(r4, a, q); mpz_mul(r5, a, r); + mpz_mul(r6, a, s); mpz_mul(r7, a, t); mpz_mul(r8, a, u); + mpz_mul(r9, a, v); mpz_mul(r10, a, w); mpz_mul(r11, a, x); + + mpz_mul(tmul, b, n); mpz_sub(r0, r0, tmul); + mpz_mul(tmul, b, m); mpz_add(r1, r1, tmul); + mpz_mul(tmul, b, p); mpz_sub(r2, r2, tmul); + mpz_mul(tmul, b, o); mpz_add(r3, r3, tmul); + mpz_mul(tmul, b, r); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, b, q); mpz_add(r5, r5, tmul); + mpz_mul(tmul, b, t); mpz_sub(r6, r6, tmul); + mpz_mul(tmul, b, s); mpz_add(r7, r7, tmul); + mpz_mul(tmul, b, v); mpz_sub(r8, r8, tmul); + mpz_mul(tmul, b, u); mpz_add(r9, r9, tmul); + mpz_mul(tmul, b, x); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, b, w); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, c, q); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, c, m); mpz_add(r2, r2, tmul); + mpz_mul(tmul, c, n); mpz_add(r3, r3, tmul); + mpz_mul(tmul, c, o); mpz_add(r4, r4, tmul); + mpz_mul(tmul, c, p); mpz_add(r5, r5, tmul); + mpz_mul(tmul, c, w); mpz_add(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, c, s); mpz_add(r8, r8, tmul); + mpz_mul(tmul, c, t); mpz_add(r9, r9, tmul); + mpz_mul(tmul, c, u); mpz_add(r10, r10, tmul); + mpz_mul(tmul, c, v); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, c, r); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, d, n); mpz_sub(r2, r2, tmul); + mpz_mul(tmul, d, m); mpz_add(r3, r3, tmul); + mpz_mul(tmul, d, p); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, d, o); mpz_add(r5, r5, tmul); + mpz_mul(tmul, c, x); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, d, t); mpz_sub(r8, r8, tmul); + mpz_mul(tmul, d, s); mpz_add(r9, r9, tmul); + mpz_mul(tmul, d, v); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, d, u); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, d, r); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, e, q); mpz_add(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, e, m); mpz_add(r4, r4, tmul); + mpz_mul(tmul, e, n); mpz_add(r5, r5, tmul); + mpz_mul(tmul, d, x); mpz_sub(r6, r6, tmul); mpz_sub(r7, r7, tmul); + mpz_mul(tmul, e, w); mpz_add(r8, r8, tmul); mpz_add(r9, r9, tmul); + mpz_mul(tmul, e, s); mpz_add(r10, r10, tmul); + mpz_mul(tmul, e, t); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, d, q); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, e, r); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, f, n); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, f, m); mpz_add(r5, r5, tmul); + mpz_mul(tmul, d, w); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, e, x); mpz_sub(r8, r8, tmul); mpz_add(r9, r9, tmul); + mpz_mul(tmul, f, t); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, f, s); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, e, o); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, f, r); mpz_sub(r2, r2, tmul); mpz_sub(r3, r3, tmul); + mpz_mul(tmul, g, u); mpz_add(r4, r4, tmul); + mpz_mul(tmul, g, v); mpz_add(r5, r5, tmul); + mpz_mul(tmul, e, u); mpz_add(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, f, x); mpz_sub(r8, r8, tmul); mpz_sub(r9, r9, tmul); + mpz_mul(tmul, g, q); mpz_add(r10, r10, tmul); + mpz_mul(tmul, g, r); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, e, p); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, f, q); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, h, v); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, h, u); mpz_add(r5, r5, tmul); + mpz_mul(tmul, e, v); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, f, w); mpz_sub(r8, r8, tmul); mpz_add(r9, r9, tmul); + mpz_mul(tmul, h, r); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, h, q); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, f, p); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, g, s); mpz_add(r2, r2, tmul); + mpz_mul(tmul, g, t); mpz_add(r3, r3, tmul); + mpz_mul(tmul, i, s); mpz_add(r4, r4, tmul); + mpz_mul(tmul, i, t); mpz_add(r5, r5, tmul); + mpz_mul(tmul, f, v); mpz_sub(r6, r6, tmul); mpz_sub(r7, r7, tmul); + mpz_mul(tmul, g, o); mpz_add(r8, r8, tmul); + mpz_mul(tmul, g, p); mpz_add(r9, r9, tmul); + mpz_mul(tmul, i, o); mpz_add(r10, r10, tmul); + mpz_mul(tmul, i, p); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, f, o); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, h, t); mpz_sub(r2, r2, tmul); + mpz_mul(tmul, h, s); mpz_add(r3, r3, tmul); + mpz_mul(tmul, j, t); mpz_sub(r4, r4, tmul); + mpz_mul(tmul, j, s); mpz_add(r5, r5, tmul); + mpz_mul(tmul, f, u); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, h, p); mpz_sub(r8, r8, tmul); + mpz_mul(tmul, h, o); mpz_add(r9, r9, tmul); + mpz_mul(tmul, j, p); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, j, o); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, g, w); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, i, w); mpz_add(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, k, w); mpz_add(r4, r4, tmul); mpz_add(r5, r5, tmul); + mpz_mul(tmul, g, m); mpz_add(r6, r6, tmul); + mpz_mul(tmul, g, n); mpz_add(r7, r7, tmul); + mpz_mul(tmul, i, m); mpz_add(r8, r8, tmul); + mpz_mul(tmul, i, n); mpz_add(r9, r9, tmul); + mpz_mul(tmul, k, m); mpz_add(r10, r10, tmul); + mpz_mul(tmul, k, n); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, g, x); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, i, x); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, k, x); mpz_sub(r4, r4, tmul); mpz_add(r5, r5, tmul); + mpz_mul(tmul, h, n); mpz_sub(r6, r6, tmul); + mpz_mul(tmul, h, m); mpz_add(r7, r7, tmul); + mpz_mul(tmul, j, n); mpz_sub(r8, r8, tmul); + mpz_mul(tmul, j, m); mpz_add(r9, r9, tmul); + mpz_mul(tmul, l, n); mpz_sub(r10, r10, tmul); + mpz_mul(tmul, l, m); mpz_add(r11, r11, tmul); + + mpz_mul(tmul, h, x); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, j, x); mpz_sub(r2, r2, tmul); mpz_sub(r3, r3, tmul); + mpz_mul(tmul, l, x); mpz_sub(r4, r4, tmul); mpz_sub(r5, r5, tmul); + mpz_mul(tmul, i, q); mpz_add(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, k, q); mpz_add(r8, r8, tmul); mpz_add(r9, r9, tmul); + + mpz_mul(tmul, h, w); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, j, w); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, l, w); mpz_sub(r4, r4, tmul); mpz_add(r5, r5, tmul); + mpz_mul(tmul, i, r); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, k, r); mpz_sub(r8, r8, tmul); mpz_add(r9, r9, tmul); + + mpz_mul(tmul, i, u); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, k, u); mpz_add(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, j, r); mpz_sub(r6, r6, tmul); mpz_sub(r7, r7, tmul); + mpz_mul(tmul, l, r); mpz_sub(r8, r8, tmul); mpz_sub(r9, r9, tmul); + + mpz_mul(tmul, i, v); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, k, v); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, j, q); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + mpz_mul(tmul, l, q); mpz_sub(r8, r8, tmul); mpz_add(r9, r9, tmul); + + mpz_mul(tmul, j, v); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + mpz_mul(tmul, l, v); mpz_sub(r2, r2, tmul); mpz_sub(r3, r3, tmul); + mpz_mul(tmul, k, o); mpz_add(r6, r6, tmul); mpz_add(r7, r7, tmul); + + mpz_mul(tmul, j, u); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, l, u); mpz_sub(r2, r2, tmul); mpz_add(r3, r3, tmul); + mpz_mul(tmul, k, p); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + + mpz_mul(tmul, k, s); mpz_add(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, l, p); mpz_sub(r6, r6, tmul); mpz_sub(r7, r7, tmul); + + mpz_mul(tmul, k, t); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + mpz_mul(tmul, l, o); mpz_sub(r6, r6, tmul); mpz_add(r7, r7, tmul); + + mpz_mul(tmul, l, t); mpz_sub(r0, r0, tmul); mpz_sub(r1, r1, tmul); + + mpz_mul(tmul, l, s); mpz_sub(r0, r0, tmul); mpz_add(r1, r1, tmul); + + mpz_fdiv_r(r0, r0, Q) + mpz_fdiv_r(r1, r1, Q) + mpz_fdiv_r(r2, r2, Q) + mpz_fdiv_r(r3, r3, Q) + mpz_fdiv_r(r4, r4, Q) + mpz_fdiv_r(r5, r5, Q) + mpz_fdiv_r(r6, r6, Q) + mpz_fdiv_r(r7, r7, Q) + mpz_fdiv_r(r8, r8, Q) + mpz_fdiv_r(r9, r9, Q) + mpz_fdiv_r(r10, r10, Q) + mpz_fdiv_r(r11, r11, Q) + + fq12_t_set(rop, res) + fq12_t_release(_res) + fq_t_release(_tmul) + + +# ec.py, paring.py calc operations on fq_t, fq2_t, fq12_t operands +cdef void fq2_t_to_affine(fq2_t ropx, fq2_t ropy, int *ropinf, + fq2_t x, fq2_t y, fq2_t z, int inf): + cdef mpz_ptr z_sq, z_cu + cdef int _z_sq, _z_cu + if inf: + fq2_t_set(ropx, x) + fq2_t_set(ropy, y) + ropinf[0] = inf + + z_sq = fq2_t_get(&_z_sq) + z_cu = fq2_t_get(&_z_cu) + # x = x * invert(z^2) + # y = y * invert(z^3) + fq2_t_mul(z_sq, z, z) + fq2_t_mul(z_cu, z_sq, z) + fq2_t_invert(z_sq, z_sq) + fq2_t_invert(z_cu, z_cu) + fq2_t_mul(ropx, x, z_sq) + fq2_t_mul(ropy, y, z_cu) + ropinf[0] = inf + + fq2_t_release(_z_sq) + fq2_t_release(_z_cu) + + +cdef void fq2_t_double_point(fq2_t ropx, fq2_t ropy, int *ropinf, + fq2_t px, fq2_t py, int *pinf): + cdef mpz_ptr xr, yr, tmul + cdef int _xr, _yr, _tmul + xr = fq2_t_get(&_xr) + yr = fq2_t_get(&_yr) + tmul = fq2_t_get(&_tmul) + + # left = 3 * px * px + fq2_t_pow(yr, px, mpz_n2) + fq2_t_mul_fq_t(yr, yr, mpz_n3) + + # s = left * invert(2*py) + fq2_t_mul_fq_t(xr, py, mpz_n2) + fq2_t_invert(xr, xr) + fq2_t_mul(yr, yr, xr) + + # xr = fq_pow(Q, s, 2) - 2*px + fq2_t_pow(xr, yr, mpz_n2) + fq2_t_sub(xr, xr, px) + fq2_t_sub(xr, xr, px) + + # yr = s * (px - xr) - py + fq2_t_sub(tmul, px, xr) + fq2_t_mul(yr, yr, tmul) + fq2_t_sub(ropy, yr, py) + + fq2_t_set(ropx, xr) + ropinf[0] = 0 + + fq2_t_release(_xr) + fq2_t_release(_yr) + fq2_t_release(_tmul) + + +cdef void fq2_t_add_points(fq2_t ropx, fq2_t ropy, int *ropinf, + fq2_t x1, fq2_t y1, int *inf1, + fq2_t x2, fq2_t y2, int *inf2): + cdef mpz_ptr xr, yr, tmul + cdef int _xr, _yr, _tmul + + if inf1[0]: + fq2_t_set(ropx, x2) + fq2_t_set(ropy, y2) + ropinf[0] = inf2[0] + return + if inf1[0]: + fq2_t_set(ropx, x1) + fq2_t_set(ropy, y1) + ropinf[0] = inf1[0] + return + if fq2_t_eq(x1, x2) and fq2_t_eq(y1, y2): + fq2_t_double_point(ropx, ropy, ropinf, x1, y1, inf1) + return + if fq2_t_eq(x1, x2): + fq2_t_set(ropx, fq2_t_zero) + fq2_t_set(ropy, fq2_t_zero) + ropinf[0] = 1 + return + + xr = fq2_t_get(&_xr) + yr = fq2_t_get(&_yr) + tmul = fq2_t_get(&_tmul) + + # s = (y2 - y1) * inv(x2 - x1) + fq2_t_sub(xr, y2, y1) + fq2_t_sub(yr, x2, x1) + fq2_t_invert(yr, yr) + fq2_t_mul(xr, xr, yr) + + # ropx = s*s - x1 - x2 + fq2_t_pow(yr, xr, mpz_n2) + fq2_t_sub(yr, yr, x1) + fq2_t_sub(yr, yr, x2) + + # ropy = s * (x1 - xr) - y1 + fq2_t_sub(tmul, x1, yr) + fq2_t_mul(xr, xr, tmul) + fq2_t_sub(ropy, xr, y1) + + fq2_t_set(ropx, yr) + ropinf[0] = 0 + + fq2_t_release(_xr) + fq2_t_release(_yr) + fq2_t_release(_tmul) + + +cdef void fq_t_double_point_jacobian(fq_t ropx, fq_t ropy, fq_t ropz, + fq_t x_op, fq_t y_op, fq_t z_op): + cdef mpz_ptr xres, yres, zres + cdef int _xres, _yres, _zres + xres = fq_t_get(&_xres) + yres = fq_t_get(&_yres) + zres = fq_t_get(&_zres) + + # M = 3*X^2 + a*Z^4 + # a is 0 on bls12-381 + mpz_pow_ui(yres, x_op, 2) + mpz_mul_ui(yres, yres, 3) + + # S = 4*X*Y^2 + mpz_pow_ui(zres, y_op, 2) + mpz_mul(zres, zres, x_op) + mpz_mul_ui(zres, zres, 4) + + # X' = M^2 - 2*S + mpz_mul(xres, yres, yres) + mpz_sub(xres, xres, zres) + mpz_sub(xres, xres, zres) + + # Y' = M*(S - X') - 8*Y^4 + mpz_sub(zres, zres, xres) + mpz_mul(yres, yres, zres) + mpz_pow_ui(zres, y_op, 4) + mpz_mul_ui(zres, zres, 8) + mpz_sub(yres, yres, zres) + + # Z' = 2*Y*Z + mpz_mul(zres, y_op, z_op) + mpz_mul_ui(zres, zres, 2) + + mpz_fdiv_r(ropx, xres, Q) + mpz_fdiv_r(ropy, yres, Q) + mpz_fdiv_r(ropz, zres, Q) + + fq_t_release(_xres) + fq_t_release(_yres) + fq_t_release(_yres) + + +cdef void fq2_t_double_point_jacobian(fq2_t ropx, fq2_t ropy, fq2_t ropz, + fq2_t x_op, fq2_t y_op, fq2_t z_op): + cdef mpz_ptr xres, yres, zres + cdef int _xres, _yres, _zres + xres = fq2_t_get(&_xres) + yres = fq2_t_get(&_yres) + zres = fq2_t_get(&_zres) + + # M = 3*X^2 + a*Z^4 + # a is 0 on bls12-381 + fq2_t_pow(yres, x_op, mpz_n2) + fq2_t_mul_fq_t(yres, yres, mpz_n3) + + # S = 4*X*Y^2 + fq2_t_pow(zres, y_op, mpz_n2) + fq2_t_mul(zres, zres, x_op) + fq2_t_mul_fq_t(zres, zres, mpz_n4) + + # X' = M^2 - 2*S + fq2_t_mul(xres, yres, yres) + fq2_t_sub(xres, xres, zres) + fq2_t_sub(xres, xres, zres) + + # Y' = M*(S - X') - 8*Y^4 + fq2_t_sub(zres, zres, xres) + fq2_t_mul(yres, yres, zres) + fq2_t_pow(zres, y_op, mpz_n4) + fq2_t_mul_fq_t(zres, zres, mpz_n8) + fq2_t_sub(yres, yres, zres) + + # Z' = 2*Y*Z + fq2_t_mul(zres, y_op, z_op) + fq2_t_mul_fq_t(zres, zres, mpz_n2) + + for i in range(2): + mpz_fdiv_r(&ropx[i], &xres[i], Q) + mpz_fdiv_r(&ropy[i], &yres[i], Q) + mpz_fdiv_r(&ropz[i], &zres[i], Q) + + fq2_t_release(_xres) + fq2_t_release(_yres) + fq2_t_release(_yres) + + +cdef void fq12_t_double_point_jacobian(fq12_t ropx, fq12_t ropy, fq12_t ropz, + fq12_t x_op, fq12_t y_op, fq12_t z_op): + cdef mpz_ptr xres, yres, zres + cdef int _xres, _yres, _zres + xres = fq12_t_get(&_xres) + yres = fq12_t_get(&_yres) + zres = fq12_t_get(&_zres) + + # M = 3*X^2 + a*Z^4 + # a is 0 on bls12-381 + fq12_t_pow(yres, x_op, mpz_n2) + fq12_t_mul_fq_t(yres, yres, mpz_n3) + + # S = 4*X*Y^2 + fq12_t_pow(zres, y_op, mpz_n2) + fq12_t_mul(zres, zres, x_op) + fq12_t_mul_fq_t(zres, zres, mpz_n4) + + # X' = M^2 - 2*S + fq12_t_mul(xres, yres, yres) + fq12_t_sub(xres, xres, zres) + fq12_t_sub(xres, xres, zres) + + # Y' = M*(S - X') - 8*Y^4 + fq12_t_sub(zres, zres, xres) + fq12_t_mul(yres, yres, zres) + fq12_t_pow(zres, y_op, mpz_n4) + fq12_t_mul_fq_t(zres, zres, mpz_n8) + fq12_t_sub(yres, yres, zres) + + # Z' = 2*Y*Z + fq12_t_mul(zres, y_op, z_op) + fq12_t_mul_fq_t(zres, zres, mpz_n2) + + for i in range(12): + mpz_fdiv_r(&ropx[i], &xres[i], Q) + mpz_fdiv_r(&ropy[i], &yres[i], Q) + mpz_fdiv_r(&ropz[i], &zres[i], Q) + + fq12_t_release(_xres) + fq12_t_release(_yres) + fq12_t_release(_yres) + + +cdef fq_t_add_points_jacobian(fq_t ropx, fq_t ropy, fq_t ropz, int *ropinf, + fq_t x1, fq_t y1, fq_t z1, int *inf1, + fq_t x2, fq_t y2, fq_t z2, int *inf2): + cdef mpz_ptr u1, u2, s1, s2, h_sq + cdef int _u1, _u2, _s1, _s2, _h_sq + + if inf1[0]: + mpz_set(ropx, x2) + mpz_set(ropy, y2) + mpz_set(ropz, z2) + ropinf[0] = inf2[0] + return + if inf2[0]: + mpz_set(ropx, x1) + mpz_set(ropy, y1) + mpz_set(ropz, z1) + ropinf[0] = inf1[0] + return + + u1 = fq_t_get(&_u1) + u2 = fq_t_get(&_u2) + s1 = fq_t_get(&_s1) + s2 = fq_t_get(&_s2) + h_sq = fq_t_get(&_h_sq) + + # u1 = x1*z2^2 + mpz_pow_ui(u1, z2, 2) + mpz_mul(u1, u1, x1) + mpz_fdiv_r(u1, u1, Q) + # u2 = x2*z1^2 + mpz_pow_ui(u2, z1, 2) + mpz_mul(u2, u2, x2) + mpz_fdiv_r(u2, u2, Q) + # s1 = y1*z2^3 + mpz_pow_ui(s1, z2, 3) + mpz_mul(s1, s1, y1) + mpz_fdiv_r(s1, s1, Q) + # s2 = y2*z1^3 + mpz_pow_ui(s2, z1, 3) + mpz_mul(s2, s2, y2) + mpz_fdiv_r(s2, s2, Q) + + if fq_t_eq(u1, u2): + if not fq_t_eq(s1, s2): + mpz_set(ropx, fq_t_one) + mpz_set(ropy, fq_t_one) + mpz_set(ropz, fq_t_zero) + ropinf[0] = 1 + else: + fq_t_double_point_jacobian(ropx, ropy, ropz, x1, y1, z1) + ropinf[0] = 0 + else: + # h = u2 - u1 + mpz_sub(u2, u2, u1) + # r = s2 - s1 + mpz_sub(s2, s2, s1) + # zr = h*z1*z2 + mpz_mul(ropz, z1, z2) + mpz_mul(ropz, ropz, u2) + mpz_fdiv_r(ropz, ropz, Q) + # h^2 + mpz_mul(h_sq, u2, u2) + # h^3 + mpz_mul(ropy, h_sq, u2) + # xr = r^2 - h^3 - 2*u1*h^2 + mpz_mul(ropx, s2, s2) + mpz_sub(ropx, ropx, ropy) + mpz_mul(u1, u1, h_sq) + mpz_sub(ropx, ropx, u1) + mpz_sub(ropx, ropx, u1) + mpz_fdiv_r(ropx, ropx, Q) + # yr = r*(u1*h^2 - xr) - s1*h^3 + mpz_mul(s1, s1, ropy) + mpz_sub(ropy, u1, ropx) + mpz_mul(ropy, ropy, s2) + mpz_sub(ropy, ropy, s1) + mpz_fdiv_r(ropy, ropy, Q) + ropinf[0] = 0 + + fq_t_release(_u1) + fq_t_release(_u2) + fq_t_release(_s1) + fq_t_release(_s2) + fq_t_release(_h_sq) + + +cdef fq2_t_add_points_jacobian(fq2_t ropx, fq2_t ropy, fq2_t ropz, int *ropinf, + fq2_t x1, fq2_t y1, fq2_t z1, int *inf1, + fq2_t x2, fq2_t y2, fq2_t z2, int *inf2): + cdef mpz_ptr u1, u2, s1, s2, h_sq + cdef int _u1, _u2, _s1, _s2, _h_sq + + if inf1[0]: + fq2_t_set(ropx, x2) + fq2_t_set(ropy, y2) + fq2_t_set(ropz, z2) + ropinf[0] = inf2[0] + return + if inf2[0]: + fq2_t_set(ropx, x1) + fq2_t_set(ropy, y1) + fq2_t_set(ropz, z1) + ropinf[0] = inf1[0] + return + + u1 = fq2_t_get(&_u1) + u2 = fq2_t_get(&_u2) + s1 = fq2_t_get(&_s1) + s2 = fq2_t_get(&_s2) + h_sq = fq2_t_get(&_h_sq) + + # u1 = x1*z2^2 + fq2_t_pow(u1, z2, mpz_n2) + fq2_t_mul(u1, u1, x1) + # u2 = x2*z1^2 + fq2_t_pow(u2, z1, mpz_n2) + fq2_t_mul(u2, u2, x2) + # s1 = y1*z2^3 + fq2_t_pow(s1, z2, mpz_n3) + fq2_t_mul(s1, s1, y1) + # s2 = y2*z1^3 + fq2_t_pow(s2, z1, mpz_n3) + fq2_t_mul(s2, s2, y2) + + if fq2_t_eq(u1, u2): + if not fq2_t_eq(s1, s2): + fq2_t_set(ropx, fq2_t_one) + fq2_t_set(ropy, fq2_t_one) + fq2_t_set(ropz, fq2_t_zero) + ropinf[0] = 1 + else: + fq2_t_double_point_jacobian(ropx, ropy, ropz, x1, y1, z1) + ropinf[0] = 0 + else: + # h = u2 - u1 + fq2_t_sub(u2, u2, u1) + # r = s2 - s1 + fq2_t_sub(s2, s2, s1) + # zr = h*z1*z2 + fq2_t_mul(ropz, z1, z2) + fq2_t_mul(ropz, ropz, u2) + # h^2 + fq2_t_mul(h_sq, u2, u2) + # h^3 + fq2_t_mul(ropy, h_sq, u2) + # xr = r^2 - h^3 - 2*u1*h^2 + fq2_t_mul(ropx, s2, s2) + fq2_t_sub(ropx, ropx, ropy) + fq2_t_mul(u1, u1, h_sq) + fq2_t_sub(ropx, ropx, u1) + fq2_t_sub(ropx, ropx, u1) + # yr = r*(u1*h^2 - xr) - s1*h^3 + fq2_t_mul(s1, s1, ropy) + fq2_t_sub(ropy, u1, ropx) + fq2_t_mul(ropy, ropy, s2) + fq2_t_sub(ropy, ropy, s1) + ropinf[0] = 0 + + fq2_t_release(_u1) + fq2_t_release(_u2) + fq2_t_release(_s1) + fq2_t_release(_s2) + fq2_t_release(_h_sq) + + +cdef fq12_t_add_points_jacobian(fq12_t ropx, fq12_t ropy, fq12_t ropz, + int *ropinf, + fq12_t x1, fq12_t y1, fq12_t z1, int *inf1, + fq12_t x2, fq12_t y2, fq12_t z2, int *inf2): + cdef mpz_ptr u1, u2, s1, s2, h_sq + cdef int _u1, _u2, _s1, _s2, _h_sq + + if inf1[0]: + fq12_t_set(ropx, x2) + fq12_t_set(ropy, y2) + fq12_t_set(ropz, z2) + ropinf[0] = inf2[0] + return + if inf2[0]: + fq12_t_set(ropx, x1) + fq12_t_set(ropy, y1) + fq12_t_set(ropz, z1) + ropinf[0] = inf1[0] + return + + u1 = fq12_t_get(&_u1) + u2 = fq12_t_get(&_u2) + s1 = fq12_t_get(&_s1) + s2 = fq12_t_get(&_s2) + h_sq = fq12_t_get(&_h_sq) + + # u1 = x1*z2^2 + fq12_t_pow(u1, z2, mpz_n2) + fq12_t_mul(u1, u1, x1) + # u2 = x2*z1^2 + fq12_t_pow(u2, z1, mpz_n2) + fq12_t_mul(u2, u2, x2) + # s1 = y1*z2^3 + fq12_t_pow(s1, z2, mpz_n3) + fq12_t_mul(s1, s1, y1) + # s2 = y2*z1^3 + fq12_t_pow(s2, z1, mpz_n3) + fq12_t_mul(s2, s2, y2) + + if fq12_t_eq(u1, u2): + if not fq12_t_eq(s1, s2): + fq12_t_set(ropx, fq12_t_one) + fq12_t_set(ropy, fq12_t_one) + fq12_t_set(ropz, fq12_t_zero) + ropinf[0] = 1 + else: + fq12_t_double_point_jacobian(ropx, ropy, ropz, x1, y1, z1) + ropinf[0] = 1 + else: + # h = u2 - u1 + fq12_t_sub(u2, u2, u1) + # r = s2 - s1 + fq12_t_sub(s2, s2, s1) + # zr = h*z1*z2 + fq12_t_mul(ropz, z1, z2) + fq12_t_mul(ropz, ropz, u2) + # h^2 + fq12_t_mul(h_sq, u2, u2) + # h^3 + fq12_t_mul(ropy, h_sq, u2) + # xr = r^2 - h^3 - 2*u1*h^2 + fq12_t_mul(ropx, s2, s2) + fq12_t_sub(ropx, ropx, ropy) + fq12_t_mul(u1, u1, h_sq) + fq12_t_sub(ropx, ropx, u1) + fq12_t_sub(ropx, ropx, u1) + # yr = r*(u1*h^2 - xr) - s1*h^3 + fq12_t_mul(s1, s1, ropy) + fq12_t_sub(ropy, u1, ropx) + fq12_t_mul(ropy, ropy, s2) + fq12_t_sub(ropy, ropy, s1) + ropinf[0] = 0 + + fq12_t_release(_u1) + fq12_t_release(_u2) + fq12_t_release(_s1) + fq12_t_release(_s2) + fq12_t_release(_h_sq) + + +cdef void fq2_t_scalar_mult_jacobian(fq2_t ropx, fq2_t ropy, fq2_t ropz, + int *ropinf, mpz_t c, + fq2_t x, fq2_t y, fq2_t z, int *inf): + cdef mp_bitcnt_t bits_left, bit_n + cdef mpz_ptr tfq, xr, yr, zr + cdef int _tfq, _xr, _yr, _zr, infr + + tfq = fq_t_get(&_tfq) + + mpz_fdiv_r(tfq, c, Q) + if inf[0] or mpz_cmp(tfq, mpz_n0) == 0: + fq2_t_set(ropx, fq2_t_one) + fq2_t_set(ropy, fq2_t_one) + fq2_t_set(ropz, fq2_t_zero) + ropinf[0] = 1 + fq_t_release(_tfq) + return + + xr = fq2_t_get(&_xr) + yr = fq2_t_get(&_yr) + zr = fq2_t_get(&_zr) + fq2_t_set(xr, fq2_t_one) + fq2_t_set(yr, fq2_t_one) + fq2_t_set(zr, fq2_t_zero) + infr = 1 + + bit_n = 0 + bits_left = mpz_popcount(c) + while bits_left > 0: + if mpz_tstbit(c, bit_n): + # result += addend + fq2_t_add_points_jacobian(xr, yr, zr, &infr, + xr, yr, zr, &infr, x, y, z, inf) + bits_left -= 1 + # double point + fq2_t_double_point_jacobian(x, y, z, x, y, z) + bit_n += 1 + fq2_t_set(ropx, xr) + fq2_t_set(ropy, yr) + fq2_t_set(ropz, zr) + ropinf[0] = infr + + fq_t_release(_tfq) + fq2_t_release(_xr) + fq2_t_release(_yr) + fq2_t_release(_zr) + + +cdef void fq2_t_double_line_eval(fq12_t res, + fq2_t rx_t, fq2_t ry_t, fq_t px, fq_t py): + cdef mpz_ptr r12_x, r12_y, slope + cdef int _r12_x, _r12_y, _slope + r12_x = fq12_t_get(&_r12_x) + r12_y = fq12_t_get(&_r12_y) + slope = fq12_t_get(&_slope) + + #R12 = untwist(R) + fq2_t_untwist(r12_x, r12_y, rx_t, ry_t) + + # slope = (3 * pow(R12.x, 2)) / (2 * R12.y) + fq12_t_pow(res, r12_x, mpz_n2) + fq12_t_mul_fq_t(res, res, mpz_n3) + fq12_t_mul_fq_t(slope, r12_y, mpz_n2) + fq12_t_invert(slope, slope) + fq12_t_mul(slope, res, slope) + + # v = R12.y - slope * R12.x + fq12_t_mul(res, slope, r12_x) + fq12_t_sub(res, r12_y, res) + + # res = P.y - P.x * slope - v + fq12_t_mul_fq_t(slope, slope, px) + fq_t_sub_fq12_t(res, py, res) + fq12_t_sub(res, res, slope) + + fq12_t_release(_r12_x) + fq12_t_release(_r12_y) + fq12_t_release(_slope) + + +cdef void fq2_t_add_line_eval(fq12_t res, + fq2_t rx, fq2_t ry, fq2_t qx, fq2_t qy, + fq_t px, fq_t py): + cdef mpz_ptr r12x, r12y, q12x, q12y, nq12x, nq12y, slope, tmul + cdef int _r12x, _r12y, _q12x, _q12y, _nq12x, _nq12y, _slope, _tmul + r12x = fq12_t_get(&_r12x) + r12y = fq12_t_get(&_r12y) + q12x = fq12_t_get(&_q12x) + q12y = fq12_t_get(&_q12y) + nq12x = fq12_t_get(&_nq12x) + nq12y = fq12_t_get(&_nq12y) + slope = fq12_t_get(&_slope) + tmul = fq12_t_get(&_tmul) + + #R12 = untwist(R) + #Q12 = untwist(Q) + fq2_t_untwist(r12x, r12y, rx, ry) + fq2_t_untwist(q12x, q12y, qx, qy) + + # This is the case of a vertical line, where the denominator + # will be 0. + #if R12 == Q12.negate(): + # return P.x - R12.x + fq12_t_neg(nq12x, q12x) + fq12_t_neg(nq12y, q12y) + if fq12_t_eq(r12x, nq12x) and fq12_t_eq(r12y, nq12y): + fq_t_sub_fq12_t(res, px, r12x) + fq12_t_release(_r12x) + fq12_t_release(_r12y) + fq12_t_release(_q12x) + fq12_t_release(_q12y) + fq12_t_release(_nq12x) + fq12_t_release(_nq12y) + fq12_t_release(_slope) + fq12_t_release(_tmul) + return + + # slope = (Q12.y - R12.y) / (Q12.x - R12.x) + fq12_t_sub(res, q12x, r12x) + fq12_t_invert(res, res) + fq12_t_sub(slope, q12y, r12y) + fq12_t_mul(slope, slope, res) + + # v = (Q12.y * R12.x - R12.y * Q12.x) / (R12.x - Q12.x) + fq12_t_mul(res, q12y, r12x) + fq12_t_mul(tmul, r12y, q12x) + fq12_t_sub(res, res, tmul) + fq12_t_sub(tmul, r12x, q12x) + fq12_t_invert(tmul, tmul) + fq12_t_mul(tmul, res, tmul) + + #res = P.y - P.x * slope - v + fq12_t_mul_fq_t(slope, slope, px) + fq_t_sub_fq12_t(res, py, slope) + fq12_t_sub(res, res, tmul) + + fq12_t_release(_r12x) + fq12_t_release(_r12y) + fq12_t_release(_q12x) + fq12_t_release(_q12y) + fq12_t_release(_nq12x) + fq12_t_release(_nq12y) + fq12_t_release(_slope) + fq12_t_release(_tmul) + + +cdef void fq2_t_untwist(fq12_t ropx, fq12_t ropy, fq2_t x_t, fq2_t y_t): + cdef mpz_ptr tmul + cdef int _tmul + tmul = fq_t_get(&_tmul) + #m, n = x_t + #new_x = (0, 0, 0, 0, (tw1*m - tw2*n) % Q, (tw1*n + tw2*m) % Q, + # 0, 0, 0, 0, 0, 0) + mpz_set(&ropx[0], mpz_n0) + mpz_set(&ropx[1], mpz_n0) + mpz_set(&ropx[2], mpz_n0) + mpz_set(&ropx[3], mpz_n0) + mpz_mul(&ropx[4], tw1, &x_t[0]) + mpz_mul(tmul, tw2, &x_t[1]) + mpz_sub(&ropx[4], &ropx[4], tmul) + mpz_mul(&ropx[5], tw1, &x_t[1]) + mpz_mul(tmul, tw2, &x_t[0]) + mpz_add(&ropx[5], &ropx[5], tmul) + mpz_set(&ropx[6], mpz_n0) + mpz_set(&ropx[7], mpz_n0) + mpz_set(&ropx[8], mpz_n0) + mpz_set(&ropx[9], mpz_n0) + mpz_set(&ropx[10], mpz_n0) + mpz_set(&ropx[11], mpz_n0) + + #m, n = y_t + #new_y = (0, 0, 0, 0, 0, 0, + # 0, 0, (tw1*m - tw2*n) % Q, (tw1*n + tw2*m) % Q, 0, 0) + mpz_set(&ropy[0], mpz_n0) + mpz_set(&ropy[1], mpz_n0) + mpz_set(&ropy[2], mpz_n0) + mpz_set(&ropy[3], mpz_n0) + mpz_set(&ropy[4], mpz_n0) + mpz_set(&ropy[5], mpz_n0) + mpz_set(&ropy[6], mpz_n0) + mpz_set(&ropy[7], mpz_n0) + mpz_mul(&ropy[8], tw1, &y_t[0]) + mpz_mul(tmul, tw2, &y_t[1]) + mpz_sub(&ropy[8], &ropy[8], tmul) + mpz_mul(&ropy[9], tw1, &y_t[1]) + mpz_mul(tmul, tw2, &y_t[0]) + mpz_add(&ropy[9], &ropy[9], tmul) + mpz_set(&ropy[10], mpz_n0) + mpz_set(&ropy[11], mpz_n0) + fq_t_release(_tmul) + + +cdef void fq_t_miller_loop(fq12_t res, + fq_t px, fq_t py, int pinf, + fq2_t qx, fq2_t qy, int qinf): + cdef mp_bitcnt_t bits_left, bit_n + cdef mpz_ptr rx, ry, tfq12 + cdef int _rx, _ry, _tfq12, rinf + + rx = fq2_t_get(&_rx) + ry = fq2_t_get(&_ry) + tfq12 = fq12_t_get(&_tfq12) + + fq2_t_set(rx, qx) + fq2_t_set(ry, qy) + rinf = qinf + fq12_t_set(res, fq12_t_one) + + bit_n = 0 + bits_left = mpz_popcount(NX) + while bits_left > 0: + if mpz_tstbit(NX, bit_n): + bits_left -= 1 + bit_n += 1 + + bit_n -= 1 + while bit_n > 0: + bit_n -= 1 + # Compute sloped line lrr + fq2_t_double_line_eval(tfq12, rx, ry, px, py) + fq12_t_pow(res, res, mpz_n2) + fq12_t_mul(res, res, tfq12) + # R = 2 * R + fq2_t_double_point(rx, ry, &rinf, rx, ry, &rinf) + if mpz_tstbit(NX, bit_n): + # Compute sloped line lrq + fq2_t_add_line_eval(tfq12, rx, ry, qx, qy, px, py) + fq12_t_mul(res, res, tfq12) + # R = R + Q + fq2_t_add_points(rx, ry, &rinf, rx, ry, &rinf, qx, qy, &qinf) + + fq2_t_release(_rx) + fq2_t_release(_ry) + fq12_t_release(_tfq12) + + +cdef void fq12_t_final_exp(fq12_t rop, fq12_t a_op): + cdef mpz_ptr res + cdef int _res + res = fq12_t_get(&_res) + # ans = pow(e, mpz_final_exp_e) + fq12_t_pow(res, a_op, mpz_final_exp_e) + # ans = ans.qi_power(2) * ans + fq12_t_qi_pow(rop, res, 2) + fq12_t_mul(res, rop, res) + # ans = ans.qi_power(6) / ans + fq12_t_qi_pow(rop, res, 6) + fq12_t_floordiv(rop, rop, res) + fq12_t_release(_res) + + +cdef void fq_t_ate_pairing_multi(int n, fq12_t rop, + fq_t *ps_x, fq_t *ps_y, int *ps_inf, + fq2_t *qs_x, fq2_t *qs_y, int *qs_inf): + cdef mpz_ptr ml_res + cdef int _ml_res + ml_res = fq12_t_get(&_ml_res) + + fq12_t_set(rop, fq12_t_one) + for i in range(n): + fq_t_miller_loop(ml_res, + ps_x[i], ps_y[i], ps_inf[i], + qs_x[i], qs_y[i], qs_inf[i]) + fq12_t_mul(rop, rop, ml_res) + fq12_t_final_exp(rop, rop) + + fq12_t_release(_ml_res) + + +# fq operations +def fq_invert(P, A): + cdef mpz_ptr z, a + cdef int _z, _a + a = fq_t_get(&_a) + fq_t_set_pylong(a, A) + if P == Q_int: + fq_t_invert(a, a, Q) + else: + z = fq_t_get(&_z) + fq_t_set_pylong(z, P) + fq_t_invert(a, a, z) + fq_t_release(_z) + res = fq_t_get_pylong(a) + fq_t_release(_a) + return res + + +def fq_floordiv(P, A, X): + cdef mpz_ptr z, a, x + cdef int _z, _a, _x + a = fq_t_get(&_a) + x = fq_t_get(&_x) + fq_t_set_pylong(a, A) + fq_t_set_pylong(x, X) + if P == Q_int: + fq_t_floordiv(a, a, x, Q) + else: + z = fq_t_get(&_z) + fq_t_set_pylong(z, P) + fq_t_floordiv(a, a, x, z) + fq_t_release(_z) + res = fq_t_get_pylong(a) + fq_t_release(_a) + fq_t_release(_x) + return res + + +def fq_pow(P, A, E): + cdef mpz_ptr z, a, e + cdef int _z, _a, _e + a = fq_t_get(&_a) + e = fq_t_get(&_e) + fq_t_set_pylong(a, A) + fq_t_set_pylong(e, E) + if P == Q_int: + fq_t_pow(a, a, e, Q) + else: + z = fq_t_get(&_z) + fq_t_set_pylong(z, P) + fq_t_pow(a, a, e, z) + fq_t_release(_z) + res = fq_t_get_pylong(a) + fq_t_release(_a) + fq_t_release(_e) + return res + + +# fq2 operations +def fq2_invert(t_x): + cdef mpz_ptr x + cdef int _x + x = fq2_t_get(&_x) + fq2_t_set_fq2(x, t_x) + fq2_t_invert(x, x) + res = fq2_t_get_fq2(x) + fq2_t_release(_x) + return res + + +def fq2_floordiv(t_a, t_x): + cdef mpz_ptr a, x + cdef int _a, _x + a = fq2_t_get(&_a) + x = fq2_t_get(&_x) + fq2_t_set_fq2(a, t_a) + fq2_t_set_fq2(x, t_x) + fq2_t_floordiv(a, a, x) + res = fq2_t_get_fq2(a) + fq2_t_release(_a) + fq2_t_release(_x) + return res + + +def fq2_qi_pow(t_x, i): + cdef mpz_ptr x + cdef int _x + i %= 2 + if i == 0: + return t_x + x = fq2_t_get(&_x) + fq2_t_set_fq2(x, t_x) + fq2_t_qi_pow(x, x, i) + res = fq2_t_get_fq2(x) + fq2_t_release(_x) + return res + + +def fq2_pow(t_a, E): + cdef mpz_ptr a, e + cdef int _e, _a + a = fq2_t_get(&_a) + e = fq_t_get(&_e) + fq2_t_set_fq2(a, t_a) + fq_t_set_pylong(e, E) + fq2_t_pow(a, a, e) + res = fq2_t_get_fq2(a) + fq2_t_release(_a) + fq_t_release(_e) + return res + + +def fq2_add(t_a, t_m): + cdef mpz_ptr a, b + cdef int _a, _b + a = fq2_t_get(&_a) + b = fq2_t_get(&_b) + fq2_t_set_fq2(a, t_a) + fq2_t_set_fq2(b, t_m) + fq2_t_add(a, a, b) + res = fq2_t_get_fq2(a) + fq2_t_release(_a) + fq2_t_release(_b) + return res + + +def fq2_mul(t_a, t_m): + cdef mpz_ptr a, b + cdef int _a, _b + a = fq2_t_get(&_a) + b = fq2_t_get(&_b) + fq2_t_set_fq2(a, t_a) + fq2_t_set_fq2(b, t_m) + fq2_t_mul(a, a, b) + res = fq2_t_get_fq2(a) + fq2_t_release(_a) + fq2_t_release(_b) + return res + + +# fq6 operations +def fq6_invert(t_x): + cdef mpz_ptr x + cdef int _x + x = fq6_t_get(&_x) + fq6_t_set_fq6(x, t_x) + fq6_t_invert(x, x) + res = fq6_t_get_fq6(x) + fq6_t_release(_x) + return res + + +def fq6_floordiv(t_a, t_x): + cdef mpz_ptr a, x + cdef int _a, _x + a = fq6_t_get(&_a) + x = fq6_t_get(&_x) + fq6_t_set_fq6(a, t_a) + fq6_t_set_fq6(x, t_x) + fq6_t_floordiv(a, a, x) + res = fq6_t_get_fq6(a) + fq6_t_release(_a) + fq6_t_release(_x) + return res + + +def fq6_qi_pow(t_x, i): + cdef mpz_ptr x + cdef int _x + i %= 6 + if i == 0: + return t_x + x = fq6_t_get(&_x) + fq6_t_set_fq6(x, t_x) + fq6_t_qi_pow(x, x, i) + res = fq6_t_get_fq6(x) + fq6_t_release(_x) + return res + + +def fq6_add(t_a, t_m): + cdef mpz_ptr a, b + cdef int _a, _b + a = fq6_t_get(&_a) + b = fq6_t_get(&_b) + fq6_t_set_fq6(a, t_a) + fq6_t_set_fq6(b, t_m) + fq6_t_add(a, a, b) + res = fq6_t_get_fq6(a) + fq6_t_release(_a) + fq6_t_release(_b) + return res + + +def fq6_mul(t_a, t_m): + cdef mpz_ptr a, b + cdef int _a, _b + a = fq6_t_get(&_a) + b = fq6_t_get(&_b) + fq6_t_set_fq6(a, t_a) + fq6_t_set_fq6(b, t_m) + fq6_t_mul(a, a, b) + res = fq6_t_get_fq6(a) + fq6_t_release(_a) + fq6_t_release(_b) + return res + + +# fq12 operations +def fq12_invert(t_x): + cdef mpz_ptr x + cdef int _x + x = fq12_t_get(&_x) + fq12_t_set_fq12(x, t_x) + fq12_t_invert(x, x) + res = fq12_t_get_fq12(x) + fq12_t_release(_x) + return res + + +def fq12_floordiv(t_a, t_x): + cdef mpz_ptr a, x + cdef int _a, _x + a = fq12_t_get(&_a) + x = fq12_t_get(&_x) + fq12_t_set_fq12(a, t_a) + fq12_t_set_fq12(x, t_x) + fq12_t_floordiv(a, a, x) + res = fq12_t_get_fq12(a) + fq12_t_release(_a) + fq12_t_release(_x) + return res + + +def fq12_qi_pow(t_x, i): + cdef mpz_ptr x + cdef int _x + i %= 12 + if i == 0: + return t_x + x = fq12_t_get(&_x) + fq12_t_set_fq12(x, t_x) + fq12_t_qi_pow(x, x, i) + res = fq12_t_get_fq12(x) + fq12_t_release(_x) + return res + + +def fq12_pow(t_a, E): + cdef mpz_ptr a, e + cdef int _a, _e + a = fq12_t_get(&_a) + e = fq_t_get(&_e) + fq12_t_set_fq12(a, t_a) + fq_t_set_pylong(e, E) + fq12_t_pow(a, a, e) + res = fq12_t_get_fq12(a) + fq12_t_release(_a) + fq_t_release(_e) + return res + + +def fq12_mul_fq(t_a, t_m): + cdef mpz_ptr a, m + cdef int _a, _m + a = fq12_t_get(&_a) + m = fq_t_get(&_m) + fq12_t_set_fq12(a, t_a) + fq_t_set_pylong(m, t_m) + fq12_t_mul_fq_t(a, a, m) + res = fq12_t_get_fq12(a) + fq12_t_release(_a) + fq_t_release(_m) + return res + + +def fq12_add(t_a, t_m): + cdef mpz_ptr a, m + cdef int _a, _m + a = fq12_t_get(&_a) + m = fq12_t_get(&_m) + fq12_t_set_fq12(a, t_a) + fq12_t_set_fq12(m, t_m) + fq12_t_add(a, a, m) + res = fq12_t_get_fq12(a) + fq12_t_release(_a) + fq12_t_release(_m) + return res + + +def fq12_mul(t_a, t_m): + cdef mpz_ptr a, m + cdef int _a, _m + a = fq12_t_get(&_a) + m = fq12_t_get(&_m) + fq12_t_set_fq12(a, t_a) + fq12_t_set_fq12(m, t_m) + fq12_t_mul(a, a, m) + res = fq12_t_get_fq12(a) + fq12_t_release(_a) + fq12_t_release(_m) + return res + + +# ec.py, paring.py calc operations +def fq2_to_affine(X, Y, Z, INF): + cdef mpz_ptr x, y, z + cdef int _x, _y, _z, inf + x = fq2_t_get(&_x) + y = fq2_t_get(&_y) + z = fq2_t_get(&_z) + fq2_t_set_fq2(x, X) + fq2_t_set_fq2(y, Y) + fq2_t_set_fq2(z, Z) + inf = 1 if INF else 0 + + fq2_t_to_affine(x, y, &inf, x, y, z, inf) + + rx = fq2_t_get_fq2(x) + ry = fq2_t_get_fq2(y) + rinf = True if inf else False + + fq2_t_release(_x) + fq2_t_release(_y) + fq2_t_release(_z) + return rx, ry, rinf + + +def fq2_double_point(X, Y, INF): + cdef mpz_ptr x, y + cdef int _x, _y, inf + x = fq2_t_get(&_x) + y = fq2_t_get(&_y) + fq2_t_set_fq2(x, X) + fq2_t_set_fq2(y, Y) + inf = 1 if INF else 0 + + fq2_t_double_point(x, y, &inf, x, y, &inf) + xr = fq2_t_get_fq2(x) + yr = fq2_t_get_fq2(y) + infr = True if inf else False + + fq2_t_release(_x) + fq2_t_release(_y) + return xr, yr, infr + + +def fq2_add_points(X1, Y1, INF1, X2, Y2, INF2): + cdef mpz_ptr x1, y1, x2, y2 + cdef int _x1, _y1, _x2, _y2, inf1, inf2 + x1 = fq2_t_get(&_x1) + y1 = fq2_t_get(&_y1) + x2 = fq2_t_get(&_x2) + y2 = fq2_t_get(&_y2) + fq2_t_set_fq2(x1, X1) + fq2_t_set_fq2(y1, Y1) + inf1 = 1 if INF1 else 0 + fq2_t_set_fq2(x2, X2) + fq2_t_set_fq2(y2, Y2) + inf2 = 1 if INF2 else 0 + + fq2_t_add_points(x1, y1, &inf1, x1, y1, &inf1, x2, y2, &inf2) + xr = fq2_t_get_fq2(x1) + yr = fq2_t_get_fq2(y1) + infr = True if inf1 else False + + fq2_t_release(_x1) + fq2_t_release(_y1) + fq2_t_release(_x2) + fq2_t_release(_y2) + return xr, yr, infr + + +def fq_double_point_jacobian(X, Y, Z): + cdef mpz_ptr x, y, z + cdef int _x, _y, _z + x = fq_t_get(&_x) + y = fq_t_get(&_y) + z = fq_t_get(&_z) + + fq_t_set_pylong(x, X) + fq_t_set_pylong(y, Y) + fq_t_set_pylong(z, Z) + + fq_t_double_point_jacobian(x, y, z, x, y, z) + xr = fq_t_get_pylong(x) + yr = fq_t_get_pylong(y) + zr = fq_t_get_pylong(z) + + fq_t_release(_x) + fq_t_release(_y) + fq_t_release(_z) + return xr, yr, zr + + +def fq2_double_point_jacobian(X, Y, Z): + cdef mpz_ptr x, y, z + cdef int _x, _y, _z + x = fq2_t_get(&_x) + y = fq2_t_get(&_y) + z = fq2_t_get(&_z) + + fq2_t_set_fq2(x, X) + fq2_t_set_fq2(y, Y) + fq2_t_set_fq2(z, Z) + + fq2_t_double_point_jacobian(x, y, z, x, y, z) + xr = fq2_t_get_fq2(x) + yr = fq2_t_get_fq2(y) + zr = fq2_t_get_fq2(z) + + fq2_t_release(_x) + fq2_t_release(_y) + fq2_t_release(_z) + return xr, yr, zr + + +def fq12_double_point_jacobian(X, Y, Z): + cdef mpz_ptr x, y, z + cdef int _x, _y, _z + x = fq12_t_get(&_x) + y = fq12_t_get(&_y) + z = fq12_t_get(&_z) + + fq12_t_set_fq12(x, X) + fq12_t_set_fq12(y, Y) + fq12_t_set_fq12(z, Z) + + fq12_t_double_point_jacobian(x, y, z, x, y, z) + xr = fq12_t_get_fq12(x) + yr = fq12_t_get_fq12(y) + zr = fq12_t_get_fq12(z) + + fq12_t_release(_x) + fq12_t_release(_y) + fq12_t_release(_z) + return xr, yr, zr + + +def fq_add_points_jacobian(X1, Y1, Z1, INF1, X2, Y2, Z2, INF2): + cdef mpz_ptr x1, y1, z1, x2, y2, z2 + cdef int _x1, _y1, _z1, _x2, _y2, _z2 + cdef int inf1, inf2 + inf1 = 1 if INF1 else 0 + inf2 = 1 if INF2 else 0 + if inf1: + return X2, Y2, Z2, INF2 + if inf2: + return X1, Y1, Z1, INF1 + x1 = fq_t_get(&_x1) + y1 = fq_t_get(&_y1) + z1 = fq_t_get(&_z1) + x2 = fq_t_get(&_x2) + y2 = fq_t_get(&_y2) + z2 = fq_t_get(&_z2) + + fq_t_set_pylong(x1, X1) + fq_t_set_pylong(y1, Y1) + fq_t_set_pylong(z1, Z1) + fq_t_set_pylong(x2, X2) + fq_t_set_pylong(y2, Y2) + fq_t_set_pylong(z2, Z2) + + fq_t_add_points_jacobian(x1, y1, z1, &inf1, + x1, y1, z1, &inf1, x2, y2, z2, &inf2) + xr = fq_t_get_pylong(x1) + yr = fq_t_get_pylong(y1) + zr = fq_t_get_pylong(z1) + infr = True if inf1 else False + + fq_t_release(_x1) + fq_t_release(_y1) + fq_t_release(_z1) + fq_t_release(_x2) + fq_t_release(_y2) + fq_t_release(_z2) + return xr, yr, zr, infr + + +def fq2_add_points_jacobian(X1, Y1, Z1, INF1, X2, Y2, Z2, INF2): + cdef mpz_ptr x1, y1, z1, x2, y2, z2 + cdef int _x1, _y1, _z1, _x2, _y2, _z2 + cdef int inf1, inf2 + inf1 = 1 if INF1 else 0 + inf2 = 1 if INF2 else 0 + if inf1: + return X2, Y2, Z2, INF2 + if inf2: + return X1, Y1, Z1, INF1 + x1 = fq2_t_get(&_x1) + y1 = fq2_t_get(&_y1) + z1 = fq2_t_get(&_z1) + x2 = fq2_t_get(&_x2) + y2 = fq2_t_get(&_y2) + z2 = fq2_t_get(&_z2) + + fq2_t_set_fq2(x1, X1) + fq2_t_set_fq2(y1, Y1) + fq2_t_set_fq2(z1, Z1) + fq2_t_set_fq2(x2, X2) + fq2_t_set_fq2(y2, Y2) + fq2_t_set_fq2(z2, Z2) + + fq2_t_add_points_jacobian(x1, y1, z1, &inf1, + x1, y1, z1, &inf1, x2, y2, z2, &inf2) + xr = fq2_t_get_fq2(x1) + yr = fq2_t_get_fq2(y1) + zr = fq2_t_get_fq2(z1) + infr = True if inf1 else False + + fq2_t_release(_x1) + fq2_t_release(_y1) + fq2_t_release(_z1) + fq2_t_release(_x2) + fq2_t_release(_y2) + fq2_t_release(_z2) + return xr, yr, zr, infr + + +def fq12_add_points_jacobian(X1, Y1, Z1, INF1, X2, Y2, Z2, INF2): + cdef mpz_ptr x1, y1, z1, x2, y2, z2 + cdef int _x1, _y1, _z1, _x2, _y2, _z2 + cdef int inf1, inf2 + inf1 = 1 if INF1 else 0 + inf2 = 1 if INF2 else 0 + if inf1: + return X2, Y2, Z2, INF2 + if inf2: + return X1, Y1, Z1, INF1 + x1 = fq12_t_get(&_x1) + y1 = fq12_t_get(&_y1) + z1 = fq12_t_get(&_z1) + x2 = fq12_t_get(&_x2) + y2 = fq12_t_get(&_y2) + z2 = fq12_t_get(&_z2) + + fq12_t_set_fq12(x1, X1) + fq12_t_set_fq12(y1, Y1) + fq12_t_set_fq12(z1, Z1) + fq12_t_set_fq12(x2, X2) + fq12_t_set_fq12(y2, Y2) + fq12_t_set_fq12(z2, Z2) + + fq12_t_add_points_jacobian(x1, y1, z1, &inf1, + x1, y1, z1, &inf1, x2, y2, z2, &inf2) + xr = fq12_t_get_fq12(x1) + yr = fq12_t_get_fq12(y1) + zr = fq12_t_get_fq12(z1) + infr = True if inf1 else False + + fq12_t_release(_x1) + fq12_t_release(_y1) + fq12_t_release(_z1) + fq12_t_release(_x2) + fq12_t_release(_y2) + fq12_t_release(_z2) + return xr, yr, zr, infr + + +def fq2_scalar_mult_jacobian(C, X, Y, Z, INF): + cdef mpz_ptr c, x, y, z + cdef int _c, _x, _y, _z, inf + c = fq_t_get(&_c) + x = fq2_t_get(&_x) + y = fq2_t_get(&_y) + z = fq2_t_get(&_z) + fq_t_set_pylong(c, C) + fq2_t_set_fq2(x, X) + fq2_t_set_fq2(y, Y) + fq2_t_set_fq2(z, Z) + inf = 1 if INF else 0 + + fq2_t_scalar_mult_jacobian(x, y, z, &inf, c, x, y, z, &inf) + xr = fq2_t_get_fq2(x) + yr = fq2_t_get_fq2(y) + zr = fq2_t_get_fq2(z) + infr = True if inf else False + + fq_t_release(_c) + fq2_t_release(_x) + fq2_t_release(_y) + fq2_t_release(_z) + return xr, yr, zr, infr + + +def fq2_double_line_eval(RX, RY, PX, PY): + cdef mpz_ptr rx, ry, px, py, rop + cdef int _rx, _ry, _px, _py, _rop + rx = fq2_t_get(&_rx) + ry = fq2_t_get(&_ry) + px = fq_t_get(&_px) + py = fq_t_get(&_py) + rop = fq12_t_get(&_rop) + + fq2_t_set_fq2(rx, RX) + fq2_t_set_fq2(ry, RY) + fq_t_set_pylong(px, PX) + fq_t_set_pylong(py, PY) + fq2_t_double_line_eval(rop, rx, ry, px, py) + res = fq12_t_get_fq12(rop) + + fq2_t_release(_rx) + fq2_t_release(_ry) + fq_t_release(_px) + fq_t_release(_py) + fq12_t_release(_rop) + return res + + +def fq2_add_line_eval(RX, RY, QX, QY, PX, PY): + cdef mpz_ptr rx, ry, qx, qy, px, py, rop + cdef int _rx, _ry, _qx, _qy, _px, _py, _rop + rx = fq2_t_get(&_rx) + ry = fq2_t_get(&_ry) + qx = fq2_t_get(&_qx) + qy = fq2_t_get(&_qy) + px = fq_t_get(&_px) + py = fq_t_get(&_py) + rop = fq12_t_get(&_rop) + + fq2_t_set_fq2(rx, RX) + fq2_t_set_fq2(ry, RY) + fq2_t_set_fq2(qx, QX) + fq2_t_set_fq2(qy, QY) + fq_t_set_pylong(px, PX) + fq_t_set_pylong(py, PY) + fq2_t_add_line_eval(rop, rx, ry, qx, qy, px, py) + res = fq12_t_get_fq12(rop) + + fq2_t_release(_rx) + fq2_t_release(_ry) + fq2_t_release(_qx) + fq2_t_release(_qy) + fq_t_release(_px) + fq_t_release(_py) + fq12_t_release(_rop) + return res + + +def fq2_untwist(X, Y): + cdef mpz_ptr x, y, ropx, ropy + cdef int _x, _y, _ropx, _ropy + x = fq2_t_get(&_x) + y = fq2_t_get(&_y) + ropx = fq12_t_get(&_ropx) + ropy = fq12_t_get(&_ropy) + fq2_t_set_fq2(x, X) + fq2_t_set_fq2(y, Y) + fq2_t_untwist(ropx, ropy, x, y) + resx = fq12_t_get_fq12(ropx) + resy = fq12_t_get_fq12(ropy) + fq2_t_release(_x) + fq2_t_release(_y) + fq12_t_release(_ropx) + fq12_t_release(_ropy) + return resx, resy + + +def fq_miller_loop(PX, PY, PINF, QX, QY, QINF): + cdef mpz_ptr px, py, qx, qy, rop + cdef int _px, _py, _qx, _qy, _rop, pinf, qinf + px = fq_t_get(&_px) + py = fq_t_get(&_py) + qx = fq2_t_get(&_qx) + qy = fq2_t_get(&_qy) + rop = fq12_t_get(&_rop) + + fq_t_set_pylong(px, PX) + fq_t_set_pylong(py, PY) + pinf = 1 if PINF else 0 + fq2_t_set_fq2(qx, QX) + fq2_t_set_fq2(qy, QY) + qinf = 1 if QINF else 0 + + fq_t_miller_loop(rop, px, py, pinf, qx, qy, qinf) + res = fq12_t_get_fq12(rop) + + fq_t_release(_px) + fq_t_release(_py) + fq2_t_release(_qx) + fq2_t_release(_qy) + fq12_t_release(_rop) + return res + + +def fq12_final_exp(t_x): + cdef mpz_ptr e + cdef int _e + e = fq12_t_get(&_e) + fq12_t_set_fq12(e, t_x) + fq12_t_final_exp(e, e) + res = fq12_t_get_fq12(e) + fq12_t_release(_e) + return res + + +def fq_ate_pairing_multi(Ps, Qs): + cdef int n + cdef fq_t *ps_x + cdef fq_t *ps_y + cdef int *ps_inf + cdef fq2_t *qs_x + cdef fq2_t *qs_y + cdef int *qs_inf + + cdef mpz_ptr prod + cdef int _prod + prod = fq12_t_get(&_prod) + + n = len(Qs) + + ps_x = malloc(n * sizeof(fq_t)) + ps_y = malloc(n * sizeof(fq_t)) + ps_inf = malloc(n * sizeof(int)) + + qs_x = malloc(n * sizeof(fq2_t)) + qs_y = malloc(n * sizeof(fq2_t)) + qs_inf = malloc(n * sizeof(int)) + + for i in range(n): + fq_t_init(ps_x[i]) + fq_t_init(ps_y[i]) + fq2_t_init(qs_x[i]) + fq2_t_init(qs_y[i]) + + mpz_set_pylong(ps_x[i], Ps[i][0]) + mpz_set_pylong(ps_y[i], Ps[i][1]) + ps_inf[i] = 1 if Ps[i][2] else 0 + + fq2_t_set_fq2(qs_x[i], Qs[i][0]) + fq2_t_set_fq2(qs_y[i], Qs[i][1]) + qs_inf[i] = 1 if Qs[i][2] else 0 + + fq_t_ate_pairing_multi(n, prod, + ps_x, ps_y, ps_inf, + qs_x, qs_y, qs_inf) + res = fq12_t_get_fq12(prod) + + for i in range(n): + mpz_clear(ps_x[i]) + mpz_clear(ps_y[i]) + mpz_clear(&qs_x[i][0]) + mpz_clear(&qs_x[i][1]) + mpz_clear(&qs_y[i][0]) + mpz_clear(&qs_y[i][1]) + + free(ps_x) + free(ps_y) + free(ps_inf) + free(qs_x) + free(qs_y) + free(qs_inf) + + fq12_t_release(_prod) + return res + + +# fq queues vars and classes +DEF Q_BLOCK_SIZE = 100 +DEF Q2_BLOCK_SIZE = 100 +DEF Q6_BLOCK_SIZE = 100 +DEF Q12_BLOCK_SIZE = 100 + + +cdef fq_t fq_q[Q_BLOCK_SIZE] +cdef int fq_qi[Q_BLOCK_SIZE] +cdef int fq_qt # tail +cdef fq2_t fq2_q[Q2_BLOCK_SIZE] +cdef int fq2_qi[Q2_BLOCK_SIZE] +cdef int fq2_qt # tail +cdef fq6_t fq6_q[Q6_BLOCK_SIZE] +cdef int fq6_qi[Q6_BLOCK_SIZE] +cdef int fq6_qt # tail +cdef fq12_t fq12_q[Q12_BLOCK_SIZE] +cdef int fq12_qi[Q12_BLOCK_SIZE] +cdef int fq12_qt + + +cdef mpz_ptr fq_t_get(int *pi): + global fq_qt + cdef mpz_ptr p + if fq_qt <= 0: + pi[0] = -1 + raise Exception('fq_q queue empty') + pi[0] = fq_qi[fq_qt] + p = fq_q[fq_qt] + fq_qt -= 1 + return p + + +cdef void fq_t_release(int x): + global fq_qt + if x >= 0: + fq_qt += 1 + fq_qi[fq_qt] = x + + +cdef void fq_t_alloc(): + global fq_qt + cdef int i + for i in range(Q_BLOCK_SIZE): + fq_qt = i + fq_qi[i] = i + fq_t_init(fq_q[i]) + + +cdef mpz_ptr fq2_t_get(int *pi): + global fq2_qt + cdef mpz_ptr p + if fq2_qt <= 0: + pi[0] = -1 + raise Exception('fq2_q queue empty') + pi[0] = fq2_qi[fq2_qt] + p = fq2_q[fq2_qt] + fq2_qt -= 1 + return p + + +cdef void fq2_t_release(int x): + global fq2_qt + if x >= 0: + fq2_qt += 1 + fq2_qi[fq2_qt] = x + + +cdef void fq2_t_alloc(): + global fq2_qt + cdef int i + for i in range(Q2_BLOCK_SIZE): + fq2_qt = i + fq2_qi[i] = i + fq2_t_init(fq2_q[i]) + + +cdef mpz_ptr fq6_t_get(int *pi): + global fq6_qt + cdef mpz_ptr p + if fq6_qt <= 0: + pi[0] = -1 + raise Exception('fq6_q queue empty') + pi[0] = fq6_qi[fq6_qt] + p = fq6_q[fq6_qt] + fq6_qt -= 1 + return p + + +cdef void fq6_t_release(int x): + global fq6_qt + if x >= 0: + fq6_qt += 1 + fq6_qi[fq6_qt] = x + + +cdef void fq6_t_alloc(): + global fq6_qt + cdef int i + for i in range(Q6_BLOCK_SIZE): + fq6_qt = i + fq6_qi[i] = i + fq6_t_init(fq6_q[i]) + + +cdef mpz_ptr fq12_t_get(int *pi): + global fq12_qt + cdef mpz_ptr p + if fq12_qt <= 0: + pi[0] = -1 + raise Exception('fq12_q queue empty') + pi[0] = fq12_qi[fq12_qt] + p = fq12_q[fq12_qt] + fq12_qt -= 1 + return p + + +cdef void fq12_t_release(int x): + global fq12_qt + if x >= 0: + fq12_qt += 1 + fq12_qi[fq12_qt] = x + + +cdef void fq12_t_alloc(): + global fq12_qt + cdef int i + for i in range(Q12_BLOCK_SIZE): + fq12_qt = i + fq12_qi[i] = i + fq12_t_init(fq12_q[i]) + + +# module init +def fq_queues_init(): + fq_t_alloc() + fq2_t_alloc() + fq6_t_alloc() + fq12_t_alloc() + + +def params_init(): + global Q_int + Q_int = int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b' + '84f38512bf6730d2a0f6b0f6241eabfffeb153ff' + 'ffb9feffffffffaaab', 16) + mpz_init2(Q, INIT_BITS) + mpz_set_pylong(Q, Q_int) + mpz_init2(B, INIT_BITS) + mpz_set_pylong(B, 0x4) + mpz_init2(N, INIT_BITS) + mpz_set_pylong(N, int('0x73eda753299d7d483339d80809a1d80553bda4' + '02fffe5bfeffffffff00000001', 16)) + mpz_init2(NX, INIT_BITS) + mpz_set_pylong(NX, 0xd201000000010000) + + # twist/untwist inverse constants + mpz_init2(tw1, INIT_BITS) + mpz_set_pylong(tw1, int('0xd0088f51cbff34d258dd3db21a5d66' + 'bb23ba5c279c2895fb39869507b587b1' + '20f55ffff58a9ffffdcff7fffffffd556', 16)) + mpz_init2(tw2, INIT_BITS) + mpz_set_pylong(tw2, int('0xd0088f51cbff34d258dd3db21a5d66' + 'bb23ba5c279c2895fb39869507b587b1' + '20f55ffff58a9ffffdcff7fffffffd555', 16)) + + fq_t_init_set_pylong(fq_t_zero, 0) + fq_t_init_set_pylong(fq_t_one, 1) + fq_t_init_set_pylong_mod(fq2_t_root, Q, -1) + fq2_t_init_set_fq_t(fq2_t_zero, fq_t_zero) + fq2_t_init_set_fq_t(fq2_t_one, fq_t_one) + fq2_t_init_set_fq2(fq6_t_root, (1, 1)) + fq6_t_init_set_fq_t(fq6_t_zero, fq_t_zero) + fq6_t_init_set_fq_t(fq6_t_one, fq_t_one) + fq6_t_init_set_fq6(fq12_t_root, (0, 0, 1, 0, 0, 0)) + fq12_t_init_set_fq_t(fq12_t_zero, fq_t_zero) + fq12_t_init_set_fq_t(fq12_t_one, fq_t_one) + + fq_t_init(mpz_final_exp_e) + mpz_pow_ui(mpz_final_exp_e, Q, 4) + fq_t_init(mpz_n2) + mpz_pow_ui(mpz_n2, Q, 2) + mpz_sub(mpz_final_exp_e, mpz_final_exp_e, mpz_n2) + mpz_add_ui(mpz_final_exp_e, mpz_final_exp_e, 1) + mpz_fdiv_q(mpz_final_exp_e, mpz_final_exp_e, N) + + fq_t_set_pylong(mpz_n2, 2) + fq_t_init_set_pylong(mpz_n0, 0) + fq_t_init_set_pylong(mpz_n3, 3) + fq_t_init_set_pylong(mpz_n4, 4) + fq_t_init_set_pylong(mpz_n8, 8) + + +def frob_coeffs_init(): + fq2_t_init_set_fq2(fc_6[0][0], + (0, + int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaac', 16))) + fq2_t_init_set_fq2(fc_6[0][1], + (int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaad', 16), 0)) + fq2_t_init_set_fq2(fc_6[1][0], + (int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'fe', 16), 0)) + fq2_t_init_set_fq2(fc_6[1][1], + (int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaac', 16), 0)) + fq2_t_init_set_fq2(fc_6[2][0], (0, 1)) + fq2_t_init_set_fq2(fc_6[2][1], + (int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b' + '84f38512bf6730d2a0f6b0f6241eabfffeb153ff' + 'ffb9feffffffffaaaa', 16), 0)) + fq2_t_init_set_fq2(fc_6[3][0], + (int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaac', 16), 0)) + fq2_t_init_set_fq2(fc_6[3][1], + (int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'fe', 16), 0)) + fq2_t_init_set_fq2(fc_6[4][0], + (0, + int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'fe', 16))) + fq2_t_init_set_fq2(fc_6[4][1], + (int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'ff', 16), 0)) + + + fq6_t_init_set_fq6(fc_12[0], + (int('0x1904d3bf02bb0667c231beb4202c0d1f0fd603' + 'fd3cbd5f4f7b2443d784bab9c4f67ea53d63e781' + '3d8d0775ed92235fb8', 16), + int('0xfc3e2b36c4e03288e9e902231f9fb854a14787' + 'b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec2' + '2cf78a126ddc4af3', 16), 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[1], + (int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'ff', 16), 0, 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[2], + (int('0x135203e60180a68ee2e9c448d77a2cd91c3ded' + 'd930b1cf60ef396489f61eb45e304466cf3e67fa' + '0af1ee7b04121bdea2', 16), + int('0x6af0e0437ff400b6831e36d6bd17ffe48395da' + 'bc2d3435e77f76e17009241c5ee67992f72ec05f' + '4c81084fbede3cc09', 16), 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[3], + (int('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a9' + '3be6f89688de17d813620a00022e01fffffffeff' + 'fe', 16), 0, 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[4], + (int('0x144e4211384586c16bd3ad4afa99cc9170df35' + '60e77982d0db45f3536814f0bd5871c1908bd478' + 'cd1ee605167ff82995', 16), + int('0x5b2cfd9013a5fd8df47fa6b48b1e045f398162' + '40c0b8fee8beadf4d8e9c0566c63a3e6e257f873' + '29b18fae980078116', 16), 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[5], + (int('0x1a0111ea397fe69a4b1ba7b6434bacd764774b' + '84f38512bf6730d2a0f6b0f6241eabfffeb153ff' + 'ffb9feffffffffaaaa', 16), 0, 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[6], + (int('0xfc3e2b36c4e03288e9e902231f9fb854a14787' + 'b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec2' + '2cf78a126ddc4af3', 16), + int('0x1904d3bf02bb0667c231beb4202c0d1f0fd603' + 'fd3cbd5f4f7b2443d784bab9c4f67ea53d63e781' + '3d8d0775ed92235fb8', 16), 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[7], + (int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaac', 16), 0, 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[8], + (int('0x6af0e0437ff400b6831e36d6bd17ffe48395da' + 'bc2d3435e77f76e17009241c5ee67992f72ec05f' + '4c81084fbede3cc09', 16), + int('0x135203e60180a68ee2e9c448d77a2cd91c3ded' + 'd930b1cf60ef396489f61eb45e304466cf3e67fa' + '0af1ee7b04121bdea2', 16), 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[9], + (int('0x1a0111ea397fe699ec02408663d4de85aa0d85' + '7d89759ad4897d29650fb85f9b409427eb4f49ff' + 'fd8bfd00000000aaad', 16), 0, 0, 0, 0, 0)) + fq6_t_init_set_fq6(fc_12[10], + (int('0x5b2cfd9013a5fd8df47fa6b48b1e045f398162' + '40c0b8fee8beadf4d8e9c0566c63a3e6e257f873' + '29b18fae980078116', 16), + int('0x144e4211384586c16bd3ad4afa99cc9170df35' + '60e77982d0db45f3536814f0bd5871c1908bd478' + 'cd1ee605167ff82995', 16), 0, 0, 0, 0)) + + +def module_init(): + fq_queues_init() + params_init() + frob_coeffs_init() + + +module_init() diff --git a/extmod/bls_py/mpz.pxd b/extmod/bls_py/mpz.pxd new file mode 100644 index 0000000..a70f6da --- /dev/null +++ b/extmod/bls_py/mpz.pxd @@ -0,0 +1,195 @@ +# cython: language_level=3 +# -*- coding: utf-8 -*- + +from libc.stdio cimport FILE +from libc.stdint cimport intmax_t, uintmax_t + +from .types cimport * + + +cdef extern from "gmp.h": + + ### Integer Functions ### + + # Initialization Functions + void mpz_init (mpz_t integer) + void mpz_init2 (mpz_t integer, unsigned long n) + void mpz_clear (mpz_t integer) + void mpz_realloc2 (mpz_t integer, unsigned long n) + void mpz_inits (mpz_t x , ...) + void mpz_clears (mpz_t x , ...) + + # Assignment Functions + void mpz_set (mpz_t rop, mpz_t op) + void mpz_set_ui (mpz_t rop, unsigned long int op) + void mpz_set_si (mpz_t rop, signed long int op) + void mpz_set_ux (mpz_t rop, uintmax_t op) + void mpz_set_sx (mpz_t rop, intmax_t op) + void mpz_set_d (mpz_t rop, double op) + int mpz_set_str (mpz_t rop, char *str, int base) + void mpz_swap (mpz_t rop1, mpz_t rop2) + + # Combined Initialization and Assignment Functions + void mpz_init_set (mpz_t rop, mpz_t op) + void mpz_init_set_ui (mpz_t rop, unsigned long int op) + void mpz_init_set_si (mpz_t rop, signed long int op) + void mpz_init_set_ux (mpz_t rop, uintmax_t op) + void mpz_init_set_sx (mpz_t rop, intmax_t op) + void mpz_init_set_d (mpz_t rop, double op) + int mpz_init_set_str (mpz_t rop, char *str, int base) + + # Conversion Functions + unsigned long int mpz_get_ui (mpz_t op) + signed long int mpz_get_si (mpz_t op) + uintmax_t mpz_get_ux (mpz_t op) + intmax_t mpz_get_sx (mpz_t op) + double mpz_get_d (mpz_t op) + double mpz_get_d_2exp (long int *exp, mpz_t op) + char * mpz_get_str (char *str, int base, mpz_t op) + + # Arithmetic Functions + void mpz_add (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_add_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_sub (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_sub_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_ui_sub (mpz_t rop, unsigned long int op1, mpz_t op2) + void mpz_mul (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_mul_si (mpz_t rop, mpz_t op1, long int op2) + void mpz_mul_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_addmul (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_addmul_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_submul (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_submul_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_mul_2exp (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_neg (mpz_t rop, mpz_t op) + void mpz_abs (mpz_t rop, mpz_t op) + + # Division Functions + void mpz_cdiv_q (mpz_t q, mpz_t n, mpz_t d) + void mpz_cdiv_r (mpz_t r, mpz_t n, mpz_t d) + void mpz_cdiv_qr (mpz_t q, mpz_t r, mpz_t n, mpz_t d) + unsigned long int mpz_cdiv_q_ui (mpz_t q, mpz_t n, unsigned long int d) + unsigned long int mpz_cdiv_r_ui (mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_cdiv_qr_ui (mpz_t q, mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_cdiv_ui (mpz_t n, unsigned long int d) + void mpz_cdiv_q_2exp (mpz_t q, mpz_t n, unsigned long int b) + void mpz_cdiv_r_2exp (mpz_t r, mpz_t n, unsigned long int b) + void mpz_fdiv_q (mpz_t q, mpz_t n, mpz_t d) + void mpz_fdiv_r (mpz_t r, mpz_t n, mpz_t d) + void mpz_fdiv_qr (mpz_t q, mpz_t r, mpz_t n, mpz_t d) + unsigned long int mpz_fdiv_q_ui (mpz_t q, mpz_t n, unsigned long int d) + unsigned long int mpz_fdiv_r_ui (mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_fdiv_qr_ui (mpz_t q, mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_fdiv_ui (mpz_t n, unsigned long int d) + void mpz_fdiv_q_2exp (mpz_t q, mpz_t n, unsigned long int b) + void mpz_fdiv_r_2exp (mpz_t r, mpz_t n, unsigned long int b) + void mpz_tdiv_q (mpz_t q, mpz_t n, mpz_t d) + void mpz_tdiv_r (mpz_t r, mpz_t n, mpz_t d) + void mpz_tdiv_qr (mpz_t q, mpz_t r, mpz_t n, mpz_t d) + unsigned long int mpz_tdiv_q_ui (mpz_t q, mpz_t n, unsigned long int d) + unsigned long int mpz_tdiv_r_ui (mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_tdiv_qr_ui (mpz_t q, mpz_t r, mpz_t n, unsigned long int d) + unsigned long int mpz_tdiv_ui (mpz_t n, unsigned long int d) + void mpz_tdiv_q_2exp (mpz_t q, mpz_t n, unsigned long int b) + void mpz_tdiv_r_2exp (mpz_t r, mpz_t n, unsigned long int b) + void mpz_mod (mpz_t r, mpz_t n, mpz_t d) + unsigned long int mpz_mod_ui (mpz_t r, mpz_t n, unsigned long int d) + void mpz_divexact (mpz_t q, mpz_t n, mpz_t d) + void mpz_divexact_ui (mpz_t q, mpz_t n, unsigned long d) + bint mpz_divisible_p (mpz_t n, mpz_t d) + bint mpz_divisible_ui_p (mpz_t n, unsigned long int d) + bint mpz_divisible_2exp_p (mpz_t n, unsigned long int b) + bint mpz_congruent_p (mpz_t n, mpz_t c, mpz_t d) + bint mpz_congruent_ui_p (mpz_t n, unsigned long int c, unsigned long int d) + bint mpz_congruent_2exp_p (mpz_t n, mpz_t c, unsigned long int b) + + # Exponentiation Functions + void mpz_powm (mpz_t rop, mpz_t base, mpz_t exp, mpz_t mod) + void mpz_powm_ui (mpz_t rop, mpz_t base, unsigned long int exp, mpz_t mod) + void mpz_pow_ui (mpz_t rop, mpz_t base, unsigned long int exp) + void mpz_ui_pow_ui (mpz_t rop, unsigned long int base, unsigned long int exp) + + # Root Extraction Functions + int mpz_root (mpz_t rop, mpz_t op, unsigned long int n) + void mpz_rootrem (mpz_t root, mpz_t rem, mpz_t u, unsigned long int n) + void mpz_sqrt (mpz_t rop, mpz_t op) + void mpz_sqrtrem (mpz_t rop1, mpz_t rop2, mpz_t op) + bint mpz_perfect_power_p (mpz_t op) + bint mpz_perfect_square_p (mpz_t op) + + # Number Theoretic Functions + bint mpz_probab_prime_p (mpz_t n, int reps) + void mpz_nextprime (mpz_t rop, mpz_t op) + void mpz_gcd (mpz_t rop, mpz_t op1, mpz_t op2) + unsigned long int mpz_gcd_ui (mpz_t rop, mpz_t op1, unsigned long int op2) + void mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, mpz_t a, mpz_t b) + void mpz_lcm (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_lcm_ui (mpz_t rop, mpz_t op1, unsigned long op2) + int mpz_invert (mpz_t rop, mpz_t op1, mpz_t op2) + int mpz_jacobi (mpz_t a, mpz_t b) + int mpz_legendre (mpz_t a, mpz_t p) + int mpz_kronecker (mpz_t a, mpz_t b) + int mpz_kronecker_si (mpz_t a, long b) + int mpz_kronecker_ui (mpz_t a, unsigned long b) + int mpz_si_kronecker (long a, mpz_t b) + int mpz_ui_kronecker (unsigned long a, mpz_t b) + unsigned long int mpz_remove (mpz_t rop, mpz_t op, mpz_t f) + void mpz_fac_ui (mpz_t rop, unsigned long int op) + void mpz_2fac_ui (mpz_t rop, unsigned long int op) + void mpz_mfac_uiui (mpz_t rop, unsigned long int n, unsigned long int m) + void mpz_bin_ui (mpz_t rop, mpz_t n, unsigned long int k) + void mpz_bin_uiui (mpz_t rop, unsigned long int n, unsigned long int k) + void mpz_fib_ui (mpz_t fn, unsigned long int n) + void mpz_fib2_ui (mpz_t fn, mpz_t fnsub1, unsigned long int n) + void mpz_lucnum_ui (mpz_t ln, unsigned long int n) + void mpz_lucnum2_ui (mpz_t ln, mpz_t lnsub1, unsigned long int n) + + # Comparison Functions + int mpz_cmp (mpz_t op1, mpz_t op2) + int mpz_cmp_d (mpz_t op1, double op2) + int mpz_cmp_si (mpz_t op1, signed long int op2) + int mpz_cmp_ui (mpz_t op1, unsigned long int op2) + int mpz_cmpabs (mpz_t op1, mpz_t op2) + int mpz_cmpabs_d (mpz_t op1, double op2) + int mpz_cmpabs_ui (mpz_t op1, unsigned long int op2) + int mpz_sgn (mpz_t op) + + # Logical and Bit Manipulation Functions + void mpz_and (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_ior (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_xor (mpz_t rop, mpz_t op1, mpz_t op2) + void mpz_com (mpz_t rop, mpz_t op) + unsigned long int mpz_popcount (mpz_t op) + unsigned long int mpz_hamdist (mpz_t op1, mpz_t op2) + unsigned long int mpz_scan0 (mpz_t op, unsigned long int starting_bit) + unsigned long int mpz_scan1 (mpz_t op, unsigned long int starting_bit) + void mpz_setbit (mpz_t rop, unsigned long int bit_index) + void mpz_clrbit (mpz_t rop, unsigned long int bit_index) + void mpz_combit (mpz_t rop, unsigned long int bit_index) + int mpz_tstbit (mpz_t op, unsigned long int bit_index) + + # Input and Output Functions + size_t mpz_out_str (FILE *stream, int base, mpz_t op) + size_t mpz_inp_str (mpz_t rop, FILE *stream, int base) + size_t mpz_out_raw (FILE *stream, mpz_t op) + size_t mpz_inp_raw (mpz_t rop, FILE *stream) + + # Integer Import and Export + void mpz_import (mpz_t rop, size_t count, int order, int size, int endian, size_t nails, void *op) + void * mpz_export (void *rop, size_t *countp, int order, int size, int endian, size_t nails, mpz_t op) + + # Miscellaneous Functions + bint mpz_fits_ulong_p (mpz_t op) + bint mpz_fits_slong_p (mpz_t op) + bint mpz_fits_uint_p (mpz_t op) + bint mpz_fits_sint_p (mpz_t op) + bint mpz_fits_ushort_p (mpz_t op) + bint mpz_fits_sshort_p (mpz_t op) + bint mpz_odd_p (mpz_t op) + bint mpz_even_p (mpz_t op) + size_t mpz_sizeinbase (mpz_t op, int base) + + # Special Functions + void * _mpz_realloc (mpz_t integer, mp_size_t new_alloc) + mp_limb_t mpz_getlimbn (mpz_t op, mp_size_t n) + size_t mpz_size (mpz_t op) diff --git a/extmod/bls_py/types.pxd b/extmod/bls_py/types.pxd new file mode 100644 index 0000000..40d9a32 --- /dev/null +++ b/extmod/bls_py/types.pxd @@ -0,0 +1,33 @@ +# cython: language_level=3 +# -*- coding: utf-8 -*- + +cdef extern from "gmp.h": + # GMP's configuration of how many bits are stuffed into a limb + cdef unsigned int GMP_LIMB_BITS + cdef int mp_bits_per_limb + + # Underlying typedefs + ctypedef unsigned long mp_limb_t + ctypedef long mp_limb_signed_t + ctypedef unsigned long mp_bitcnt_t + ctypedef long mp_size_t + ctypedef long mp_exp_t + + ctypedef mp_limb_t* mp_ptr + ctypedef mp_limb_t* mp_srcptr + + # This internal structure is not guaranteed to stay the same with + # future releases of GMP or MPIR. + ctypedef struct __mpz_struct: + int _mp_alloc + int _mp_size + mp_ptr _mp_d + + # User facing types + ctypedef __mpz_struct mpz_t[1] + + ctypedef __mpz_struct *mpz_ptr + ctypedef __mpz_struct *mpz_srcptr + + # Cython doesn't want to take the address of an mpz_t + cdef mpz_t* address_of_mpz "&"(mpz_t x) diff --git a/setup.py b/setup.py index e6120d6..6fd266b 100644 --- a/setup.py +++ b/setup.py @@ -1,26 +1,52 @@ #!/usr/bin/python3 +import sys from setuptools import setup +from setuptools.extension import Extension + +try: + from Cython.Build import cythonize + USE_CYTHON = True +except ImportError: + USE_CYTHON = False description='BLS12-381 and Signatures in python' + long_description=('Implements the BLS12 curve and optimal ate pairing, ' 'as well as BLS signatures and aggregation. Use for ' 'reference / educational purposes only. ' 'Based on reference implementation from Chia BLS Signatures') +if sys.platform in ('windows', 'win32'): + MP_LIB = 'mpir' +else: + MP_LIB = 'gmp' + + +ext = '.pyx' if USE_CYTHON else '.c' + + +extensions = [ + Extension('bls_py.fields_t_c', [f'extmod/bls_py/fields_t_c{ext}'], + libraries=[MP_LIB]), +] + + +if USE_CYTHON: + extensions = cythonize(extensions) + + setup( name='python-bls', - version='0.1.5', + version='0.1.6', url='https://github.com/zebra-lucky/python-bls', license='Apache License 2.0', - install_requires=[ - 'typing; python_version < "3.5"', - ], - python_requires='>=3.4', + python_requires='>=3.6', packages=['bls_py'], + ext_modules=extensions, platforms='any', description=description, long_description=long_description,