Explicit-Formulas Database

Tripling-oriented Doche/Icart/Kohel curves

An elliptic curve in tripling-oriented Doche/Icart/Kohel form is a curve of the form y^2 = x^3 + 3a(x+1)^2, where a(4a-9) is nonzero. The neutral element of the curve is the point at infinity.

Tripling-oriented Doche/Icart/Kohel coordinates represent an affine point (x,y) on a tripling-oriented Doche/Icart/Kohel-form elliptic curve y^2 = x^3 + 3a(x+1)^2 as (X:Y:Z:ZZ) satisfying Y^2 = X^3 + 3aZ^2(X+Z^2)^2 and ZZ = Z^2. Here (X:Y:Z:ZZ) = (s^2 X:s^3 Y:sZ:s^2 ZZ) for all nonzero s.

Speed records:

The following commands for the Magma computer-algebra system check various addition formulas for tripling-oriented Doche/Icart/Kohel coordinates.

Tripling-oriented Doche/Icart/Kohel scaling.

     K<a,X1,Y1,X2,Y2>:=FieldOfFractions(PolynomialRing(Rationals(),5));
     R<Z1,Z2>:=PolynomialRing(K,2);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     // here are the formulas:
     A:=1/Z1;
     AA:=A^2;
     X2:=X1*AA;
     Y2:=Y1*AA*A;
     Z2:=1;
     // check:
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     S!(y1^2-x1^3-3*a*(x1+1)^2);
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     S!(y2^2-x2^3-3*a*(x2+1)^2);
     S!(Z2-1);
     S!(x2-x1); S!(y2-y1);

Tripling-oriented Doche/Icart/Kohel addition (11M+6S+1D+13add+2times2+1times3+1times8+1times16) matches traditional addition. S,M counts stated in the literature: 11M + 6S in 2007 Bernstein/Birkner/Lange/Peters.

2006 Doche/Icart/Kohel, page 199, top display, Z2 set to 1, affine only:

     K<a,x1,x2>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<y1,y2>:=PolynomialRing(K,2);
     S:=quo<R|y1^2-x1^3-3*a*(x1+1)^2,y2^2-x2^3-3*a*(x2+1)^2>;
     X1:=x1; Y1:=y1; Z1:=1;
     X2:=x2; Y2:=y2; Z2:=1;
     // here are the formulas:
     // uncached:
     A:=X1;
     B:=Y1;
     C:=X2-A;
     D:=Y2-B;
     Z3:=C;
     E:=Z3^2;
     F:=C^2;
     G:=C*F;
     H:=A*F;
     X3:=D^2-G-3*a*E-2*H;
     Y3:=D*(H-X3)-B*G;
     Z3Z3:=E;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
Simplified, projectified:
     K<a,X1,Y1,X2,Y2>:=FieldOfFractions(PolynomialRing(Rationals(),5));
     R<Z1,Z2>:=PolynomialRing(K,2);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     S!(y1^2-x1^3-3*a*(x1+1)^2);
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     S!(y2^2-x2^3-3*a*(x2+1)^2);
     // here are the formulas:
     D:=Y2/Z2^3-Y1/Z1^3;
     Z3:=X2/Z2^2-X1/Z1^2;
     X3:=D^2-Z3^3-3*a*Z3^2-2*Z3^2*X1/Z1^2;
     Y3:=D*(Z3^2*X1/Z1^2-X3)-Z3^3*Y1/Z1^3;
     // back to affine:
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
Denominators cleared:
     K<a,X1,Y1,X2,Y2>:=FieldOfFractions(PolynomialRing(Rationals(),5));
     R<Z1,Z2>:=PolynomialRing(K,2);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     S!(y1^2-x1^3-3*a*(x1+1)^2);
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     S!(y2^2-x2^3-3*a*(x2+1)^2);
     // here are the formulas:
     A:=X2*Z1^2-X1*Z2^2;
     B:=Y2*Z1^3-Y1*Z2^3;
     X3:=B^2-A^3-Z1^2*Z2^2*3*a*A^2-Z2^2*2*A^2*X1;
     Y3:=B*(Z2^2*A^2*X1-X3)-Z2^3*A^3*Y1;
     Z3:=Z1*Z2*A;
     // back to affine:
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
Common subexpressions eliminated, 13M + 4S + 1D + 7add + 1times2 + 1times3:
     K<a,X1,Y1,X2,Y2>:=FieldOfFractions(PolynomialRing(Rationals(),5));
     R<Z1,Z2>:=PolynomialRing(K,2);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     S!(y1^2-x1^3-3*a*(x1+1)^2);
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     S!(y2^2-x2^3-3*a*(x2+1)^2);
     // already provided as part of input:
     Z1Z1:=Z1^2;
     Z2Z2:=Z2^2;
     // here are the formulas:
     A:=X2*Z1Z1-X1*Z2Z2;
     B:=Y2*Z1*Z1Z1-Y1*Z2*Z2Z2;
     C:=Z2*A;
     CC:=C^2;
     D:=X1*CC;
     Z3:=Z1*C;
     E:=Z3^2;
     X3:=B^2-A*A^2-3*a*E-2*D;
     Y3:=B*(D-X3)-Y1*C*CC;
     Z3Z3:=E;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2007 Bernstein/Birkner/Lange/Peters, 11M + 6S + 1D + 13add + 2times2 + 1times3 + 1times8 + 1times16:
     K<a,X1,Y1,X2,Y2>:=FieldOfFractions(PolynomialRing(Rationals(),5));
     R<Z1,Z2>:=PolynomialRing(K,2);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     S!(y1^2-x1^3-3*a*(x1+1)^2);
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     S!(y2^2-x2^3-3*a*(x2+1)^2);
     // already provided as part of input:
     Z1Z1:=Z1^2;
     Z2Z2:=Z2^2;
     // cached:
     Z2Z2Z2:=Z2*Z2Z2;
     // uncached:
     Z1Z1Z1:=Z1*Z1Z1;
     A:=X2*Z1Z1-X1*Z2Z2;
     B:=Y2*Z1Z1Z1-Y1*Z2Z2Z2;
     AA:=A^2;
     C:=(Z2+A)^2-Z2Z2-AA;
     CC:=C^2;
     CC8:=8*CC;
     D:=X1*CC8;
     Z3:=(Z1+C)^2-Z1Z1-CC;
     E:=Z3^2;
     X3:=16*(B^2-A*AA)-D-3*a*E;
     Y3:=2*B*(D-2*X3)-Y1*C*CC8;
     Z3Z3:=E;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);

Tripling-oriented Doche/Icart/Kohel mixed addition (7M+4S+1D+10add+3times2+1times3+1times4) matches traditional addition. S,M,D counts stated in the literature: 8M+3S+1D in 2006 Doche/Icart/Kohel ("8M+3S to compute an addition. If u is a random element in the field, then an extra multiplication is required"). 7M+4S+1D in 2007 Bernstein/Lange.

2006 Doche/Icart/Kohel, page 199, top display, roles of 1 and 2 reversed, 8M+3S+1D+7add+1times2+1times3:

     K<a,X1,Y1,X2>:=FieldOfFractions(PolynomialRing(Rationals(),4));
     R<Z1,Y2>:=PolynomialRing(K,2);
     Z2:=1;
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     // here are the formulas:
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // uncached:
     A:=X2*Z1Z1;
     B:=Y2*Z1Z1*Z1;
     C:=X1-A;
     D:=Y1-B;
     Z3:=Z1*C;
     E:=Z3^2;
     F:=C^2;
     G:=C*F;
     H:=A*F;
     X3:=D^2-G-3*a*E-2*H;
     Y3:=D*(H-X3)-B*G;
     Z3Z3:=E;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2007 Bernstein/Birkner/Lange/Peters, 7M+4S+1D+10add+3times2+1times3+1times4:
     K<a,X1,Y1,X2>:=FieldOfFractions(PolynomialRing(Rationals(),4));
     R<Z1,Y2>:=PolynomialRing(K,2);
     Z2:=1;
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     // here are the formulas:
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // uncached:
     A:=X2*Z1Z1;
     B:=Y2*Z1Z1*Z1;
     C:=X1-A;
     D:=2*(Y1-B);
     F:=C^2;
     F4:=4*F;
     Z3:=(Z1+C)^2-Z1Z1-F;
     E:=Z3^2;
     G:=C*F4;
     H:=A*F4;
     X3:=D^2-G-2*H-3*a*E;
     Y3:=D*(H-X3)-2*B*G;
     Z3Z3:=E;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);

Tripling-oriented Doche/Icart/Kohel addition with Z1=1 and Z2=1 (4M + 2S + 1D + 7add + 4times2 + 1times3 + 1times4) matches traditional addition. S,M,D counts stated in the literature: 8M+3S+1D in 2007 Bernstein/Lange.

2007 Bernstein/Birkner/Lange/Peters, 4M + 2S + 1D + 7add + 4times2 + 1times3 + 1times4:

     K<a,X1,Y1,X2>:=FieldOfFractions(PolynomialRing(Rationals(),4));
     R<Z1,Y2>:=PolynomialRing(K,2);
     Z1:=1; Z2:=1;
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2,Y2^2-X2^3-3*a*Z2^2*(X2+Z2^2)^2>;
     // here are the formulas:
     // uncached:
     C:=X1-X2;
     D:=2*(Y1-Y2);
     F:=C^2;
     F4:=4*F;
     Z3:=2*C;
     G:=C*F4;
     H:=X2*F4;
     X3:=D^2-G-2*H-3*a*F4;
     Y3:=D*(H-X3)-2*Y2*G;
     Z3Z3:=F4;
     // back to affine:
     Z3Z3-Z3^2;
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     x2:=X2/Z2^2; y2:=Y2/Z2^3;
     lambda:=(y2-y1)/(x2-x1);
     r3:=lambda^2-3*a-x1-x2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);

Tripling-oriented Doche/Icart/Kohel doubling (2M + 7S + 2D + 12add + 3times2 + 2times3 + 1times8) matches traditional doubling. S,M,D counts stated in the literature: 4M+5S+2D in 2006 Doche/Icart/Kohel ("4M+5S as long as we neglect multiplications by u, otherwise a doubling can be obtained with 6M+4S"; no explanation of the 4S). 2M+7S+2D in 2007 Bernstein/Birkner/Lange/Peters.

2006 Doche/Icart/Kohel, page 198, bottom display, corrected by 2007 Bernstein/Birkner/Lange/Peters to incorporate the missing -3a term:

     K<a,x1>:=FieldOfFractions(PolynomialRing(Rationals(),2));
     R<y1>:=PolynomialRing(K,1);
     S:=quo<R|y1^2-x1^3-3*a*(x1+1)^2>;
     x2:=x1; y2:=y1;
     X1:=x1; Y1:=y1; Z1:=1;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     // warning: 2006 Doche/Icart/Kohel is missing -3*a*Z3Z3
     A:=Y1*Z1;
     Z3:=2*A;
     B:=4*Y1^2*X1;
     C:=B+6*a*A^2;
     Z3Z3:=4*A^2;
     D:=3*X1^2;
     E:=D+6*a*Z1Z1*(Z1Z1+X1);
     X3:=E^2-2*B-3*a*Z3Z3;
     Y3:=E*(B-X3)-8*Y1^4;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r3:=lambda^2-3*a-2*x1; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2006 Doche/Icart/Kohel, page 198, bottom display, corrected by 2007 Bernstein/Birkner/Lange/Peters to incorporate the missing -3a term:
     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     // warning: 2006 Doche/Icart/Kohel is missing -3*a*Z3Z3
     A:=Y1*Z1;
     Z3:=2*A;
     B:=4*Y1^2*X1;
     C:=B+6*a*A^2;
     Z3Z3:=4*A^2;
     D:=3*X1^2;
     E:=D+6*a*Z1Z1*(Z1Z1+X1);
     X3:=E^2-2*B-3*a*Z3Z3;
     Y3:=E*(B-X3)-8*Y1^4;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r3:=lambda^2-3*a-2*x1; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2006 Doche/Icart/Kohel, page 198, bottom display, corrected by 2007 Bernstein/Birkner/Lange/Peters to incorporate the missing -3a term, unused C eliminated, common subexpressions eliminated, 4M + 5S + 2D + 6add + 2times2 + 2times3 + 1times4 + 1times6 + 1times8:
     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     Y1Y1:=Y1^2;
     A:=Y1*Z1;
     Z3:=2*A;
     B:=4*Y1Y1*X1;
     Z3Z3:=Z3^2;
     D:=3*X1^2;
     E:=D+6*a*Z1Z1*(Z1Z1+X1);
     X3:=E^2-2*B-3*a*Z3Z3;
     Y3:=E*(B-X3)-8*Y1Y1^2;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r3:=lambda^2-3*a-2*x1; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2007 Bernstein/Birkner/Lange/Peters, 2M + 7S + 2D + 12add + 3times2 + 2times3 + 1times8:
     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     A:=X1^2;
     B:=2*a*Z1Z1*(X1+Z1Z1);
     C:=3*(A+B);
     D:=Y1^2;
     E:=D^2;
     Z3:=(Y1+Z1)^2-D-Z1Z1;
     Z3Z3:=Z3^2;
     F:=2*((X1+D)^2-A-E);
     X3:=C^2-3*a*Z3Z3-2*F;
     Y3:=C*(F-X3)-8*E;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r3:=lambda^2-3*a-2*x1; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);

Tripling-oriented Doche/Icart/Kohel doubling with Z1=1 (1M + 5S + 2D + 9add + 4times2 + 2times3 + 1times4+ 1times8) matches traditional doubling. S,M,D counts stated in the literature: 1M + 5S + 2D in 2007 Bernstein/Lange.

     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     Z1:=1;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // here are the formulas:
     A:=X1^2;
     B:=2*a*(X1+1);
     C:=3*(A+B);
     D:=Y1^2;
     E:=D^2;
     Z3:=2*Y1;
     Z3Z3:=4*D;
     F:=2*((X1+D)^2-A-E);
     X3:=C^2-3*a*Z3Z3-2*F;
     Y3:=C*(F-X3)-8*E;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r3:=lambda^2-3*a-2*x1; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);

Tripling-oriented Doche/Icart/Kohel tripling (6M+6S+2D+7add+4times3+2times4+1times9) matches traditional tripling. S,M,D counts stated in the literature: 6M+6S+2D in 2006 Doche/Icart/Kohel ("6M+6S ... a multiplication by u is negligible. Otherwise, 8M+6S are necessary"). 6M+6S+2D in 2007 Bernstein/Birkner/Lange/Peters; thanks to Hisil for comments.

2006 Doche/Icart/Kohel, page 198, middle display:

     K<a,x1>:=FieldOfFractions(PolynomialRing(Rationals(),2));
     R<y1>:=PolynomialRing(K,1);
     S:=quo<R|y1^2-x1^3-3*a*(x1+1)^2>;
     x2:=x1; y2:=y1;
     X1:=x1; Y1:=y1; Z1:=1;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     A:=(X1+3*Z1Z1)^2;
     B:=a*Z1Z1*A;
     Xt:=Y1^2+B;
     Yt:=Y1*(Y1^2-3*B);
     Zt:=X1*Z1;
     C:=Zt^2;
     D:=((4*a-9)*C-Xt)^2;
     E:=-3*a*C*D;
     X3:=(Yt^2+E);
     Y3:=Yt*(X3-4*E);
     Z3:=3*Xt*Zt;
     Z3Z3:=Z3^2;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r2:=lambda^2-3*a-2*x1; s2:=lambda*(x1-r2)-y1;
     lambda:=(s2-y1)/(r2-x1);
     r3:=lambda^2-3*a-x1-r2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2006 Doche/Icart/Kohel, page 198, middle display:
     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     A:=(X1+3*Z1Z1)^2;
     B:=a*Z1Z1*A;
     Xt:=Y1^2+B;
     Yt:=Y1*(Y1^2-3*B);
     Zt:=X1*Z1;
     C:=Zt^2;
     D:=((4*a-9)*C-Xt)^2;
     E:=-3*a*C*D;
     X3:=(Yt^2+E);
     Y3:=Yt*(X3-4*E);
     Z3:=3*Xt*Zt;
     Z3Z3:=Z3^2;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r2:=lambda^2-3*a-2*x1; s2:=lambda*(x1-r2)-y1;
     lambda:=(s2-y1)/(r2-x1);
     r3:=lambda^2-3*a-x1-r2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);
2006 Doche/Icart/Kohel, page 198, middle display, common subexpressions eliminated, 6M + 6S + 2D + 7add + 4times3 + 2times4 + 1times9:
     K<a,X1,Y1>:=FieldOfFractions(PolynomialRing(Rationals(),3));
     R<Z1>:=PolynomialRing(K,1);
     S:=quo<R|Y1^2-X1^3-3*a*Z1^2*(X1+Z1^2)^2>;
     x1:=X1/Z1^2; y1:=Y1/Z1^3;
     // already provided as part of input:
     Z1Z1:=Z1^2;
     // here are the formulas:
     Y1Y1:=Y1^2;
     A:=(X1+3*Z1Z1)^2;
     B:=a*Z1Z1*A;
     Xt:=Y1Y1+B;
     Yt:=Y1*(Y1Y1-3*B);
     Zt:=X1*Z1;
     C:=Zt^2;
     Ca:=a*C;
     E:=3*Ca*(4*Ca-9*C-Xt)^2;
     X3:=Yt^2-E;
     Y3:=Yt*(X3+4*E);
     Z3:=3*Xt*Zt;
     Z3Z3:=Z3^2;
     // back to affine:
     S!(Z3Z3-Z3^2);
     x3:=X3/Z3^2; y3:=Y3/Z3^3;
     S!(y3^2-x3^3-3*a*(x3+1)^2);
     // versus traditional affine formulas:
     lambda:=(3*x1^2+6*a*x1+6*a)/(2*y1);
     r2:=lambda^2-3*a-2*x1; s2:=lambda*(x1-r2)-y1;
     lambda:=(s2-y1)/(r2-x1);
     r3:=lambda^2-3*a-x1-r2; s3:=lambda*(x1-r3)-y1;
     // check the answer:
     S!(x3-r3); S!(y3-s3);