예제 #1
0
        // B.3 pg 62
        public override ECPoint Add(ECPoint b)
        {
            if (this.IsInfinity)
            {
                return(b);
            }
            if (b.IsInfinity)
            {
                return(this);
            }
            if (this == b)
            {
                return(Twice());
            }

            ECCurve curve = this.Curve;
            int     coord = curve.CoordinateSystem;

            ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord;
            ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;

            switch (coord)
            {
            case ECCurve.COORD_AFFINE:
            {
                ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);

                if (dx.IsZero)
                {
                    if (dy.IsZero)
                    {
                        // this == b, i.e. this must be doubled
                        return(Twice());
                    }

                    // this == -b, i.e. the result is the point at infinity
                    return(Curve.Infinity);
                }

                ECFieldElement gamma = dy.Divide(dx);
                ECFieldElement X3    = gamma.Square().Subtract(X1).Subtract(X2);
                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];
                ECFieldElement Z2 = b.RawZCoords[0];

                bool Z1IsOne = Z1.IsOne;
                bool Z2IsOne = Z2.IsOne;

                ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
                ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
                ECFieldElement u  = u1.Subtract(u2);
                ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
                ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
                ECFieldElement v  = v1.Subtract(v2);

                // Check if b == this or b == -this
                if (v.IsZero)
                {
                    if (u.IsZero)
                    {
                        // this == b, i.e. this must be doubled
                        return(this.Twice());
                    }

                    // this == -b, i.e. the result is the point at infinity
                    return(curve.Infinity);
                }

                // TODO Optimize for when w == 1
                ECFieldElement w          = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
                ECFieldElement vSquared   = v.Square();
                ECFieldElement vCubed     = vSquared.Multiply(v);
                ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
                ECFieldElement A          = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));

                ECFieldElement X3 = v.Multiply(A);
                ECFieldElement Y3 = vSquaredV2.Subtract(A).Multiply(u).Subtract(vCubed.Multiply(u2));
                ECFieldElement Z3 = vCubed.Multiply(w);

                return(new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed));
            }

            case ECCurve.COORD_JACOBIAN:
            case ECCurve.COORD_JACOBIAN_MODIFIED:
            {
                ECFieldElement Z1 = this.RawZCoords[0];
                ECFieldElement Z2 = b.RawZCoords[0];

                bool Z1IsOne = Z1.IsOne;

                ECFieldElement X3, Y3, Z3, Z3Squared = null;

                if (!Z1IsOne && Z1.Equals(Z2))
                {
                    // TODO Make this available as public method coZAdd?

                    ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2);
                    if (dx.IsZero)
                    {
                        if (dy.IsZero)
                        {
                            return(Twice());
                        }
                        return(curve.Infinity);
                    }

                    ECFieldElement C = dx.Square();
                    ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C);
                    ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1);

                    X3 = dy.Square().Subtract(W1).Subtract(W2);
                    Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1);
                    Z3 = dx;

                    if (Z1IsOne)
                    {
                        Z3Squared = C;
                    }
                    else
                    {
                        Z3 = Z3.Multiply(Z1);
                    }
                }
                else
                {
                    ECFieldElement Z1Squared, U2, S2;
                    if (Z1IsOne)
                    {
                        Z1Squared = Z1; U2 = X2; S2 = Y2;
                    }
                    else
                    {
                        Z1Squared = Z1.Square();
                        U2        = Z1Squared.Multiply(X2);
                        ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1);
                        S2 = Z1Cubed.Multiply(Y2);
                    }

                    bool           Z2IsOne = Z2.IsOne;
                    ECFieldElement Z2Squared, U1, S1;
                    if (Z2IsOne)
                    {
                        Z2Squared = Z2; U1 = X1; S1 = Y1;
                    }
                    else
                    {
                        Z2Squared = Z2.Square();
                        U1        = Z2Squared.Multiply(X1);
                        ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2);
                        S1 = Z2Cubed.Multiply(Y1);
                    }

                    ECFieldElement H = U1.Subtract(U2);
                    ECFieldElement R = S1.Subtract(S2);

                    // Check if b == this or b == -this
                    if (H.IsZero)
                    {
                        if (R.IsZero)
                        {
                            // this == b, i.e. this must be doubled
                            return(this.Twice());
                        }

                        // this == -b, i.e. the result is the point at infinity
                        return(curve.Infinity);
                    }

                    ECFieldElement HSquared = H.Square();
                    ECFieldElement G        = HSquared.Multiply(H);
                    ECFieldElement V        = HSquared.Multiply(U1);

                    X3 = R.Square().Add(G).Subtract(Two(V));
                    Y3 = V.Subtract(X3).Multiply(R).Subtract(S1.Multiply(G));

                    Z3 = H;
                    if (!Z1IsOne)
                    {
                        Z3 = Z3.Multiply(Z1);
                    }
                    if (!Z2IsOne)
                    {
                        Z3 = Z3.Multiply(Z2);
                    }

                    // Alternative calculation of Z3 using fast square
                    //X3 = four(X3);
                    //Y3 = eight(Y3);
                    //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).multiply(H);

                    if (Z3 == H)
                    {
                        Z3Squared = HSquared;
                    }
                }

                ECFieldElement[] zs;
                if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
                {
                    // TODO If the result will only be used in a subsequent addition, we don't need W3
                    ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared);

                    zs = new ECFieldElement[] { Z3, W3 };
                }
                else
                {
                    zs = new ECFieldElement[] { Z3 };
                }

                return(new FpPoint(curve, X3, Y3, zs, IsCompressed));
            }

            default:
            {
                throw new InvalidOperationException("unsupported coordinate system");
            }
            }
        }