Commit b9d01dbd authored by GUILLEVIC Aurore's avatar GUILLEVIC Aurore

other families with k=8

parent 61c23ae3
......@@ -19,7 +19,7 @@ from PairingFriendlyCurve import print_parameters, print_parameters_for_RELIC
class CocksPinch8(EllipticCurve_finite_field):
"""
A Cocks-Pinch curve of embedding degree k=8, D=8, rho=2 and optimal ate pairing available.
A Cocks-Pinch curve of embedding degree k=8, D=4, rho=2 and optimal ate pairing available.
"""
def __init__(self, u, hy, ht, exp_tr=None, p=None, r=None, c=None, tr=None, y=None, a=None, beta=None, lamb=None):
......
"""
Fotiadis-Konstantinou curve with k=8, rho=2 and D=4
From the papers https://eprint.iacr.org/2018/1017.pdf
(for the curves)
k = 8; D = 4; rho = 2; #quartic twists, V = [x, -1, 0, 0], x = 0 (mod 2)
px = (x^8 + x^6 + 5*x^4 + x^2 + 4*x + 4)/4
rx = x^4 + 1
tx = x^4 + x + 2
yx = (x^3 - x^2)/2 #remove the /2 if you consider D=1
cx = (x^4+x^2)/4
beta = (x^6 - x^5 - 2*x^3 + 3*x^2 - 3*x - 2)/4
lamb = x^2
and
https://eprint.iacr.org/2018/969.pdf
https://eprint.iacr.org/2019/555.pdf
(for pairing computation estimates)
"""
import sage
from exceptions import ValueError
from sage.functions.log import log
from sage.functions.other import ceil
from sage.functions.other import sqrt
from sage.arith.misc import XGCD, xgcd
from sage.rings.integer import Integer
from sage.rings.finite_rings.finite_field_constructor import FiniteField
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field
from sage.schemes.elliptic_curves.constructor import EllipticCurve
import PairingFriendlyCurve
from PairingFriendlyCurve import get_curve_parameter_a_j1728, get_curve_generator_order_r_j1728
from PairingFriendlyCurve import print_parameters, print_parameters_for_RELIC
class FK8D4(EllipticCurve_finite_field):
"""
A Fotiadis-Konstantinou curve of embedding degree k=8, D=4, rho=2
https://eprint.iacr.org/2018/1017
"""
def __init__(self, u, a=None):
"""
u is the seed s.t. p=P(u), r=R(u), t=T(u)
:param u : seed
:param a : curve parameter in E: y^2 = x^3 + a*x (optional)
"""
self._k = 8 # embedding degree
self._D = 4 # curve discriminant
self._b = 0
self._u = Integer(u)
# see bottom of file for formulas
self.polynomial_r = [1, 0, 0, 0, 1] # u^4 + 1
self.polynomial_r_denom = Integer(1)
self.polynomial_tr= [2, 1, 0, 0, 1]
self.polynomial_tr_denom = Integer(1)
self.polynomial_p = [4, 4, 1, 0, 5, 0, 1, 0, 1]
self.polynomial_p_denom = Integer(4)
self.polynomial_y = [0, 0, -1, 1]
self.polynomial_y_denom = Integer(2)
self.polynomial_c = [0, 0, 1, 0, 1]
self.polynomial_c_denom = Integer(4)
self.polynomial_beta = [-2, -3, 3, -2, 0, -1, 1]
self.polynomial_beta_denom = Integer(4)
self.polynomial_lamb = [0,0,1] # x^2 mod r(x) = x^4+1
self.polynomial_lamb_denom = Integer(1)
self._p = sum([Integer(self.polynomial_p[i])*self._u**i for i in range(len(self.polynomial_p))])//self.polynomial_p_denom
self._pbits = self._p.nbits()
self._r = sum([Integer(self.polynomial_r[i])*self._u**i for i in range(len(self.polynomial_r))])//self.polynomial_r_denom
self._c = sum([Integer(self.polynomial_c[i])*self._u**i for i in range(len(self.polynomial_c))])//self.polynomial_c_denom
self._tr= sum([Integer(self.polynomial_tr[i])*self._u**i for i in range(len(self.polynomial_tr))])//self.polynomial_tr_denom
if not self._c * self._r == self._p + 1 - self._tr:
raise ValueError("Error: r*c != p+1-tr\nr={}\nc={}\np+1-tr={}\n".format(self._r,self._c,self._p+1-self._tr))
self._y = sum([Integer(self.polynomial_y[i])*self._u**i for i in range(len(self.polynomial_y))])//self.polynomial_y_denom
# GLV parameter for fast scalar multiplication thanks to automorphism
# psi: (x,y) -> (-x,i*y) = [lambda mod r]*(x,y) if (x,y) is of order r
# where beta is a root of x^2+1 mod p, beta = sqrt(-1) mod p
# and lambda is a root of x^2+1 mod r, lamb = sqrt(-1) mod r
# there are two choices: beta, -beta, and the same for lamb: lamb, -lamb
# arbitrarily the positive ones are chosen
# if u is odd, beta has integer coefficients,
# but if u is even, then beta has denomiator 2: use / instead of //
if (self._u % 2) == 0:
self._beta = sum([Integer(self.polynomial_beta[i])*self._u**i for i in range(len(self.polynomial_beta))])/self.polynomial_beta_denom
else:
self._beta = sum([Integer(self.polynomial_beta[i])*self._u**i for i in range(len(self.polynomial_beta))])//self.polynomial_beta_denom
# lamb is always an integer
self._lamb = sum([Integer(self.polynomial_lamb[i])*self._u**i for i in range(len(self.polynomial_lamb))])//self.polynomial_lamb_denom
try:
self._Fp = FiniteField(self._p)
except ValueError as err:
print("ValueError creating Fp: {}".format(err))
raise
except:
print("Error creating Fp")
raise
if not self._r.is_prime():
raise ValueError("Error r is not prime")
# if u is even, beta has denominator 2, reduces mod p:
if (self._u %2) == 0:
self._beta = Integer(self._Fp(self._beta))
if ((self._beta**2 + 1) % self._p) != 0:
raise ValueError("Error beta^2 + 1 != 0 mod p")
if ((self._lamb**2 + 1) % self._r) != 0:
raise ValueError("Error lamb^2 + 1 != 0 mod r")
self._Fpz = PolynomialRing(self._Fp, names=('z',))
(self._z,) = self._Fpz._first_ngens(1)
self._bp = self._Fp(0) # second curve parameter is 0 because j=1728
if a != None:
try:
a = Integer(a)
except:
raise
self._a = a
self._ap = self._Fp(a)
else:
# check that beta = U/V, where U=t/2, V = y
self._a, self._ap = get_curve_parameter_a_j1728(self._tr, self._y, self._beta, self._p, self._Fp)
# Now self._a is such that E: y^2 = x^3 + a*x has order r
try:
# this init function of super inherits from class EllipticCurve_generic defined in ell_generic.py
# __init__ method inherited from ell_generic
EllipticCurve_finite_field.__init__(self, self._Fp, [0,0,0,self._ap,0])
except ValueError as err:
print("ValueError at EllipticCurve_finite_field.__init__: {}".format(err))
raise
except:
print("An error occupred when initialising the elliptic curve")
raise
self.order_checked = super(FK8D4,self).order()
if self.order_checked != (self._p+1-self._tr):
print("Error, wrong order")
raise ValueError("Wrong curve order: this one is a twist")
# computes a generator
self._G = get_curve_generator_order_r_j1728(self)
self._Gx = self._G[0]
self._Gy = self._G[1]
# adjust beta and lamb according to the curve
# do we have (-x,beta*y) = lamb*(x,y)?
if self([-self._Gx, self._Gy*self._beta]) != self._lamb*self._G:
print("adjusting beta, lambda")
if self([-self._Gx, self._Gy*(-self._beta)]) == self._lamb*self._G:
self._beta = self._p-self._beta
print("beta -> -beta")
elif self([-self._Gx, self._Gy*self._beta]) == (-self._lamb)*self._G:
self._lamb = -self._lamb
print("lamb -> -lamb")
elif self([-self._Gx, self._Gy*(-self._beta)]) == (-self._lamb)*self._G:
self._beta = self._p-self._beta
self._lamb = -self._lamb
print("lamb -> -lamb")
print("beta -> -beta")
else:
raise ValueError("Error while adjusting beta, lamb: compatibility not found")
def _repr_(self):
return "FK8D4 p"+str(self._pbits)+" (Fotiadis-Konstantinou k=8) curve with seed "+str(self._u)+"\n"+super(FK8D4,self)._repr_()
def u(self):
return self._u
def T(self):
return self._u
def p(self):
return self._p
def r(self):
return self._r
def c(self):
return self._c
def tr(self):
return self._tr
def y(self):
return self._y
def D(self):
return self._D
def a(self):
return self._a # Integer
def ap(self):
return self._ap # in Fp (finite field element)
def b(self):
return self._b # 0
def bp(self):
return self._bp # 0
def beta(self):
return self._beta
def lamb(self):
return self._lamb
def k(self):
return self._k
def Fp(self):
return self._Fp
def Fpz(self):
return self._Fpz, self._z
def G(self):
return self._G
def print_parameters(self):
PairingFriendlyCurve.print_parameters(self)
def print_parameters_for_RELIC(self):
PairingFriendlyCurve.print_parameters_for_RELIC(self)
"""
Tanaka-Nakamula curves k=8 D=4 rho=1.5
Published at Pairing'2008
k = 8; D = 4; rho = 1.5; #quartic twists available
rx = 2*x^4 + 4*x^3 + 6*x^2 + 4*x + 1
tx = 2*x^3 + 2*x^2 + 4*x + 2
yx = 3*x^3 + 5*x^2 + 7*x + 3
px = 10*x^6 + 32*x^5 + 72*x^4 + 94*x^3 + 85*x^2 + 46*x + 10
cx = 5*x^2 + 6*x + 9
twx= 10*x^6 + 32*x^5 + 72*x^4 + 96*x^3 + 87*x^2 + 50*x + 13
beta = 70*x^5 + 184*x^4 + 396*x^3 + 424*x^2 + 341*x + 117
lamb = 4*x^3 + 6*x^2 + 8*x + 3
"""
import sage
from exceptions import ValueError
from sage.functions.log import log
from sage.functions.other import ceil
from sage.functions.other import sqrt
from sage.arith.misc import XGCD, xgcd
from sage.rings.integer import Integer
from sage.rings.finite_rings.finite_field_constructor import FiniteField
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field
from sage.schemes.elliptic_curves.constructor import EllipticCurve
import PairingFriendlyCurve
from PairingFriendlyCurve import get_curve_parameter_a_j1728, get_curve_generator_order_r_j1728
from PairingFriendlyCurve import print_parameters, print_parameters_for_RELIC
class TN8(EllipticCurve_finite_field):
"""
A Tanaka-Nakamula curve of embedding degree k=8, D=4 rho=1.5
Pairing 2008
"""
def __init__(self, u, a=None):
"""
u is the seed s.t. p=P(u), r=R(u), t=T(u)
:param u : seed
:param a : curve parameter in E: y^2 = x^3 + a*x (optional)
"""
self._k = 8 # embedding degree
self._D = 4 # curve discriminant
self._b = 0
self._u = Integer(u)
# see bottom of file for formulas
self.polynomial_r = [1, 4, 6, 4, 2]
self.polynomial_tr= [2, 4, 2, 2]
self.polynomial_y = [3, 7, 5, 3]
self.polynomial_p = [10, 46, 85, 94, 72, 32, 10]
self.polynomial_c = [9, 6, 5]
self.polynomial_beta = [117, 341, 424, 396, 184, 70]
self.polynomial_lamb = [3, 8, 6, 4]
self.polynomial_r_denom = Integer(1)
self.polynomial_tr_denom = Integer(1)
self.polynomial_y_denom = Integer(1)
self.polynomial_p_denom = Integer(1)
self.polynomial_c_denom = Integer(1)
self.polynomial_beta_denom = Integer(1)
self.polynomial_lamb_denom = Integer(1)
self._p = sum([Integer(self.polynomial_p[i])*self._u**i for i in range(len(self.polynomial_p))])
self._pbits = self._p.nbits()
self._r = sum([Integer(self.polynomial_r[i])*self._u**i for i in range(len(self.polynomial_r))])
self._c = sum([Integer(self.polynomial_c[i])*self._u**i for i in range(len(self.polynomial_c))])
self._tr= sum([Integer(self.polynomial_tr[i])*self._u**i for i in range(len(self.polynomial_tr))])
if not self._c * self._r == self._p + 1 - self._tr:
raise ValueError("Error: r*c != p+1-tr\nr={}\nc={}\np+1-tr={}\n".format(self._r,self._c,self._p+1-self._tr))
self._y = sum([Integer(self.polynomial_y[i])*self._u**i for i in range(len(self.polynomial_y))])
# GLV parameter for fast scalar multiplication thanks to automorphism
# psi: (x,y) -> (-x,i*y) = [lambda mod r]*(x,y) if (x,y) is of order r
# where beta is a root of x^2+1 mod p, beta = sqrt(-1) mod p
# and lambda is a root of x^2+1 mod r, lamb = sqrt(-1) mod r
# there are two choices: beta, -beta, and the same for lamb: lamb, -lamb
# arbitrarily the positive ones are chosen
self._beta = sum([Integer(self.polynomial_beta[i])*self._u**i for i in range(len(self.polynomial_beta))])
self._lamb = sum([Integer(self.polynomial_lamb[i])*self._u**i for i in range(len(self.polynomial_lamb))])
try:
self._Fp = FiniteField(self._p)
except ValueError as err:
print("ValueError creating Fp: {}".format(err))
raise
except:
print("Error creating Fp")
raise
if not self._r.is_prime():
raise ValueError("Error r is not prime")
if ((self._beta**2 + 1) % self._p) != 0:
raise ValueError("Error beta^2 + 1 != 0 mod p")
if ((self._lamb**2 + 1) % self._r) != 0:
raise ValueError("Error lamb^2 + 1 != 0 mod r")
self._Fpz = PolynomialRing(self._Fp, names=('z',))
(self._z,) = self._Fpz._first_ngens(1)
self._bp = self._Fp(0) # second curve parameter is 0 because j=1728
if a != None:
try:
a = Integer(a)
except:
raise
self._a = a
self._ap = self._Fp(a)
else:
# check that beta = U/V, where U=t/2, V = y
self._a, self._ap = get_curve_parameter_a_j1728(self._tr, self._y, self._beta, self._p, self._Fp)
# Now self._a is such that E: y^2 = x^3 + a*x has order r
try:
# this init function of super inherits from class EllipticCurve_generic defined in ell_generic.py
# __init__ method inherited from ell_generic
EllipticCurve_finite_field.__init__(self, self._Fp, [0,0,0,self._ap,0])
except ValueError as err:
print("ValueError at EllipticCurve_finite_field.__init__: {}".format(err))
raise
except:
print("An error occupred when initialising the elliptic curve")
raise
self.order_checked = super(TN8,self).order()
if self.order_checked != (self._p+1-self._tr):
print("Error, wrong order")
raise ValueError("Wrong curve order: this one is a twist")
# computes a generator
self._G = get_curve_generator_order_r_j1728(self)
self._Gx = self._G[0]
self._Gy = self._G[1]
# adjust beta and lamb according to the curve
# do we have (-x,beta*y) = lamb*(x,y)?
if self([-self._Gx, self._Gy*self._beta]) != self._lamb*self._G:
print("adjusting beta, lambda")
if self([-self._Gx, self._Gy*(-self._beta)]) == self._lamb*self._G:
self._beta = self._p-self._beta
print("beta -> -beta")
elif self([-self._Gx, self._Gy*self._beta]) == (-self._lamb)*self._G:
self._lamb = -self._lamb
print("lamb -> -lamb")
elif self([-self._Gx, self._Gy*(-self._beta)]) == (-self._lamb)*self._G:
self._beta = self._p-self._beta
self._lamb = -self._lamb
print("lamb -> -lamb")
print("beta -> -beta")
else:
raise ValueError("Error while adjusting beta, lamb: compatibility not found")
def _repr_(self):
return "TN8 p"+str(self._pbits)+" (Tanaka-Nakamula k=8) curve with seed "+str(self._u)+"\n"+super(TN8,self)._repr_()
def u(self):
return self._u
def T(self):
return self._u
def p(self):
return self._p
def r(self):
return self._r
def c(self):
return self._c
def tr(self):
return self._tr
def y(self):
return self._y
def D(self):
return self._D
def a(self):
return self._a # Integer
def ap(self):
return self._ap # in Fp (finite field element)
def b(self):
return self._b # 0
def bp(self):
return self._bp # 0
def beta(self):
return self._beta
def lamb(self):
return self._lamb
def k(self):
return self._k
def Fp(self):
return self._Fp
def Fpz(self):
return self._Fpz, self._z
def G(self):
return self._G
def print_parameters(self):
PairingFriendlyCurve.print_parameters(self)
def print_parameters_for_RELIC(self):
PairingFriendlyCurve.print_parameters_for_RELIC(self)
"""
ZZx.<x> = ZZ[]
k=8
ux = 2*x^3 + 4*x^2 + 6*x + 3
Phi8 = cyclotomic_polynomial(k)
Phi8(ux).factor()
rx = (2*x^4 + 4*x^3 + 6*x^2 + 4*x + 1)
tx = (ux^3+1) % rx
# yx = (tx-2)/sqrt(-D)
sqrt_D = ux^2 % rx
#g, u, v = xgcd(sqrt_D, rx)
#g == u*sqrt_D + v*rx
#inv_sqrt_D = u/ZZ(g)
inv_sqrt_D = sqrt_D # 1/sqrt(-1) = -sqrt(-1)
assert ((inv_sqrt_D^2 + 1) % rx) == 0
yx = ((tx-2)*inv_sqrt_D/2) % rx
px = (tx^2 + 4*yx^2)/4
assert tx^2 - 4*px == -4*yx^2
assert (px+1-tx) % rx == 0
cx = (px+1-tx)//rx
assert Phi8(px) % rx == 0
twx = px+1+tx
lamb = sqrt_D
# sqrt(-1) mod px <-> tx/yx -> invert yx mod px
g,u,v = xgcd(yx,px)
g == u*yx + v*px
inv_yx = u/ZZ(g)
beta = tx*inv_yx/2 % px
assert ((beta^2 +1) % rx) == 0
assert ((lamb^2 +1) % px) == 0
print("rx = {}".format(rx))
print("tx = {}".format(tx))
print("yx = {}".format(yx))
print("px = {}".format(px))
print("cx = {}".format(cx))
print("twx= {}".format(twx))
print("beta = {}".format(beta))
print("lamb = {}".format(lamb))
print("R = {}".format(rx.list()))
print("T = {}".format(tx.list()))
print("Y = {}".format(yx.list()))
print("P = {}".format(px.list()))
print("C = {}".format(cx.list()))
print("TW= {}".format(twx.list()))
print("BETA = {}".format(beta.list()))
print("LAMB = {}".format(lamb.list()))
"""
......@@ -224,6 +224,83 @@ class TestPairingFriendlyCurve():
# outside the class
def generate_parameters_high(pnbits, poly_p, poly_r, polys_cofact_twist=[], u_mod_m=0, m=1,verbose=False):
""" Generate parameters:
find u s.t. p=poly_p(u), r=poly_r(u), tw=poly_r_twist(u) are prime,
and p is pnbits long."""
lc = poly_p.leading_coefficient()
deg_p = poly_p.degree()
u_min = floor((2**(pnbits-1)/lc)**(1/deg_p))
u_min = (u_min-(u_min % m) + u_mod_m)
while (ceil(poly_p(u_min))).nbits() < pnbits:
u_min+=m
while (ceil(poly_p(u_min))).nbits() > pnbits:
u_min-=m
u_max = floor((2**pnbits/lc)**(1/deg_p))
u_max = (u_max-(u_max % m) + u_mod_m)
while (ceil(poly_p(u_max))).nbits() > pnbits:
u_max-=m
while (ceil(poly_p(u_max))).nbits() < pnbits:
u_max+=m
u = u_max
p = ZZ(poly_p(u))
r = ZZ(poly_r(u))
tw= [ZZ(c_i(u)) for c_i in polys_cofact_twist]
if pnbits < 1024:
prod_primes = prod(prime_range(10**5))
else:
prod_primes = prod(prime_range(10**7))
i = 0
# save the gcd of parameters to detect possible systematic cofactor
gcd_p = 0
gcd_r = 0
gcd_ci = [0 for j in range(len(tw))]
gcd_pi = gcd(prod_primes, p)
gcd_ri = gcd(prod_primes, r)
cond = gcd_pi > 1 or gcd_ri > 1
j = 0
for ci in tw:
gcd_cii = gcd(prod_primes, ci)
gcd_ci[j] = gcd_cii
cond = cond or gcd_ci[j] > 1
j += 1
cond = cond or not p.is_pseudoprime() or not r.is_pseudoprime()
for ci in tw:
cond = cond or not ci.is_pseudoprime()
while u >= u_min and cond:
u -=m
p = ZZ(poly_p(u))
r = ZZ(poly_r(u))
tw= [ZZ(c_i(u)) for c_i in polys_cofact_twist]
gcd_pi = gcd(prod_primes, p)
gcd_ri = gcd(prod_primes, r)
gcd_p = gcd(gcd_p, gcd_pi)
gcd_r = gcd(gcd_r, gcd_ri)
cond = gcd_pi > 1 or gcd_ri > 1
j = 0
for ci in tw:
gcd_cii = gcd(prod_primes, ci)
gcd_ci[j] = gcd(gcd_ci[j], gcd_cii)
cond = cond or gcd_cii > 1
j += 1
cond = cond or not p.is_pseudoprime() or not r.is_pseudoprime()
for ci in tw:
cond = cond or not ci.is_pseudoprime()
i +=1
if verbose and (i % 10**5) == 0:
print i
print("gcd all p: {} gcd all r: {} gcd all ci: {}".format(gcd_p, gcd_r, gcd_ci))
# reset
gcd_p = 0
gcd_r = 0
gcd_ci = [0 for j in range(len(tw))]
if u >= u_min:
print("u={}, i = {}".format(u,i))
return u, p, r, tw, u_min, u_max, i
# else return None
from CocksPinch6 import CocksPinch6
from CocksPinch8 import CocksPinch8
from CocksPinch_k import CocksPinch_k
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment