1 //==============================================================================================
2 //
3 //	This file is part of LiDIA --- a library for computational number theory
4 //
5 //	Copyright (c) 1994--2001 the LiDIA Group.  All rights reserved.
6 //
7 //	See http://www.informatik.tu-darmstadt.de/TI/LiDIA/
8 //
9 //----------------------------------------------------------------------------------------------
10 //
11 //	$Id$
12 //
13 //	Author	: Nigel Smart, John Cremona
14 //                Adaption of John Cremona's code; some code came
15 //                originally from Oisin McGuiness
16 //	Changes	: See CVS log
17 //
18 //==============================================================================================
19 
20 
21 #ifdef HAVE_CONFIG_H
22 # include	"config.h"
23 #endif
24 #include	"LiDIA/bigint.h"
25 #include	"LiDIA/bigfloat.h"
26 #include	"LiDIA/nmbrthry_functions.h"
27 #include	"LiDIA/base_vector.h"
28 
29 #include	"LiDIA/elliptic_curve_bigint.h"
30 #include	"LiDIA/point_bigint.h"
31 
32 
33 
34 #ifdef LIDIA_NAMESPACE
35 namespace LiDIA {
36 #endif
37 
38 
39 
40 //
41 // ctors' and d'tor
42 //
43 
point()44 point< bigint >::point()
45 	: x(0),
46 	  y(0),
47 	  z(0),
48 	  height(0),
49 	  ord(0)
50 {
51 	ec = new elliptic_curve< bigint > ();
52 }
53 
54 
55 
point(const bigint & xp,const bigint & yp,const elliptic_curve<bigint> & ecp)56 point< bigint >::point(const bigint & xp,
57 		       const bigint & yp,
58 		       const elliptic_curve< bigint > &ecp)
59 
60 	: x(xp),
61 	  y(yp),
62 	  z(1),
63 	  height(-1),
64 	  ord(0)
65 
66 {
67 	ec = new elliptic_curve< bigint > (ecp);
68 }
69 
70 
71 
point(const bigint & xp,const bigint & yp,const bigint & zp,const elliptic_curve<bigint> & ecp)72 point< bigint >::point(const bigint & xp,
73 			const bigint & yp,
74 			const bigint & zp,
75 			const elliptic_curve< bigint > &ecp)
76 
77 	: x(xp),
78 	  y(yp),
79 	  z(zp),
80 	  height(-1),
81 	  ord(0)
82 
83 {
84 	ec = new elliptic_curve< bigint > (ecp);
85 	reduce();
86 }
87 
88 
89 
point(const point<bigint> & P)90 point< bigint >::point(const point< bigint > & P)
91 
92 	: x(P.x),
93 	  y(P.y),
94 	  z(P.z),
95 	  height(P.height),
96 	  ord(P.ord)
97 
98 {
99 	ec = new elliptic_curve< bigint > (*(P.ec));
100 }
101 
102 
103 
point(const elliptic_curve<bigint> & e)104 point< bigint >::point(const elliptic_curve< bigint > &e)
105 
106 	: x(0),
107 	  y(1),
108 	  z(0),
109 	  height(0),
110 	  ord(1)
111 
112 {
113 	ec = new elliptic_curve< bigint > (e);
114 }
115 
116 
117 
~point()118 point< bigint >::~point()
119 {
120 	delete ec;
121 }
122 
123 
124 
125 //
126 // Access
127 //
128 
129 elliptic_curve< bigint >
get_curve() const130 point< bigint >::get_curve() const
131 {
132 	return *ec;
133 }
134 
135 
136 
137 //
138 // Assignment
139 //
140 
141 void
assign_zero(const elliptic_curve<bigint> & e)142 point< bigint >::assign_zero(const elliptic_curve< bigint > & e)
143 {
144 	ec->assign(e);
145 	z.assign_zero();
146 	y.assign_one();
147 	x.assign_zero();
148 	height = 0;
149 	ord = 1;
150 }
151 
152 
153 
154 void
assign(const point<bigint> & P)155 point< bigint >::assign(const point< bigint > & P)
156 {
157 	if (&P != this) {
158 		ec->assign(*(P.ec));
159 		x = P.x;
160 		y = P.y;
161 		z = P.z;
162 		height = P.height;
163 		ord = P.ord;
164 	}
165 }
166 
167 
168 
169 void
assign(const bigint & xx,const bigint & yy,const elliptic_curve<bigint> & e)170 point< bigint >::assign(const bigint & xx, const bigint & yy, const
171 			elliptic_curve< bigint > & e)
172 {
173 	ec->assign(e);
174 	x = xx;
175 	y = yy;
176 	z.assign_one();
177 	height = -1;
178 	ord = 0;
179 }
180 
181 
182 
183 void
assign(const bigint & xx,const bigint & yy,const bigint & zz,const elliptic_curve<bigint> & e)184 point< bigint >::assign(const bigint & xx, const bigint & yy, const bigint &zz,
185 			const elliptic_curve< bigint > & e)
186 {
187 	ec->assign(e);
188 	x = xx;
189 	y = yy;
190 	z = zz;
191 	height = -1;
192 	ord = 0;
193 }
194 
195 
196 
197 // assign on last curve (use with care of course)
198 void
assign_zero()199 point< bigint >::assign_zero()
200 {
201 	z.assign_zero();
202 	y.assign_one();
203 	x.assign_zero();
204 	height = 0;
205 	ord = 1;
206 }
207 
208 
209 
210 void
assign(const bigint & xx,const bigint & yy)211 point< bigint >::assign(const bigint & xx, const bigint & yy)
212 {
213 	x = xx;
214 	y = yy;
215 	z.assign_one();
216 	height = -1;
217 	ord = 0;
218 }
219 
220 
221 
222 void
assign(const bigint & xx,const bigint & yy,const bigint & zz)223 point< bigint >::assign(const bigint & xx, const bigint & yy, const bigint &zz)
224 {
225 	x = xx;
226 	y = yy;
227 	z = zz;
228 	height = -1;
229 	ord = 0;
230 }
231 
232 
233 
234 void
swap(point<bigint> & P)235 point< bigint >::swap(point< bigint > & P)
236 {
237 	LiDIA::swap(x, P.x);
238 	LiDIA::swap(y, P.y);
239 	LiDIA::swap(z, P.z);
240 	LiDIA::swap(height, P.height);
241 
242 	int te = P.ord;
243 	P.ord = ord;
244 	ord = te;
245 
246 	elliptic_curve< bigint > * e = P.ec;
247 	P.ec = ec;
248 	ec = e;
249 }
250 
251 
252 
253 void
reduce()254 point< bigint >::reduce()
255 {
256 	if (z.is_zero()) {
257 		x = 0;
258 		y = 1;
259 		return;
260 	}
261 	if (z.is_one()) {
262 		return;
263 	}
264 
265 	bigint d = gcd(x, y);
266 	if (!d.is_one())
267 		d = gcd(d, z); // now d = gcd(x, y, z)
268 	if (d.is_zero()) {
269 		lidia_error_handler("point< bigint >", "reduce::Invalid point");
270 	}
271 	if (!d.is_one()) {
272 		x /= d;
273 		y /= d;
274 		z /= d;
275 	}
276 	if (z.is_lt_zero()) {
277 		x.negate();
278 		y.negate();
279 		z.negate();
280 	}
281 }
282 
283 
284 
285 //
286 // Testing points
287 //
288 
289 bool
is_equal(const point<bigint> & P) const290 point< bigint >::is_equal (const point< bigint > & P) const
291 {
292 	if (*(P.ec) != *(ec))
293 		return false;
294 
295 	bigint temp(P.x*z - P.z*x);
296 
297 	if (!temp.is_zero()) {
298 		return false;
299 	}
300 
301 	temp = P.y*z - P.z*y;
302 	if (!temp.is_zero()) {
303 		return false;
304 	}
305 
306 	temp = P.y*x - P.x*y;
307 	return temp.is_zero();
308 }
309 
310 
311 
312 bool
on_curve() const313 point< bigint >::on_curve() const
314 {
315 	if (x.is_zero() && y.is_zero() && z.is_zero()) {
316 		return 0;
317 	}
318 	if (z.is_zero()) {
319 		return 1;
320 	}
321 	// should calculate
322 	//                       y^2 +a1 x y + a3 y
323 	//  and
324 	//                       x^3 + a2 x^2 + a4 x + a6
325 	// where
326 	//          x = X/Z, y = Y/Z
327 	// and verify equality.
328 	//
329 	// In homogeneous coordinates:
330 	//
331 	// Lhs = Y^2 Z + a1 XYZ + a3 YZ^2 = (YZ) *(Y + a1 X + a3 Z)
332 	//
333 	//
334 	// Rhs = X^3 +a2 X^2 Z + a4 X Z^2 + a6 Z^3
335 	//
336 	const bigint& Lhs = y*z*(y + ec->get_a1()*x + ec->get_a3()*z);
337 	const bigint& Rhs = ec->get_a6()*z*z*z+x*(ec->get_a4()*z*z+x*(ec->get_a2()*z + x));
338 	return Lhs == Rhs;
339 }
340 
341 
342 
343 //
344 // Arithmetic
345 //
346 
347 void
add(point<bigint> & R,const point<bigint> & P,const point<bigint> & Q)348 add(point< bigint > & R,
349     const point< bigint > & P,
350     const point< bigint > & Q)
351 {
352 	if (*(P.ec) != *(Q.ec))
353 		lidia_error_handler("point< bigint >", "add::different elliptic curves");
354 
355 	if (Q.z.is_zero()) {
356 		R.assign(P);
357 		return;
358 	}
359 	if (P.z.is_zero()) {
360 		R.assign(Q);
361 		return;
362 	}
363 	if (P == Q)
364 		(P.ec)->get_point_operations()._mult_by_2(R, P);
365 	else
366 		(P.ec)->get_point_operations()._add(R, P, Q);
367 }
368 
369 
370 
371 void
subtract(point<bigint> & R,const point<bigint> & P,const point<bigint> & Q)372 subtract(point< bigint > & R,
373 	 const point< bigint > & P,
374 	 const point< bigint > & Q)
375 {
376 	point< bigint > H;
377 	negate(H, Q);
378 	add(R, P, H);
379 }
380 
381 
382 
383 void
multiply_by_2(point<bigint> & R,const point<bigint> & P)384 multiply_by_2(point< bigint > & R, const point< bigint > & P)
385 {
386 	if (P.z.is_zero()) {
387 		R.assign(P);
388 		return;
389 	}
390 	(P.ec)->get_point_operations()._mult_by_2(R, P);
391 }
392 
393 
394 
395 void
multiply(point<bigint> & R,const bigint & mm,const point<bigint> & P)396 multiply (point< bigint > & R, const bigint & mm, const point< bigint > & P)
397 {
398 	bigint m(mm);
399 	point< bigint > Z(P);
400 
401 	R.assign(P);
402 
403 	if (m.is_negative()) {
404 		m.negate();
405 		negate(Z, Z);
406 		negate(R, R);
407 	}
408 
409 	if (P.z.is_zero() || mm.is_zero()) {
410 		R.assign(*(P.ec));
411 		return;
412 	}
413 
414 	if (mm.is_one())
415 		return;
416 
417 	int i = static_cast<int>(m.bit_length())-2; // note m >= 2
418 
419 	while (i >= 0) {
420 		multiply_by_2(R, R);
421 		if (m.bit(i))
422 			add(R, R, Z);
423 		i--;
424 	}
425 }
426 
427 
428 
429 void
negate(point<bigint> & r,const point<bigint> & x)430 negate(point< bigint > & r, const point< bigint > & x)
431 {
432 	(r.ec)->assign(*(x.ec));
433 	(x.ec)->get_point_operations()._negate(r, x);
434 }
435 
436 
437 
438 // Advanced Functions
439 
440 bigfloat
get_naive_height() const441 point< bigint >::get_naive_height() const
442 {
443 	if (z.is_zero()) {
444 		return 0;
445 	}
446 	bigint g = gcd(x, z);
447 	bigfloat xx = abs(x/g);
448 	if (abs(z/g) > abs(x/g)) {
449 		xx = abs(z/g);
450 	}
451 	return log(xx);
452 }
453 
454 
455 
456 bigfloat
get_height()457 point< bigint >::get_height()
458 {
459 	// WARNING -- no check made of validity of point on curve
460 	if (z.is_zero())
461 		return bigfloat(0.0);
462 	if (height >= 0.0) return height; // already calculated it
463 	// zero height if torsion
464 	if (get_order() > 0) {
465 		height = bigfloat(0.0);
466 		return height;
467 	}
468 
469 	// N.B. So if we ever ask a point its height it will compute its order.
470 	// otherwise need to calculate it
471 
472 // Add local heights at finite primes dividing discr(E) OR denom(P).
473 // The components for primes dividing denom(P) add to log(denom(x(P)));
474 //   since P=(XZ:Y:Z^3), denom(P)=Z=gcd(XZ,Z^3), called "zroot" here,
475 //   and so the contribution is log(denom(x(P))) = 2*log(zroot).
476 //   This avoids factorizing the denominator.
477 
478 	bigint p;
479 	bigint zroot(gcd(x, z)); // = cube root of Z
480 	bigfloat ans(get_realheight() + 2*log(bigfloat(zroot)));
481 
482 	long i;
483 	base_vector< bigint > bp = ec->get_bad_primes();
484 
485 	for (i = 0; i < bp.get_size(); i++) {
486 		p = bp[i];
487 		if (!is_divisor(p, zroot))
488 			ans += get_pheight(p);
489 	}
490 
491 	height = ans;
492 	return ans;
493 }
494 
495 
496 
497 bigfloat
get_pheight(const bigint & pr) const498 point< bigint >::get_pheight(const bigint& pr) const
499 {
500 	bigint a1, a2, a3, a4, a6, b2, b4, b6, b8, c4, c6, discr;
501 
502 	ec->get_ai(a1, a2, a3, a4, a6);
503 	ec->get_bi(b2, b4, b6, b8);
504 	ec->get_ci(c4, c6);
505 
506 	discr = ec->discriminant();
507 	long n = valuation(pr, discr);
508 
509 	const bigint& zroot = gcd(x, z); // = cube root of z
510 	long vpz = 3*valuation(pr, zroot);
511 
512 	const bigint& x2 = x*x;
513 	const bigint& z2 = z*z;
514 	const bigint& xz = x*z;
515 	const bigint& yz = y*z;
516 	long a = valuation(pr, 3*x2 + 2*a2*xz + a4*z2 - a1*yz) - 2*vpz;
517 	long b = valuation(pr, 2*y + a1*x + a3*z) - vpz;
518 	long c = valuation(pr, 3*x2*x2 + b2*x2*xz + 3*b4*x2*z2 + 3*b6*xz*z2 + b8*z2*z2) -4*vpz;
519 
520 // some obvious changes enable calculation of lambda as a rational
521 // some improvements can be made if this is never to be done
522 // eg in the above, no need to work with projective coords, just use real x/z
523 	bigfloat halfn = n; halfn /= 2;
524 	bigfloat lambda;
525 
526 	if ((a <= 0) || (b <= 0)) {
527 		lambda = vpz - valuation(pr, x);
528 		if (lambda < 0)
529 			lambda = 0;
530 	}
531 	else if (!is_divisor(pr, c4)) {
532 		bigfloat m(b);
533 		if (halfn < m)
534 			m = halfn; // m = min(b , halfn);
535 		lambda = (m*(m-n)) / n;
536 	}
537 	else if (c >= (3*b))
538 		lambda = (-2*b) / bigfloat(3.0);
539 	else
540 		lambda = -c / bigfloat(4.0);
541 
542 	bigfloat ans(lambda * log(bigfloat(pr)));
543 	return ans;
544 }
545 
546 
547 
548 bigfloat
get_realheight() const549 point< bigint >::get_realheight() const
550 {
551 	bigfloat xx(bigfloat(x)/bigfloat(z));
552 	return real_height(*ec, xx);
553 }
554 
555 
556 
557 int
get_order()558 point< bigint >::get_order()
559 {
560 	if (ord) {
561 		return ord;
562 	}
563 	if (z.is_zero()) {
564 		ord = 1;
565 		return 1;
566 	}
567 	point< bigint > q = (*this);
568 	ord = 1;
569 	bigint eight(8);
570 	while (!q.is_zero() && (q.z <= eight)) {
571 		// (worst denom of a torsion point)
572 		ord++; add(q, q, (*this));
573 	}
574 	if (!q.is_zero())
575 		ord = -1;
576 	return ord;
577 }
578 
579 
580 
581 int
order(point<bigint> & P,base_vector<point<bigint>> & list)582 order(point< bigint > & P, base_vector< point < bigint > > & list)
583 {
584 	list.set_size(0);
585 	list.set_capacity(12);
586 // NB Don't set P.ord until its correct value is known,
587 // otherwise Q's ord gets set wrongly
588 	list[0] = point< bigint > (*(P.ec));
589 	if (P.is_zero()) {
590 		P.ord = 1;
591 		return 1;
592 	}
593 	long ord = 2; list[1] = P;
594 	bigint eight(8);
595 	point< bigint > Q = P;
596 	while (!(Q.is_zero()) && (Q.z <= eight) && (ord < 13)) {
597 		add(Q, Q, P);
598 		if (!(Q.is_zero()))
599 			list[ord++] = Q;
600 	}
601 
602 	if (!(Q.is_zero()))
603 		ord = -1;
604 	P.ord = ord;
605 	return ord;
606 }
607 
608 
609 
610 //
611 // I/O
612 //
613 
614 void
read(std::istream & in)615 point< bigint >::read (std::istream & in)
616 {
617 	char c;
618 	in.flags(in.flags() | std::ios::dec); //force decimal input (bug fix)
619 	in >> c;
620 	switch(c) {
621 	case '(':
622 		in >> x >> c >> y >> c;
623 		z.assign_one();
624 		break;
625 	case '[':
626 		in >> x >> c >> y >> c >> z >> c;
627 		break;
628 	}
629 	ord = 0; height = -1.0;
630 	if (on_curve())
631 		reduce();
632 	else
633 		lidia_error_handler("point< bigint >", "read >>::not on curve");
634 }
635 
636 
637 
638 void
write(std::ostream & out) const639 point< bigint >::write (std::ostream & out) const
640 {
641 	out << "[" << x << " : " << y << " : " << z << "]";
642 }
643 
644 
645 
646 #ifdef LIDIA_NAMESPACE
647 }	// end of namespace LiDIA
648 #endif
649