def gen_params_from_r(r,k): """ Description: Finds a fundamental discriminant D to use as input to the Cocks-Pinch method Input: r - prime such that r % k == 1 k - embedding degree Output: r - prime such that r % k == 1 k - embedding degree D - (negative) fundamental discriminant where D is a square mod r """ D = -Integer(Mod(int(random()*(1000)),r)) i = 0 while not kronecker(D,r) == 1: # expected number of iterations of the while loop is 2 D = -Integer(Mod(int(random()*(1000)),r)) i+=1 D = fundamental_discriminant(D) if not (kronecker(D,r) == 1): return r, k, 0 return r,k,D
def gen_params_from_r(r, k): """ Description: Finds a fundamental discriminant D to use as input to the Cocks-Pinch method Input: r - prime such that r % k == 1 k - embedding degree Output: r - prime such that r % k == 1 k - embedding degree D - (negative) fundamental discriminant where D is a square mod r """ D = -Integer(Mod(int(random() * (1000)), r)) i = 0 while not kronecker( D, r) == 1: # expected number of iterations of the while loop is 2 D = -Integer(Mod(int(random() * (1000)), r)) i += 1 D = fundamental_discriminant(D) if not (kronecker(D, r) == 1): return r, k, 0 return r, k, D
def small_A_twist(E): """ Description: Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B """ a = E.ainvs()[3] q = E.base_field().order() a = power_mod(Integer(a), -1, q) if kronecker(a, q) == -1: b = 2 while kronecker(b, q) == 1: b += 1 a = a * b assert kronecker(a, q) == 1 d = Mod(a, q).sqrt() ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def make_curve(k,D): """ Description: Find all MNT curves with embedding degree k and fundamental discriminant D Input: k - embedding degree D - (negative) fundamental discriminant Output: curves - list of the aforementioned elliptic curves; each curve is represented as a tuple (q,t,r,k,D) """ assert k == 3 or k== 4 or k == 6, 'Invalid embedding degree' assert fundamental_discriminant(D) == D, 'Invalid discriminant' if k == 3: curves = _mnt_subcall(k,D, 24,lambda x: ((x % 24 == 19) and kronecker(6,x) == 1), 6, 3, -3, lambda x: (x -3 )//6, lambda x: (x+3)//6, lambda l: 6*l - 1, lambda l: -6*l - 1, lambda l: 12*l*l - 1) if k == 4: curves = _mnt_subcall(k,D,-8, lambda x: ( (x % 8 == 3) and kronecker(-2, x) ==1) or (x == 2) or (x == 8), 3, 2, 1, lambda x: (x-2)//3, lambda x: (x-1)//3, lambda l: -l, lambda l: l+1, lambda l: l*l + l + 1) if k == 6: curves = _mnt_subcall(k,D,-8, lambda x: (x % 8 == 3) and kronecker(-2, x) == 1, 6, 5, 1, lambda x: (x+1)//6, lambda x: (x-1)//6, lambda l: 2*l + 1, lambda l: -2*l + 1, lambda l: 4*l*l + 1) for c in curves: assert is_valid_curve(c[0],c[1],c[2],c[3],c[4]), 'Invalid output' assert k == c[3], 'Bug in code' assert D == c[4], 'Bug in code' return curves
def eta_argument(a, b, c, d): res = (a + d) * c - b * d * (c * c - 1) den = 24 if is_odd(c): return res - 3 * c, den, kronecker(d, c) else: return res + 3 * d - 3 - 3 * c * d, den, kronecker(d, c)
def _action0(self,a,b,c,d): r""" Recall that the formula is valid only for c>0. Otherwise we have to use: v(A)=v((-I)(-A))=sigma(-I,-A)v(-I)v(-A). Then note that by the formula for sigma we have: sigma(-I,SL2Z[a, b, c, d])=-1 if (c=0 and d<0) or c>0 and other wise it is =1. """ fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak if c==0: if a>0: res = self._z**b else: res = self._fak*self._z**b else: if is_even(c): arg = (a+d)*c-b*d*(c*c-1)+3*d-3-3*c*d v=kronecker(c,d) else: arg = (a+d)*c-b*d*(c*c-1)-3*c v=kronecker(d,c) if not self._half_integral_weight: # recall that we can use eta for any real weight v=v**(2*self._weight) arg=arg*(self._k_num) res = v*fak*self._z**arg if self._character: res = res * self._character(d) if self._is_dual: res=res**-1 return res
def small_A_twist(E): """ Description: Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B """ a = E.ainvs()[3] q = E.base_field().order() a = power_mod(Integer(a), -1, q) if kronecker(a,q) == -1: b = 2 while kronecker(b,q) == 1: b += 1 a = a*b assert kronecker(a,q) == 1 d = Mod(a,q).sqrt() ainvs = [i for i in E.ainvs()] ainvs[3]*= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def eta_argument(a,b,c,d): res = (a+d)*c-b*d*(c*c-1) den = 24 if is_odd(c): return res-3*c,den,kronecker(d,c) else: return res+3*d-3-3*c*d,den,kronecker(d,c)
def sigma_rep(Delta, print_divisors=False): s = 0 for DD in divisors(Delta): if is_fundamental_discriminant(-DD): D = -DD for d in divisors(old_div(Delta, D)): s += kronecker(D, d) if print_divisors: print(D, d, kronecker(D, d)) return s
def xi(self, A): r""" The eight-root of unity in front of the Weil representation. INPUT: -''N'' -- integer -''A'' -- element of PSL(2,Z) EXAMPLES:: sage: A=SL2Z([41,77,33,62]) sage: WR.xi(A) -zeta8^3] sage: S,T=SL2Z.gens() sage: WR.xi(S) -zeta8^3 sage: WR.xi(T) 1 sage: A=SL2Z([-1,1,-4,3]) sage: WR.xi(A) -zeta8^2 sage: A=SL2Z([0,1,-1,0]) sage: WR.xi(A) -zeta8 """ a = Integer(A[0, 0]) b = Integer(A[0, 1]) c = Integer(A[1, 0]) d = Integer(A[1, 1]) if (c == 0): return 1 z = CyclotomicField(8).gen() N = self._N N2 = odd_part(N) Neven = ZZ(2 * N).divide_knowing_divisible_by(N2) c2 = odd_part(c) Nc = gcd(Integer(2 * N), Integer(c)) cNc = ZZ(c).divide_knowing_divisible_by(Nc) f1 = kronecker(-a, cNc) f2 = kronecker(cNc, ZZ(2 * N).divide_knowing_divisible_by(Nc)) if (is_odd(c)): s = c * N2 elif (c % Neven == 0): s = (c2 + 1 - N2) * (a + 1) else: s = (c2 + 1 - N2) * (a + 1) - N2 * a * c2 r = -1 - QQ(N2) / QQ(gcd(c, N2)) + s xi = f1 * f2 * z**r return xi
def xi(self,A): r""" The eight-root of unity in front of the Weil representation. INPUT: -''N'' -- integer -''A'' -- element of PSL(2,Z) EXAMPLES:: sage: A=SL2Z([41,77,33,62]) sage: WR.xi(A) -zeta8^3] sage: S,T=SL2Z.gens() sage: WR.xi(S) -zeta8^3 sage: WR.xi(T) 1 sage: A=SL2Z([-1,1,-4,3]) sage: WR.xi(A) -zeta8^2 sage: A=SL2Z([0,1,-1,0]) sage: WR.xi(A) -zeta8 """ a=Integer(A[0,0]); b=Integer(A[0,1]) c=Integer(A[1,0]); d=Integer(A[1,1]) if(c==0): return 1 z=CyclotomicField(8).gen() N=self._N N2=odd_part(N) Neven=ZZ(2*N).divide_knowing_divisible_by(N2) c2=odd_part(c) Nc=gcd(Integer(2*N),Integer(c)) cNc=ZZ(c).divide_knowing_divisible_by(Nc) f1=kronecker(-a,cNc) f2=kronecker(cNc,ZZ(2*N).divide_knowing_divisible_by(Nc)) if(is_odd(c)): s=c*N2 elif( c % Neven == 0): s=(c2+1-N2)*(a+1) else: s=(c2+1-N2)*(a+1)-N2*a*c2 r=-1-QQ(N2)/QQ(gcd(c,N2))+s xi=f1*f2*z**r return xi
def class_nr_pos_def_qf(D): r""" Compute the class number of positive definite quadratic forms. For fundamental discriminants this is the class number of Q(sqrt(D)), otherwise it is computed using: Cohen 'A course in Computational Algebraic Number Theory', p. 233 """ if D>0: return 0 D4 = D % 4 if D4 == 3 or D4==2: return 0 K = QuadraticField(D) if is_fundamental_discriminant(D): return K.class_number() else: D0 = K.discriminant() Df = ZZ(D).divide_knowing_divisible_by(D0) if not is_square(Df): raise ArithmeticError("Did not get a discrimimant * square! D={0} disc(D)={1}".format(D,D0)) D2 = sqrt(Df) h0 = QuadraticField(D0).class_number() w0 = _get_w(D0) w = _get_w(D) #print "w,w0=",w,w0 #print "h0=",h0 h = 1 for p in prime_divisors(D2): h = QQ(h)*(1-kronecker(D0,p)/QQ(p)) #print "h=",h #print "fak=", h=QQ(h*h0*D2*w)/QQ(w0) return h
def class_nr_pos_def_qf(D): r""" Compute the class number of positive definite quadratic forms. For fundamental discriminants this is the class number of Q(sqrt(D)), otherwise it is computed using: Cohen 'A course in Computational Algebraic Number Theory', p. 233 """ if D>0: return 0 D4 = D % 4 if D4 == 3 or D4==2: return 0 K = QuadraticField(D) if is_fundamental_discriminant(D): return K.class_number() else: D0 = K.discriminant() Df = ZZ(D).divide_knowing_divisible_by(D0) if not is_square(Df): raise ArithmeticError,"DId not get a discrinimant * square! D={0} disc(D)={1}".format(D,D0) D2 = sqrt(Df) h0 = QuadraticField(D0).class_number() w0 = _get_w(D0) w = _get_w(D) #print "w,w0=",w,w0 #print "h0=",h0 h = 1 for p in prime_divisors(D2): h = QQ(h)*(1-kronecker(D0,p)/QQ(p)) #print "h=",h #print "fak=", h=QQ(h*h0*D2*w)/QQ(w0) return h
def test_curve(q, t, r, k, D, E): """ Description: Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ bool = True bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r bool = bool and (E.trace_of_frobenius() == t) bool = bool and (kronecker( (t * t - 4 * q) * Integer(D).inverse_mod(q), q) == 1) bool = bool and (E.cardinality() == q + 1 - t) bool = bool and (E.cardinality() % r == 0) return bool
def test_curve(q,t,r,k,D,E): """ Description: Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ bool = True bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r bool = bool and (E.trace_of_frobenius() == t) bool = bool and (kronecker((t*t-4*q) * Integer(D).inverse_mod(q),q) == 1) bool = bool and (E.cardinality() == q+1-t) bool = bool and (E.cardinality() % r ==0) return bool
def eta_conjugated(a,b,c,d,l): r""" Gives eta(V_l A V_l^-1) with A=(a,b,c,d) for c>0 """ assert c>=0 and (c%l)==0 if l<>1: cp = QQ(c)/QQ(l) bp = QQ(b)*QQ(l) else: cp=c; bp=b if c==0: l*bp,1 res = (a+d)*cp-bp*d*(cp*cp-1) if is_odd(c): return res-3*cp,kronecker(d,cp) else: return res+3*d-3-3*cp*d,kronecker(cp,d)
def make_curve(k, D): """ Description: Find all MNT curves with embedding degree k and fundamental discriminant D Input: k - embedding degree D - (negative) fundamental discriminant Output: curves - list of the aforementioned elliptic curves; each curve is represented as a tuple (q,t,r,k,D) """ assert k == 3 or k == 4 or k == 6, 'Invalid embedding degree' assert fundamental_discriminant(D) == D, 'Invalid discriminant' if k == 3: curves = _mnt_subcall( k, D, 24, lambda x: ( (x % 24 == 19) and kronecker(6, x) == 1), 6, 3, -3, lambda x: (x - 3) // 6, lambda x: (x + 3) // 6, lambda l: 6 * l - 1, lambda l: -6 * l - 1, lambda l: 12 * l * l - 1) if k == 4: curves = _mnt_subcall( k, D, -8, lambda x: ((x % 8 == 3) and kronecker(-2, x) == 1) or (x == 2) or (x == 8), 3, 2, 1, lambda x: (x - 2) // 3, lambda x: (x - 1) // 3, lambda l: -l, lambda l: l + 1, lambda l: l * l + l + 1) if k == 6: curves = _mnt_subcall(k, D, -8, lambda x: (x % 8 == 3) and kronecker(-2, x) == 1, 6, 5, 1, lambda x: (x + 1) // 6, lambda x: (x - 1) // 6, lambda l: 2 * l + 1, lambda l: -2 * l + 1, lambda l: 4 * l * l + 1) for c in curves: assert is_valid_curve(c[0], c[1], c[2], c[3], c[4]), 'Invalid output' assert k == c[3], 'Bug in code' assert D == c[4], 'Bug in code' return curves
def compare_formulas_2(D, k): d1 = old_div(RR(abs(D)), RR(6)) if D < 0: D = -D s1 = RR( sqrt(abs(D)) * sum([ log(d) for d in divisors(D) if is_fundamental_discriminant(-d) and kronecker(-d, old_div(D, d)) == 1 ])) d2 = RR((old_div(2, (sqrt(3) * pi))) * s1) return d1 - d2, d2, RR(2 * sqrt(D) * log(D) / pi)
def _action(self,A): [a,b,c,d]=A v=kronecker(c,d)*self._one ### I want the type of the result always be a number field element if(d % 4 == 3): v=-v*self._i elif (c % 4 <> 0): raise ValueError,"Only use theta multiplier for 4|c!" if self._character<>None: v = self._character(d)*v if self._is_dual: v = v**-1 return v
def test_promise(r,k,D): """ Description: Tests that r,k,D is a valid input to the Cocks-Pinch method Input: r - prime k - embedding degree D - (negative) funadmental discriminant Output: bool - true iff (r,k,D) is a valid input to the Cocks-Pinch method """ bool = (kronecker(D,r) == 1) # D is a square mod r bool = bool and ( (r-1) % k ==0) # k | r-1 bool = bool and (D == fundamental_discriminant(D)) # check that D is a fundamental discriminant return bool
def test_promise(r, k, D): """ Description: Tests that r,k,D is a valid input to the Cocks-Pinch method Input: r - prime k - embedding degree D - (negative) funadmental discriminant Output: bool - true iff (r,k,D) is a valid input to the Cocks-Pinch method """ bool = (kronecker(D, r) == 1) # D is a square mod r bool = bool and ((r - 1) % k == 0) # k | r-1 bool = bool and (D == fundamental_discriminant(D) ) # check that D is a fundamental discriminant return bool
def _generate_s(bases, k2, k3): s = [] for b in bases: s_b = set() for p in range(1, 4 * b, 2): if kronecker(b, p) == -1: s_b.add(p) s.append(s_b) for i in range(len(s)): mod = 4 * bases[i] inv2 = pow(k2, -1, mod) inv3 = pow(k3, -1, mod) s2 = set() s3 = set() for z in s[i]: s2.add(inv2 * (z + k2 - 1) % mod) s3.add(inv3 * (z + k3 - 1) % mod) s[i] &= s2 & s3 return s
def _dimension_formula(self,k,eps=1,cuspidal=1): ep = 0 N = self._N if (2*k) % 4 == 1: ep = 1 if (2*k) % 4 == 3: ep = -1 if ep==0: return 0,0 if eps==-1: ep = -ep twok = ZZ(2*k) K0 = 1 sqf = ZZ(N).divide_knowing_divisible_by(squarefree_part(N)) if sqf>12: b2 = max(sqf.divisors()) else: b2 = 1 b = sqrt(b2) if ep==1: K0 = floor(QQ(b+2)/QQ(2)) else: # print "b=",b K0 = floor(QQ(b-1)/QQ(2)) if is_even(N): e2 = ep*kronecker(2,twok)/QQ(4) else: e2 = 0 N2 = odd_part(N) N22 = ZZ(N).divide_knowing_divisible_by(N2) k3 = kronecker(3,twok) if gcd(3,N)>1: if eps==1: e3 = -ep*kronecker(-3,4*k+ep-1)/QQ(3) else: e3 = -1*ep*kronecker(-3,4*k+ep+1)/QQ(3) #e3 = -1/3*ep else: f1 = kronecker(3,2*N22)*kronecker(-12,N2) - ep f2 = kronecker(-3,twok+1) e3 = f1*f2/QQ(6) ID = QQ(N+ep)*(k-1)/QQ(12) P = 0 for d in ZZ(4*N).divisors(): dm4=d % 4 if dm4== 2 or dm4 == 1: h = 0 elif d == 3: h = QQ(1)/QQ(3) elif d == 4: h = QQ(1)/QQ(2) else: h = class_nr_pos_def_qf(-d) if self._verbose>1: print "h({0})={1}".format(d,h) if h<>0: P= P + h P = QQ(P)/QQ(4) if self._verbose>0: print "P=",P P=P + QQ(ep)*kronecker(-4,N)/QQ(8) if eps==-1: P = -P if self._verbose>0: print "P=",P # P = -2*N**2 + N*(twok+10-ep*3) +(twok+10)*ep-1 if self._verbose>0: print "ID=",ID P = P - QQ(1)/QQ(2*K0) # P = QQ(P)/QQ(24) - K0 # P = P - K0 res = ID + P + e2 + e3 if self._verbose>1: print "twok=",twok print "K0=",K0 print "ep=",ep print "e2=",e2 print "e3=",e3 print "P=",P if cuspidal==0: res = res + K0 return res #,ep
def _dimension_formula(self,k,eps=1,cuspidal=1): ep = 0 N = self._N if (2*k) % 4 == 1: ep = 1 if (2*k) % 4 == 3: ep = -1 if ep==0: return 0,0 if eps==-1: ep = -ep twok = ZZ(2*k) K0 = 1 sqf = ZZ(N).divide_knowing_divisible_by(squarefree_part(N)) if sqf>12: b2 = max(sqf.divisors()) else: b2 = 1 b = sqrt(b2) if ep==1: K0 = floor(QQ(b+2)/QQ(2)) else: # print "b=",b K0 = floor(QQ(b-1)/QQ(2)) if is_even(N): e2 = ep*kronecker(2,twok)/QQ(4) else: e2 = 0 N2 = odd_part(N) N22 = ZZ(N).divide_knowing_divisible_by(N2) k3 = kronecker(3,twok) if gcd(3,N)>1: if eps==1: e3 = -ep*kronecker(-3,4*k+ep-1)/QQ(3) else: e3 = -1*ep*kronecker(-3,4*k+ep+1)/QQ(3) #e3 = -1/3*ep else: f1 = kronecker(3,2*N22)*kronecker(-12,N2) - ep f2 = kronecker(-3,twok+1) e3 = f1*f2/QQ(6) ID = QQ(N+ep)*(k-1)/QQ(12) P = 0 for d in ZZ(4*N).divisors(): dm4=d % 4 if dm4== 2 or dm4 == 1: h = 0 elif d == 3: h = QQ(1)/QQ(3) elif d == 4: h = QQ(1)/QQ(2) else: h = class_nr_pos_def_qf(-d) if self._verbose>1: print("h({0})={1}".format(d,h)) if h!=0: P= P + h P = QQ(P)/QQ(4) if self._verbose>0: print("P={0}".format(P)) P=P + QQ(ep)*kronecker(-4,N)/QQ(8) if eps==-1: P = -P if self._verbose>0: print("P={0}".format(P)) # P = -2*N**2 + N*(twok+10-ep*3) +(twok+10)*ep-1 if self._verbose>0: print("ID={0}".format(ID)) P = P - QQ(1)/QQ(2*K0) # P = QQ(P)/QQ(24) - K0 # P = P - K0 res = ID + P + e2 + e3 if self._verbose>1: print("twok={0}".format(twok)) print("K0={0}".format(K0)) print("ep={0}".format(ep)) print("e2={0}".format(e2)) print("e3={0}".format(e3)) print("P={0}".format(P)) if cuspidal==0: res = res + K0 return res #,ep
def compare_formulas_2(D, k): d1 = old_div(RR(abs(D)), RR(6)) if D < 0: D = -D s1 = RR( sqrt(abs(D)) * sum([ log(d) for d in divisors(D) if is_fundamental_discriminant(-d) and kronecker(-d, old_div(D, d)) == 1 ])) d2 = RR((old_div(2, (sqrt(3) * pi))) * s1) return d1 - d2, d2, RR(2 * sqrt(D) * log(D) / pi) A3 = lambda N: sum( [kronecker(-N, x) for x in Zmod(N) if x**2 + x + Zmod(N)(1) == 0]) def compare_formulas_2a(D, k): d1 = dimension_new_cusp_forms(kronecker_character(D), k) if D < 0: D = -D d2 = RR(1 / pi * sqrt(D) * sum([ log(d) * sigma(old_div(D, d), 0) for d in divisors(D) if Zmod(d) (old_div(D, d)).is_square() and is_fundamental_discriminant(-d) ])) return d1 - d2 def compare_formulas_3(D, k): d1 = dimension_cusp_forms(kronecker_character(D), k)