// B.3 pg 62 public override ECPoint Twice() { if (this.IsInfinity) { return(this); } ECCurve curve = this.Curve; ECFieldElement Y1 = this.RawYCoord; if (Y1.IsZero) { return(curve.Infinity); } int coord = curve.CoordinateSystem; ECFieldElement X1 = this.RawXCoord; switch (coord) { case ECCurve.COORD_AFFINE: { ECFieldElement X1Squared = X1.Square(); ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1)); ECFieldElement X3 = gamma.Square().Subtract(Two(X1)); ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1); return(new FpPoint(Curve, X3, Y3, IsCompressed)); } case ECCurve.COORD_HOMOGENEOUS: { ECFieldElement Z1 = this.RawZCoords[0]; bool Z1IsOne = Z1.IsOne; // TODO Optimize for small negative a4 and -3 ECFieldElement w = curve.A; if (!w.IsZero && !Z1IsOne) { w = w.Multiply(Z1.Square()); } w = w.Add(Three(X1.Square())); ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1); ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1); ECFieldElement B = X1.Multiply(t); ECFieldElement _4B = Four(B); ECFieldElement h = w.Square().Subtract(Two(_4B)); ECFieldElement _2s = Two(s); ECFieldElement X3 = h.Multiply(_2s); ECFieldElement _2t = Two(t); ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square())); ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square(); ECFieldElement Z3 = Two(_4sSquared).Multiply(s); return(new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed)); } case ECCurve.COORD_JACOBIAN: { ECFieldElement Z1 = this.RawZCoords[0]; bool Z1IsOne = Z1.IsOne; ECFieldElement Y1Squared = Y1.Square(); ECFieldElement T = Y1Squared.Square(); ECFieldElement a4 = curve.A; ECFieldElement a4Neg = a4.Negate(); ECFieldElement M, S; if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3))) { ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square(); M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared))); S = Four(Y1Squared.Multiply(X1)); } else { ECFieldElement X1Squared = X1.Square(); M = Three(X1Squared); if (Z1IsOne) { M = M.Add(a4); } else if (!a4.IsZero) { ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square(); ECFieldElement Z1Pow4 = Z1Squared.Square(); if (a4Neg.BitLength < a4.BitLength) { M = M.Subtract(Z1Pow4.Multiply(a4Neg)); } else { M = M.Add(Z1Pow4.Multiply(a4)); } } //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); S = Four(X1.Multiply(Y1Squared)); } ECFieldElement X3 = M.Square().Subtract(Two(S)); ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T)); ECFieldElement Z3 = Two(Y1); if (!Z1IsOne) { Z3 = Z3.Multiply(Z1); } // Alternative calculation of Z3 using fast square //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared); return(new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed)); } case ECCurve.COORD_JACOBIAN_MODIFIED: { return(TwiceJacobianModified(true)); } default: { throw new InvalidOperationException("unsupported coordinate system"); } } }
public override ECPoint TwicePlus(ECPoint b) { if (this == b) { return(ThreeTimes()); } if (this.IsInfinity) { return(b); } if (b.IsInfinity) { return(Twice()); } ECFieldElement Y1 = this.RawYCoord; if (Y1.IsZero) { return(b); } ECCurve curve = this.Curve; int coord = curve.CoordinateSystem; switch (coord) { case ECCurve.COORD_AFFINE: { ECFieldElement X1 = this.RawXCoord; ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord; ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1); if (dx.IsZero) { if (dy.IsZero) { // this == b i.e. the result is 3P return(ThreeTimes()); } // this == -b, i.e. the result is P return(this); } /* * Optimized calculation of 2P + Q, as described in "Trading Inversions for * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery. */ ECFieldElement X = dx.Square(), Y = dy.Square(); ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y); if (d.IsZero) { return(Curve.Infinity); } ECFieldElement D = d.Multiply(dx); ECFieldElement I = D.Invert(); ECFieldElement L1 = d.Multiply(I).Multiply(dy); ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1); ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2); ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1); return(new FpPoint(Curve, X4, Y4, IsCompressed)); } case ECCurve.COORD_JACOBIAN_MODIFIED: { return(TwiceJacobianModified(false).Add(b)); } default: { return(Twice().Add(b)); } } }
protected virtual ECFieldElement Two(ECFieldElement x) { return(x.Add(x)); }