< Summary

Information
Class: Renci.SshNet.Security.Org.BouncyCastle.Math.EC.FpPoint
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\BouncyCastle\math\ec\ECPoint.cs
Line coverage
43%
Covered lines: 193
Uncovered lines: 247
Coverable lines: 440
Total lines: 2122
Line coverage: 43.8%
Branch coverage
38%
Covered branches: 68
Total branches: 177
Branch coverage: 38.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%10%
.ctor(...)50%280%
.ctor(...)100%1100%
Detach()100%10%
GetZCoord(...)50%466.66%
Add(...)36.2%5848.2%
Twice()8.82%3413.09%
TwicePlus(...)38.88%1832.5%
ThreeTimes()0%100%
TimesPow2(...)66.66%3370.68%
Two(...)100%1100%
Three(...)100%1100%
Four(...)100%10%
Eight(...)100%10%
DoubleProductFromSquares(...)100%10%
Negate()50%480%
CalculateJacobianModifiedW(...)62.5%878.94%
GetJacobianModifiedW()50%266.66%
TwiceJacobianModified(...)100%4100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\BouncyCastle\math\ec\ECPoint.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Diagnostics;
 4using System.Text;
 5
 6using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier;
 7
 8namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC
 9{
 10    /**
 11     * base class for points on elliptic curves.
 12     */
 13    internal abstract class ECPoint
 14    {
 15        protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
 16
 17        protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
 18        {
 19            // Cope with null curve, most commonly used by implicitlyCa
 20            int coord = null == curve ? ECCurve.COORD_AFFINE : curve.CoordinateSystem;
 21
 22            switch (coord)
 23            {
 24                case ECCurve.COORD_AFFINE:
 25                case ECCurve.COORD_LAMBDA_AFFINE:
 26                    return EMPTY_ZS;
 27                default:
 28                    break;
 29            }
 30
 31            ECFieldElement one = curve.FromBigInteger(BigInteger.One);
 32
 33            switch (coord)
 34            {
 35                case ECCurve.COORD_HOMOGENEOUS:
 36                case ECCurve.COORD_JACOBIAN:
 37                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 38                    return new ECFieldElement[] { one };
 39                case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
 40                    return new ECFieldElement[] { one, one, one };
 41                case ECCurve.COORD_JACOBIAN_MODIFIED:
 42                    return new ECFieldElement[] { one, curve.A };
 43                default:
 44                    throw new ArgumentException("unknown coordinate system");
 45            }
 46        }
 47
 48        protected internal readonly ECCurve m_curve;
 49        protected internal readonly ECFieldElement m_x, m_y;
 50        protected internal readonly ECFieldElement[] m_zs;
 51        protected internal readonly bool m_withCompression;
 52
 53        // Dictionary is (string -> PreCompInfo)
 54        protected internal IDictionary m_preCompTable = null;
 55
 56        protected ECPoint(ECCurve curve, ECFieldElement  x, ECFieldElement y, bool withCompression)
 57            : this(curve, x, y, GetInitialZCoords(curve), withCompression)
 58        {
 59        }
 60
 61        internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
 62        {
 63            this.m_curve = curve;
 64            this.m_x = x;
 65            this.m_y = y;
 66            this.m_zs = zs;
 67            this.m_withCompression = withCompression;
 68        }
 69
 70        protected abstract bool SatisfiesCurveEquation();
 71
 72        protected virtual bool SatisfiesOrder()
 73        {
 74            if (BigInteger.One.Equals(Curve.Cofactor))
 75                return true;
 76
 77            BigInteger n = Curve.Order;
 78
 79            // TODO Require order to be available for all curves
 80
 81            return n == null || ECAlgorithms.ReferenceMultiply(this, n).IsInfinity;
 82        }
 83
 84        public ECPoint GetDetachedPoint()
 85        {
 86            return Normalize().Detach();
 87        }
 88
 89        public virtual ECCurve Curve
 90        {
 91            get { return m_curve; }
 92        }
 93
 94        protected abstract ECPoint Detach();
 95
 96        protected virtual int CurveCoordinateSystem
 97        {
 98            get
 99            {
 100                // Cope with null curve, most commonly used by implicitlyCa
 101                return null == m_curve ? ECCurve.COORD_AFFINE : m_curve.CoordinateSystem;
 102            }
 103        }
 104
 105        /**
 106         * Returns the affine x-coordinate after checking that this point is normalized.
 107         *
 108         * @return The affine x-coordinate of this point
 109         * @throws IllegalStateException if the point is not normalized
 110         */
 111        public virtual ECFieldElement AffineXCoord
 112        {
 113            get
 114            {
 115                CheckNormalized();
 116                return XCoord;
 117            }
 118        }
 119
 120        /**
 121         * Returns the affine y-coordinate after checking that this point is normalized
 122         *
 123         * @return The affine y-coordinate of this point
 124         * @throws IllegalStateException if the point is not normalized
 125         */
 126        public virtual ECFieldElement AffineYCoord
 127        {
 128            get
 129            {
 130                CheckNormalized();
 131                return YCoord;
 132            }
 133        }
 134
 135        /**
 136         * Returns the x-coordinate.
 137         *
 138         * Caution: depending on the curve's coordinate system, this may not be the same value as in an
 139         * affine coordinate system; use Normalize() to get a point where the coordinates have their
 140         * affine values, or use AffineXCoord if you expect the point to already have been normalized.
 141         *
 142         * @return the x-coordinate of this point
 143         */
 144        public virtual ECFieldElement XCoord
 145        {
 146            get { return m_x; }
 147        }
 148
 149        /**
 150         * Returns the y-coordinate.
 151         *
 152         * Caution: depending on the curve's coordinate system, this may not be the same value as in an
 153         * affine coordinate system; use Normalize() to get a point where the coordinates have their
 154         * affine values, or use AffineYCoord if you expect the point to already have been normalized.
 155         *
 156         * @return the y-coordinate of this point
 157         */
 158        public virtual ECFieldElement YCoord
 159        {
 160            get { return m_y; }
 161        }
 162
 163        public virtual ECFieldElement GetZCoord(int index)
 164        {
 165            return (index < 0 || index >= m_zs.Length) ? null : m_zs[index];
 166        }
 167
 168        public virtual ECFieldElement[] GetZCoords()
 169        {
 170            int zsLen = m_zs.Length;
 171            if (zsLen == 0)
 172            {
 173                return m_zs;
 174            }
 175            ECFieldElement[] copy = new ECFieldElement[zsLen];
 176            Array.Copy(m_zs, 0, copy, 0, zsLen);
 177            return copy;
 178        }
 179
 180        protected internal ECFieldElement RawXCoord
 181        {
 182            get { return m_x; }
 183        }
 184
 185        protected internal ECFieldElement RawYCoord
 186        {
 187            get { return m_y; }
 188        }
 189
 190        protected internal ECFieldElement[] RawZCoords
 191        {
 192            get { return m_zs; }
 193        }
 194
 195        protected virtual void CheckNormalized()
 196        {
 197            if (!IsNormalized())
 198                throw new InvalidOperationException("point not in normal form");
 199        }
 200
 201        public virtual bool IsNormalized()
 202        {
 203            int coord = this.CurveCoordinateSystem;
 204
 205            return coord == ECCurve.COORD_AFFINE
 206                || coord == ECCurve.COORD_LAMBDA_AFFINE
 207                || IsInfinity
 208                || RawZCoords[0].IsOne;
 209        }
 210
 211        /**
 212         * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
 213         * coordinates reflect those of the equivalent point in an affine coordinate system.
 214         *
 215         * @return a new ECPoint instance representing the same point, but with normalized coordinates
 216         */
 217        public virtual ECPoint Normalize()
 218        {
 219            if (this.IsInfinity)
 220            {
 221                return this;
 222            }
 223
 224            switch (this.CurveCoordinateSystem)
 225            {
 226                case ECCurve.COORD_AFFINE:
 227                case ECCurve.COORD_LAMBDA_AFFINE:
 228                {
 229                    return this;
 230                }
 231                default:
 232                {
 233                    ECFieldElement Z1 = RawZCoords[0];
 234                    if (Z1.IsOne)
 235                    {
 236                        return this;
 237                    }
 238
 239                    return Normalize(Z1.Invert());
 240                }
 241            }
 242        }
 243
 244        internal virtual ECPoint Normalize(ECFieldElement zInv)
 245        {
 246            switch (this.CurveCoordinateSystem)
 247            {
 248                case ECCurve.COORD_HOMOGENEOUS:
 249                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 250                {
 251                    return CreateScaledPoint(zInv, zInv);
 252                }
 253                case ECCurve.COORD_JACOBIAN:
 254                case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
 255                case ECCurve.COORD_JACOBIAN_MODIFIED:
 256                {
 257                    ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
 258                    return CreateScaledPoint(zInv2, zInv3);
 259                }
 260                default:
 261                {
 262                    throw new InvalidOperationException("not a projective coordinate system");
 263                }
 264            }
 265        }
 266
 267        protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy)
 268        {
 269            return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed);
 270        }
 271
 272        public bool IsInfinity
 273        {
 274            get { return m_x == null && m_y == null; }
 275        }
 276
 277        public bool IsCompressed
 278        {
 279            get { return m_withCompression; }
 280        }
 281
 282        public bool IsValid()
 283        {
 284            return ImplIsValid(false, true);
 285        }
 286
 287        internal bool IsValidPartial()
 288        {
 289            return ImplIsValid(false, false);
 290        }
 291
 292        internal bool ImplIsValid(bool decompressed, bool checkOrder)
 293        {
 294            if (IsInfinity)
 295                return true;
 296
 297            ValidityCallback callback = new ValidityCallback(this, decompressed, checkOrder);
 298            ValidityPreCompInfo validity = (ValidityPreCompInfo)Curve.Precompute(this, ValidityPreCompInfo.PRECOMP_NAME,
 299            return !validity.HasFailed();
 300        }
 301
 302        public virtual ECPoint ScaleX(ECFieldElement scale)
 303        {
 304            return IsInfinity
 305                ? this
 306                : Curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord, RawZCoords, IsCompressed);
 307        }
 308
 309        public virtual ECPoint ScaleY(ECFieldElement scale)
 310        {
 311            return IsInfinity
 312                ? this
 313                : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed);
 314        }
 315
 316        public override bool Equals(object obj)
 317        {
 318            return Equals(obj as ECPoint);
 319        }
 320
 321        public virtual bool Equals(ECPoint other)
 322        {
 323            if (this == other)
 324                return true;
 325            if (null == other)
 326                return false;
 327
 328            ECCurve c1 = this.Curve, c2 = other.Curve;
 329            bool n1 = (null == c1), n2 = (null == c2);
 330            bool i1 = IsInfinity, i2 = other.IsInfinity;
 331
 332            if (i1 || i2)
 333            {
 334                return (i1 && i2) && (n1 || n2 || c1.Equals(c2));
 335            }
 336
 337            ECPoint p1 = this, p2 = other;
 338            if (n1 && n2)
 339            {
 340                // Points with null curve are in affine form, so already normalized
 341            }
 342            else if (n1)
 343            {
 344                p2 = p2.Normalize();
 345            }
 346            else if (n2)
 347            {
 348                p1 = p1.Normalize();
 349            }
 350            else if (!c1.Equals(c2))
 351            {
 352                return false;
 353            }
 354            else
 355            {
 356                // TODO Consider just requiring already normalized, to avoid silent performance degradation
 357
 358                ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) };
 359
 360                // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
 361                c1.NormalizeAll(points);
 362
 363                p1 = points[0];
 364                p2 = points[1];
 365            }
 366
 367            return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord);
 368        }
 369
 370        public override int GetHashCode()
 371        {
 372            ECCurve c = this.Curve;
 373            int hc = (null == c) ? 0 : ~c.GetHashCode();
 374
 375            if (!this.IsInfinity)
 376            {
 377                // TODO Consider just requiring already normalized, to avoid silent performance degradation
 378
 379                ECPoint p = Normalize();
 380
 381                hc ^= p.XCoord.GetHashCode() * 17;
 382                hc ^= p.YCoord.GetHashCode() * 257;
 383            }
 384
 385            return hc;
 386        }
 387
 388        public override string ToString()
 389        {
 390            if (this.IsInfinity)
 391            {
 392                return "INF";
 393            }
 394
 395            StringBuilder sb = new StringBuilder();
 396            sb.Append('(');
 397            sb.Append(RawXCoord);
 398            sb.Append(',');
 399            sb.Append(RawYCoord);
 400            for (int i = 0; i < m_zs.Length; ++i)
 401            {
 402                sb.Append(',');
 403                sb.Append(m_zs[i]);
 404            }
 405            sb.Append(')');
 406            return sb.ToString();
 407        }
 408
 409        public virtual byte[] GetEncoded()
 410        {
 411            return GetEncoded(m_withCompression);
 412        }
 413
 414        public abstract byte[] GetEncoded(bool compressed);
 415
 416        protected internal abstract bool CompressionYTilde { get; }
 417
 418        public abstract ECPoint Add(ECPoint b);
 419        public abstract ECPoint Subtract(ECPoint b);
 420        public abstract ECPoint Negate();
 421
 422        public virtual ECPoint TimesPow2(int e)
 423        {
 424            if (e < 0)
 425                throw new ArgumentException("cannot be negative", "e");
 426
 427            ECPoint p = this;
 428            while (--e >= 0)
 429            {
 430                p = p.Twice();
 431            }
 432            return p;
 433        }
 434
 435        public abstract ECPoint Twice();
 436        public abstract ECPoint Multiply(BigInteger b);
 437
 438        public virtual ECPoint TwicePlus(ECPoint b)
 439        {
 440            return Twice().Add(b);
 441        }
 442
 443        public virtual ECPoint ThreeTimes()
 444        {
 445            return TwicePlus(this);
 446        }
 447
 448        private class ValidityCallback
 449            : IPreCompCallback
 450        {
 451            private readonly ECPoint m_outer;
 452            private readonly bool m_decompressed, m_checkOrder;
 453
 454            internal ValidityCallback(ECPoint outer, bool decompressed, bool checkOrder)
 455            {
 456                this.m_outer = outer;
 457                this.m_decompressed = decompressed;
 458                this.m_checkOrder = checkOrder;
 459            }
 460
 461            public PreCompInfo Precompute(PreCompInfo existing)
 462            {
 463                ValidityPreCompInfo info = existing as ValidityPreCompInfo;
 464                if (info == null)
 465                {
 466                    info = new ValidityPreCompInfo();
 467                }
 468
 469                if (info.HasFailed())
 470                    return info;
 471
 472                if (!info.HasCurveEquationPassed())
 473                {
 474                    if (!m_decompressed && !m_outer.SatisfiesCurveEquation())
 475                    {
 476                        info.ReportFailed();
 477                        return info;
 478                    }
 479                    info.ReportCurveEquationPassed();
 480                }
 481                if (m_checkOrder && !info.HasOrderPassed())
 482                {
 483                    if (!m_outer.SatisfiesOrder())
 484                    {
 485                        info.ReportFailed();
 486                        return info;
 487                    }
 488                    info.ReportOrderPassed();
 489                }
 490                return info;
 491            }
 492        }
 493    }
 494
 495    internal abstract class ECPointBase
 496        : ECPoint
 497    {
 498        protected internal ECPointBase(
 499            ECCurve      curve,
 500            ECFieldElement  x,
 501            ECFieldElement  y,
 502            bool      withCompression)
 503            : base(curve, x, y, withCompression)
 504        {
 505        }
 506
 507        protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool with
 508            : base(curve, x, y, zs, withCompression)
 509        {
 510        }
 511
 512        /**
 513         * return the field element encoded with point compression. (S 4.3.6)
 514         */
 515        public override byte[] GetEncoded(bool compressed)
 516        {
 517            if (this.IsInfinity)
 518            {
 519                return new byte[1];
 520            }
 521
 522            ECPoint normed = Normalize();
 523
 524            byte[] X = normed.XCoord.GetEncoded();
 525
 526            if (compressed)
 527            {
 528                byte[] PO = new byte[X.Length + 1];
 529                PO[0] = (byte)(normed.CompressionYTilde ? 0x03 : 0x02);
 530                Array.Copy(X, 0, PO, 1, X.Length);
 531                return PO;
 532            }
 533
 534            byte[] Y = normed.YCoord.GetEncoded();
 535
 536            {
 537                byte[] PO = new byte[X.Length + Y.Length + 1];
 538                PO[0] = 0x04;
 539                Array.Copy(X, 0, PO, 1, X.Length);
 540                Array.Copy(Y, 0, PO, X.Length + 1, Y.Length);
 541                return PO;
 542            }
 543        }
 544
 545        /**
 546         * Multiplies this <code>ECPoint</code> by the given number.
 547         * @param k The multiplicator.
 548         * @return <code>k * this</code>.
 549         */
 550        public override ECPoint Multiply(BigInteger k)
 551        {
 552            return this.Curve.GetMultiplier().Multiply(this, k);
 553        }
 554    }
 555
 556    internal abstract class AbstractFpPoint
 557        : ECPointBase
 558    {
 559        protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
 560            : base(curve, x, y, withCompression)
 561        {
 562        }
 563
 564        protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompr
 565            : base(curve, x, y, zs, withCompression)
 566        {
 567        }
 568
 569        protected internal override bool CompressionYTilde
 570        {
 571            get { return this.AffineYCoord.TestBitZero(); }
 572        }
 573
 574        protected override bool SatisfiesCurveEquation()
 575        {
 576            ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B;
 577            ECFieldElement lhs = Y.Square();
 578
 579            switch (CurveCoordinateSystem)
 580            {
 581            case ECCurve.COORD_AFFINE:
 582                break;
 583            case ECCurve.COORD_HOMOGENEOUS:
 584            {
 585                ECFieldElement Z = this.RawZCoords[0];
 586                if (!Z.IsOne)
 587                {
 588                    ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
 589                    lhs = lhs.Multiply(Z);
 590                    A = A.Multiply(Z2);
 591                    B = B.Multiply(Z3);
 592                }
 593                break;
 594            }
 595            case ECCurve.COORD_JACOBIAN:
 596            case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
 597            case ECCurve.COORD_JACOBIAN_MODIFIED:
 598            {
 599                ECFieldElement Z = this.RawZCoords[0];
 600                if (!Z.IsOne)
 601                {
 602                    ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4);
 603                    A = A.Multiply(Z4);
 604                    B = B.Multiply(Z6);
 605                }
 606                break;
 607            }
 608            default:
 609                throw new InvalidOperationException("unsupported coordinate system");
 610            }
 611
 612            ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B);
 613            return lhs.Equals(rhs);
 614        }
 615
 616        public override ECPoint Subtract(ECPoint b)
 617        {
 618            if (b.IsInfinity)
 619                return this;
 620
 621            // Add -b
 622            return Add(b.Negate());
 623        }
 624    }
 625
 626    /**
 627     * Elliptic curve points over Fp
 628     */
 629    internal class FpPoint
 630        : AbstractFpPoint
 631    {
 632        /**
 633         * Create a point which encodes without point compression.
 634         *
 635         * @param curve the curve to use
 636         * @param x affine x co-ordinate
 637         * @param y affine y co-ordinate
 638         */
 639        public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
 0640            : this(curve, x, y, false)
 0641        {
 0642        }
 643
 644        /**
 645         * Create a point that encodes with or without point compression.
 646         *
 647         * @param curve the curve to use
 648         * @param x affine x co-ordinate
 649         * @param y affine y co-ordinate
 650         * @param withCompression if true encode with point compression
 651         */
 652        public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
 960653            : base(curve, x, y, withCompression)
 960654        {
 960655            if ((x == null) != (y == null))
 0656                throw new ArgumentException("Exactly one of the field elements is null");
 960657        }
 658
 659        internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
 3171660            : base(curve, x, y, zs, withCompression)
 3171661        {
 3171662        }
 663
 664        protected override ECPoint Detach()
 0665        {
 0666            return new FpPoint(null, AffineXCoord, AffineYCoord, false);
 0667        }
 668
 669        public override ECFieldElement GetZCoord(int index)
 336670        {
 336671            if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem)
 0672            {
 0673                return GetJacobianModifiedW();
 674            }
 675
 336676            return base.GetZCoord(index);
 336677        }
 678
 679        // B.3 pg 62
 680        public override ECPoint Add(ECPoint b)
 1404681        {
 1404682            if (this.IsInfinity)
 0683                return b;
 1404684            if (b.IsInfinity)
 0685                return this;
 1404686            if (this == b)
 3687                return Twice();
 688
 1401689            ECCurve curve = this.Curve;
 1401690            int coord = curve.CoordinateSystem;
 691
 2802692            ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord;
 2802693            ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
 694
 1401695            switch (coord)
 696            {
 697                case ECCurve.COORD_AFFINE:
 0698                {
 0699                    ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
 700
 0701                    if (dx.IsZero)
 0702                    {
 0703                        if (dy.IsZero)
 0704                        {
 705                            // this == b, i.e. this must be doubled
 0706                            return Twice();
 707                        }
 708
 709                        // this == -b, i.e. the result is the point at infinity
 0710                        return Curve.Infinity;
 711                    }
 712
 0713                    ECFieldElement gamma = dy.Divide(dx);
 0714                    ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
 0715                    ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
 716
 0717                    return new FpPoint(Curve, X3, Y3, IsCompressed);
 718                }
 719
 720                case ECCurve.COORD_HOMOGENEOUS:
 0721                {
 0722                    ECFieldElement Z1 = this.RawZCoords[0];
 0723                    ECFieldElement Z2 = b.RawZCoords[0];
 724
 0725                    bool Z1IsOne = Z1.IsOne;
 0726                    bool Z2IsOne = Z2.IsOne;
 727
 0728                    ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
 0729                    ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
 0730                    ECFieldElement u = u1.Subtract(u2);
 0731                    ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
 0732                    ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
 0733                    ECFieldElement v = v1.Subtract(v2);
 734
 735                    // Check if b == this or b == -this
 0736                    if (v.IsZero)
 0737                    {
 0738                        if (u.IsZero)
 0739                        {
 740                            // this == b, i.e. this must be doubled
 0741                            return this.Twice();
 742                        }
 743
 744                        // this == -b, i.e. the result is the point at infinity
 0745                        return curve.Infinity;
 746                    }
 747
 748                    // TODO Optimize for when w == 1
 0749                    ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
 0750                    ECFieldElement vSquared = v.Square();
 0751                    ECFieldElement vCubed = vSquared.Multiply(v);
 0752                    ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
 0753                    ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
 754
 0755                    ECFieldElement X3 = v.Multiply(A);
 0756                    ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed);
 0757                    ECFieldElement Z3 = vCubed.Multiply(w);
 758
 0759                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
 760                }
 761
 762                case ECCurve.COORD_JACOBIAN:
 763                case ECCurve.COORD_JACOBIAN_MODIFIED:
 1401764                {
 1401765                    ECFieldElement Z1 = this.RawZCoords[0];
 1401766                    ECFieldElement Z2 = b.RawZCoords[0];
 767
 1401768                    bool Z1IsOne = Z1.IsOne;
 769
 1401770                    ECFieldElement X3, Y3, Z3, Z3Squared = null;
 771
 1401772                    if (!Z1IsOne && Z1.Equals(Z2))
 0773                    {
 774                        // TODO Make this available as public method coZAdd?
 775
 0776                        ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2);
 0777                        if (dx.IsZero)
 0778                        {
 0779                            if (dy.IsZero)
 0780                            {
 0781                                return Twice();
 782                            }
 0783                            return curve.Infinity;
 784                        }
 785
 0786                        ECFieldElement C = dx.Square();
 0787                        ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C);
 0788                        ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1);
 789
 0790                        X3 = dy.Square().Subtract(W1).Subtract(W2);
 0791                        Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1);
 0792                        Z3 = dx;
 793
 0794                        if (Z1IsOne)
 0795                        {
 0796                            Z3Squared = C;
 0797                        }
 798                        else
 0799                        {
 0800                            Z3 = Z3.Multiply(Z1);
 0801                        }
 0802                    }
 803                    else
 1401804                    {
 805                        ECFieldElement Z1Squared, U2, S2;
 1401806                        if (Z1IsOne)
 34807                        {
 102808                            Z1Squared = Z1; U2 = X2; S2 = Y2;
 34809                        }
 810                        else
 1367811                        {
 1367812                            Z1Squared = Z1.Square();
 1367813                            U2 = Z1Squared.Multiply(X2);
 1367814                            ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1);
 1367815                            S2 = Z1Cubed.Multiply(Y2);
 1367816                        }
 817
 1401818                        bool Z2IsOne = Z2.IsOne;
 819                        ECFieldElement Z2Squared, U1, S1;
 1401820                        if (Z2IsOne)
 1398821                        {
 4194822                            Z2Squared = Z2; U1 = X1; S1 = Y1;
 1398823                        }
 824                        else
 3825                        {
 3826                            Z2Squared = Z2.Square();
 3827                            U1 = Z2Squared.Multiply(X1);
 3828                            ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2);
 3829                            S1 = Z2Cubed.Multiply(Y1);
 3830                        }
 831
 1401832                        ECFieldElement H = U1.Subtract(U2);
 1401833                        ECFieldElement R = S1.Subtract(S2);
 834
 835                        // Check if b == this or b == -this
 1401836                        if (H.IsZero)
 0837                        {
 0838                            if (R.IsZero)
 0839                            {
 840                                // this == b, i.e. this must be doubled
 0841                                return this.Twice();
 842                            }
 843
 844                            // this == -b, i.e. the result is the point at infinity
 0845                            return curve.Infinity;
 846                        }
 847
 1401848                        ECFieldElement HSquared = H.Square();
 1401849                        ECFieldElement G = HSquared.Multiply(H);
 1401850                        ECFieldElement V = HSquared.Multiply(U1);
 851
 1401852                        X3 = R.Square().Add(G).Subtract(Two(V));
 1401853                        Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1);
 854
 1401855                        Z3 = H;
 1401856                        if (!Z1IsOne)
 1367857                        {
 1367858                            Z3 = Z3.Multiply(Z1);
 1367859                        }
 1401860                        if (!Z2IsOne)
 3861                        {
 3862                            Z3 = Z3.Multiply(Z2);
 3863                        }
 864
 865                        // Alternative calculation of Z3 using fast square
 866                        //X3 = four(X3);
 867                        //Y3 = eight(Y3);
 868                        //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H);
 869
 1401870                        if (Z3 == H)
 31871                        {
 31872                            Z3Squared = HSquared;
 31873                        }
 1401874                    }
 875
 876                    ECFieldElement[] zs;
 1401877                    if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
 1401878                    {
 879                        // TODO If the result will only be used in a subsequent addition, we don't need W3
 1401880                        ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared);
 881
 1401882                        zs = new ECFieldElement[] { Z3, W3 };
 1401883                    }
 884                    else
 0885                    {
 0886                        zs = new ECFieldElement[] { Z3 };
 0887                    }
 888
 1401889                    return new FpPoint(curve, X3, Y3, zs, IsCompressed);
 890                }
 891
 892                default:
 0893                {
 0894                    throw new InvalidOperationException("unsupported coordinate system");
 895                }
 896            }
 1404897        }
 898
 899        // B.3 pg 62
 900        public override ECPoint Twice()
 17901        {
 17902            if (this.IsInfinity)
 0903                return this;
 904
 17905            ECCurve curve = this.Curve;
 906
 17907            ECFieldElement Y1 = this.RawYCoord;
 17908            if (Y1.IsZero)
 0909                return curve.Infinity;
 910
 17911            int coord = curve.CoordinateSystem;
 912
 17913            ECFieldElement X1 = this.RawXCoord;
 914
 17915            switch (coord)
 916            {
 917                case ECCurve.COORD_AFFINE:
 0918                {
 0919                    ECFieldElement X1Squared = X1.Square();
 0920                    ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
 0921                    ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
 0922                    ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
 923
 0924                    return new FpPoint(Curve, X3, Y3, IsCompressed);
 925                }
 926
 927                case ECCurve.COORD_HOMOGENEOUS:
 0928                {
 0929                    ECFieldElement Z1 = this.RawZCoords[0];
 930
 0931                    bool Z1IsOne = Z1.IsOne;
 932
 933                    // TODO Optimize for small negative a4 and -3
 0934                    ECFieldElement w = curve.A;
 0935                    if (!w.IsZero && !Z1IsOne)
 0936                    {
 0937                        w = w.Multiply(Z1.Square());
 0938                    }
 0939                    w = w.Add(Three(X1.Square()));
 940
 0941                    ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1);
 0942                    ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1);
 0943                    ECFieldElement B = X1.Multiply(t);
 0944                    ECFieldElement _4B = Four(B);
 0945                    ECFieldElement h = w.Square().Subtract(Two(_4B));
 946
 0947                    ECFieldElement _2s = Two(s);
 0948                    ECFieldElement X3 = h.Multiply(_2s);
 0949                    ECFieldElement _2t = Two(t);
 0950                    ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
 0951                    ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square();
 0952                    ECFieldElement Z3 = Two(_4sSquared).Multiply(s);
 953
 0954                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
 955                }
 956
 957                case ECCurve.COORD_JACOBIAN:
 0958                {
 0959                    ECFieldElement Z1 = this.RawZCoords[0];
 960
 0961                    bool Z1IsOne = Z1.IsOne;
 962
 0963                    ECFieldElement Y1Squared = Y1.Square();
 0964                    ECFieldElement T = Y1Squared.Square();
 965
 0966                    ECFieldElement a4 = curve.A;
 0967                    ECFieldElement a4Neg = a4.Negate();
 968
 969                    ECFieldElement M, S;
 0970                    if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3)))
 0971                    {
 0972                        ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
 0973                        M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared)));
 0974                        S = Four(Y1Squared.Multiply(X1));
 0975                    }
 976                    else
 0977                    {
 0978                        ECFieldElement X1Squared = X1.Square();
 0979                        M = Three(X1Squared);
 0980                        if (Z1IsOne)
 0981                        {
 0982                            M = M.Add(a4);
 0983                        }
 0984                        else if (!a4.IsZero)
 0985                        {
 0986                            ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
 0987                            ECFieldElement Z1Pow4 = Z1Squared.Square();
 0988                            if (a4Neg.BitLength < a4.BitLength)
 0989                            {
 0990                                M = M.Subtract(Z1Pow4.Multiply(a4Neg));
 0991                            }
 992                            else
 0993                            {
 0994                                M = M.Add(Z1Pow4.Multiply(a4));
 0995                            }
 0996                        }
 997                        //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
 0998                        S = Four(X1.Multiply(Y1Squared));
 0999                    }
 1000
 01001                    ECFieldElement X3 = M.Square().Subtract(Two(S));
 01002                    ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T));
 1003
 01004                    ECFieldElement Z3 = Two(Y1);
 01005                    if (!Z1IsOne)
 01006                    {
 01007                        Z3 = Z3.Multiply(Z1);
 01008                    }
 1009
 1010                    // Alternative calculation of Z3 using fast square
 1011                    //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
 1012
 01013                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
 1014                }
 1015
 1016                case ECCurve.COORD_JACOBIAN_MODIFIED:
 171017                {
 171018                    return TwiceJacobianModified(true);
 1019                }
 1020
 1021                default:
 01022                {
 01023                    throw new InvalidOperationException("unsupported coordinate system");
 1024                }
 1025            }
 171026        }
 1027
 1028        public override ECPoint TwicePlus(ECPoint b)
 10941029        {
 10941030            if (this == b)
 01031                return ThreeTimes();
 10941032            if (this.IsInfinity)
 91033                return b;
 10851034            if (b.IsInfinity)
 01035                return Twice();
 1036
 10851037            ECFieldElement Y1 = this.RawYCoord;
 10851038            if (Y1.IsZero)
 01039                return b;
 1040
 10851041            ECCurve curve = this.Curve;
 10851042            int coord = curve.CoordinateSystem;
 1043
 10851044            switch (coord)
 1045            {
 1046                case ECCurve.COORD_AFFINE:
 01047                {
 01048                    ECFieldElement X1 = this.RawXCoord;
 01049                    ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
 1050
 01051                    ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
 1052
 01053                    if (dx.IsZero)
 01054                    {
 01055                        if (dy.IsZero)
 01056                        {
 1057                            // this == b i.e. the result is 3P
 01058                            return ThreeTimes();
 1059                        }
 1060
 1061                        // this == -b, i.e. the result is P
 01062                        return this;
 1063                    }
 1064
 1065                    /*
 1066                     * Optimized calculation of 2P + Q, as described in "Trading Inversions for
 1067                     * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
 1068                     */
 1069
 01070                    ECFieldElement X = dx.Square(), Y = dy.Square();
 01071                    ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
 01072                    if (d.IsZero)
 01073                    {
 01074                        return Curve.Infinity;
 1075                    }
 1076
 01077                    ECFieldElement D = d.Multiply(dx);
 01078                    ECFieldElement I = D.Invert();
 01079                    ECFieldElement L1 = d.Multiply(I).Multiply(dy);
 01080                    ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
 01081                    ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
 01082                    ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
 1083
 01084                    return new FpPoint(Curve, X4, Y4, IsCompressed);
 1085                }
 1086                case ECCurve.COORD_JACOBIAN_MODIFIED:
 10851087                {
 10851088                    return TwiceJacobianModified(false).Add(b);
 1089                }
 1090                default:
 01091                {
 01092                    return Twice().Add(b);
 1093                }
 1094            }
 10941095        }
 1096
 1097        public override ECPoint ThreeTimes()
 01098        {
 01099            if (this.IsInfinity)
 01100                return this;
 1101
 01102            ECFieldElement Y1 = this.RawYCoord;
 01103            if (Y1.IsZero)
 01104                return this;
 1105
 01106            ECCurve curve = this.Curve;
 01107            int coord = curve.CoordinateSystem;
 1108
 01109            switch (coord)
 1110            {
 1111                case ECCurve.COORD_AFFINE:
 01112                {
 01113                    ECFieldElement X1 = this.RawXCoord;
 1114
 01115                    ECFieldElement _2Y1 = Two(Y1);
 01116                    ECFieldElement X = _2Y1.Square();
 01117                    ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
 01118                    ECFieldElement Y = Z.Square();
 1119
 01120                    ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
 01121                    if (d.IsZero)
 01122                    {
 01123                        return Curve.Infinity;
 1124                    }
 1125
 01126                    ECFieldElement D = d.Multiply(_2Y1);
 01127                    ECFieldElement I = D.Invert();
 01128                    ECFieldElement L1 = d.Multiply(I).Multiply(Z);
 01129                    ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
 1130
 01131                    ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
 01132                    ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
 01133                    return new FpPoint(Curve, X4, Y4, IsCompressed);
 1134                }
 1135                case ECCurve.COORD_JACOBIAN_MODIFIED:
 01136                {
 01137                    return TwiceJacobianModified(false).Add(this);
 1138                }
 1139                default:
 01140                {
 1141                    // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
 01142                    return Twice().Add(this);
 1143                }
 1144            }
 01145        }
 1146
 1147        public override ECPoint TimesPow2(int e)
 5361148        {
 5361149            if (e < 0)
 01150                throw new ArgumentException("cannot be negative", "e");
 5361151            if (e == 0 || this.IsInfinity)
 41152                return this;
 5321153            if (e == 1)
 51154                return Twice();
 1155
 5271156            ECCurve curve = this.Curve;
 1157
 5271158            ECFieldElement Y1 = this.RawYCoord;
 5271159            if (Y1.IsZero)
 01160                return curve.Infinity;
 1161
 5271162            int coord = curve.CoordinateSystem;
 1163
 5271164            ECFieldElement W1 = curve.A;
 5271165            ECFieldElement X1 = this.RawXCoord;
 5271166            ECFieldElement Z1 = this.RawZCoords.Length < 1 ? curve.FromBigInteger(BigInteger.One) : this.RawZCoords[0];
 1167
 5271168            if (!Z1.IsOne)
 5221169            {
 5221170                switch (coord)
 1171                {
 1172                case ECCurve.COORD_HOMOGENEOUS:
 01173                    ECFieldElement Z1Sq = Z1.Square();
 01174                    X1 = X1.Multiply(Z1);
 01175                    Y1 = Y1.Multiply(Z1Sq);
 01176                    W1 = CalculateJacobianModifiedW(Z1, Z1Sq);
 01177                    break;
 1178                case ECCurve.COORD_JACOBIAN:
 01179                    W1 = CalculateJacobianModifiedW(Z1, null);
 01180                    break;
 1181                case ECCurve.COORD_JACOBIAN_MODIFIED:
 5221182                    W1 = GetJacobianModifiedW();
 5221183                    break;
 1184                }
 5221185            }
 1186
 88121187            for (int i = 0; i < e; ++i)
 38791188            {
 38791189                if (Y1.IsZero)
 01190                    return curve.Infinity;
 1191
 38791192                ECFieldElement X1Squared = X1.Square();
 38791193                ECFieldElement M = Three(X1Squared);
 38791194                ECFieldElement _2Y1 = Two(Y1);
 38791195                ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
 38791196                ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
 38791197                ECFieldElement _4T = _2Y1Squared.Square();
 38791198                ECFieldElement _8T = Two(_4T);
 1199
 38791200                if (!W1.IsZero)
 38791201                {
 38791202                    M = M.Add(W1);
 38791203                    W1 = Two(_8T.Multiply(W1));
 38791204                }
 1205
 38791206                X1 = M.Square().Subtract(Two(S));
 38791207                Y1 = M.Multiply(S.Subtract(X1)).Subtract(_8T);
 38791208                Z1 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
 38791209            }
 1210
 5271211            switch (coord)
 1212            {
 1213            case ECCurve.COORD_AFFINE:
 01214                ECFieldElement zInv = Z1.Invert(), zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
 01215                return new FpPoint(curve, X1.Multiply(zInv2), Y1.Multiply(zInv3), IsCompressed);
 1216            case ECCurve.COORD_HOMOGENEOUS:
 01217                X1 = X1.Multiply(Z1);
 01218                Z1 = Z1.Multiply(Z1.Square());
 01219                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
 1220            case ECCurve.COORD_JACOBIAN:
 01221                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
 1222            case ECCurve.COORD_JACOBIAN_MODIFIED:
 5271223                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1, W1 }, IsCompressed);
 1224            default:
 01225                throw new InvalidOperationException("unsupported coordinate system");
 1226            }
 5361227        }
 1228
 1229        protected virtual ECFieldElement Two(ECFieldElement x)
 302021230        {
 302021231            return x.Add(x);
 302021232        }
 1233
 1234        protected virtual ECFieldElement Three(ECFieldElement x)
 49811235        {
 49811236            return Two(x).Add(x);
 49811237        }
 1238
 1239        protected virtual ECFieldElement Four(ECFieldElement x)
 01240        {
 01241            return Two(Two(x));
 01242        }
 1243
 1244        protected virtual ECFieldElement Eight(ECFieldElement x)
 01245        {
 01246            return Four(Two(x));
 01247        }
 1248
 1249        protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b,
 1250            ECFieldElement aSquared, ECFieldElement bSquared)
 01251        {
 1252            /*
 1253             * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
 1254             * way to calculate 2.A.B, if A^2 and B^2 are already known.
 1255             */
 01256            return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
 01257        }
 1258
 1259        public override ECPoint Negate()
 1231260        {
 1231261            if (IsInfinity)
 01262                return this;
 1263
 1231264            ECCurve curve = Curve;
 1231265            int coord = curve.CoordinateSystem;
 1266
 1231267            if (ECCurve.COORD_AFFINE != coord)
 1231268            {
 1231269                return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
 1270            }
 1271
 01272            return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), IsCompressed);
 1231273        }
 1274
 1275        protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
 14011276        {
 14011277            ECFieldElement a4 = this.Curve.A;
 14011278            if (a4.IsZero || Z.IsOne)
 01279                return a4;
 1280
 14011281            if (ZSquared == null)
 13701282            {
 13701283                ZSquared = Z.Square();
 13701284            }
 1285
 14011286            ECFieldElement W = ZSquared.Square();
 14011287            ECFieldElement a4Neg = a4.Negate();
 14011288            if (a4Neg.BitLength < a4.BitLength)
 14011289            {
 14011290                W = W.Multiply(a4Neg).Negate();
 14011291            }
 1292            else
 01293            {
 01294                W = W.Multiply(a4);
 01295            }
 14011296            return W;
 14011297        }
 1298
 1299        protected virtual ECFieldElement GetJacobianModifiedW()
 16241300        {
 16241301            ECFieldElement[] ZZ = this.RawZCoords;
 16241302            ECFieldElement W = ZZ[1];
 16241303            if (W == null)
 01304            {
 1305                // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
 01306                ZZ[1] = W = CalculateJacobianModifiedW(ZZ[0], null);
 01307            }
 16241308            return W;
 16241309        }
 1310
 1311        protected virtual FpPoint TwiceJacobianModified(bool calculateW)
 11021312        {
 44081313            ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord, Z1 = this.RawZCoords[0], W1 = GetJacobianModifiedW(
 1314
 11021315            ECFieldElement X1Squared = X1.Square();
 11021316            ECFieldElement M = Three(X1Squared).Add(W1);
 11021317            ECFieldElement _2Y1 = Two(Y1);
 11021318            ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
 11021319            ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
 11021320            ECFieldElement X3 = M.Square().Subtract(Two(S));
 11021321            ECFieldElement _4T = _2Y1Squared.Square();
 11021322            ECFieldElement _8T = Two(_4T);
 11021323            ECFieldElement Y3 = M.Multiply(S.Subtract(X3)).Subtract(_8T);
 11021324            ECFieldElement W3 = calculateW ? Two(_8T.Multiply(W1)) : null;
 11021325            ECFieldElement Z3 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
 1326
 11021327            return new FpPoint(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
 11021328        }
 1329    }
 1330
 1331    internal abstract class AbstractF2mPoint
 1332        : ECPointBase
 1333    {
 1334        protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
 1335            : base(curve, x, y, withCompression)
 1336        {
 1337        }
 1338
 1339        protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withComp
 1340            : base(curve, x, y, zs, withCompression)
 1341        {
 1342        }
 1343
 1344        protected override bool SatisfiesCurveEquation()
 1345        {
 1346            ECCurve curve = Curve;
 1347            ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B;
 1348            ECFieldElement lhs, rhs;
 1349
 1350            int coord = curve.CoordinateSystem;
 1351            if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
 1352            {
 1353                ECFieldElement Z = this.RawZCoords[0];
 1354                bool ZIsOne = Z.IsOne;
 1355
 1356                if (X.IsZero)
 1357                {
 1358                    // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
 1359                    lhs = Y.Square();
 1360                    rhs = B;
 1361                    if (!ZIsOne)
 1362                    {
 1363                        ECFieldElement Z2 = Z.Square();
 1364                        rhs = rhs.Multiply(Z2);
 1365                    }
 1366                }
 1367                else
 1368                {
 1369                    ECFieldElement L = Y, X2 = X.Square();
 1370                    if (ZIsOne)
 1371                    {
 1372                        lhs = L.Square().Add(L).Add(A);
 1373                        rhs = X2.Square().Add(B);
 1374                    }
 1375                    else
 1376                    {
 1377                        ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square();
 1378                        lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2);
 1379                        // TODO If sqrt(b) is precomputed this can be simplified to a single square
 1380                        rhs = X2.SquarePlusProduct(B, Z4);
 1381                    }
 1382                    lhs = lhs.Multiply(X2);
 1383                }
 1384            }
 1385            else
 1386            {
 1387                lhs = Y.Add(X).Multiply(Y);
 1388
 1389                switch (coord)
 1390                {
 1391                    case ECCurve.COORD_AFFINE:
 1392                        break;
 1393                    case ECCurve.COORD_HOMOGENEOUS:
 1394                        {
 1395                            ECFieldElement Z = this.RawZCoords[0];
 1396                            if (!Z.IsOne)
 1397                            {
 1398                                ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
 1399                                lhs = lhs.Multiply(Z);
 1400                                A = A.Multiply(Z);
 1401                                B = B.Multiply(Z3);
 1402                            }
 1403                            break;
 1404                        }
 1405                    default:
 1406                        throw new InvalidOperationException("unsupported coordinate system");
 1407                }
 1408
 1409                rhs = X.Add(A).Multiply(X.Square()).Add(B);
 1410            }
 1411
 1412            return lhs.Equals(rhs);
 1413        }
 1414
 1415        protected override bool SatisfiesOrder()
 1416        {
 1417            ECCurve curve = Curve;
 1418            BigInteger cofactor = curve.Cofactor;
 1419            if (BigInteger.Two.Equals(cofactor))
 1420            {
 1421                /*
 1422                 *  Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A,
 1423                 *  and so a halving is possible, so this point is the double of another.
 1424                 */
 1425                ECPoint N = this.Normalize();
 1426                ECFieldElement X = N.AffineXCoord;
 1427                ECFieldElement rhs = X.Add(curve.A);
 1428                return ((AbstractF2mFieldElement)rhs).Trace() == 0;
 1429            }
 1430            if (BigInteger.ValueOf(4).Equals(cofactor))
 1431            {
 1432                /*
 1433                 * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
 1434                 * Generate both possibilities for the square of the half-point's x-coordinate (w),
 1435                 * and check if Tr(w + A) == 0 for at least one; then a second halving is possible
 1436                 * (see comments for cofactor 2 above), so this point is four times another.
 1437                 *
 1438                 * Note: Tr(x^2) == Tr(x).
 1439                 */
 1440                ECPoint N = this.Normalize();
 1441                ECFieldElement X = N.AffineXCoord;
 1442                ECFieldElement lambda = ((AbstractF2mCurve)curve).SolveQuadraticEquation(X.Add(curve.A));
 1443                if (lambda == null)
 1444                    return false;
 1445
 1446                ECFieldElement w = X.Multiply(lambda).Add(N.AffineYCoord);
 1447                ECFieldElement t = w.Add(curve.A);
 1448                return ((AbstractF2mFieldElement)t).Trace() == 0
 1449                    || ((AbstractF2mFieldElement)(t.Add(X))).Trace() == 0;
 1450            }
 1451
 1452            return base.SatisfiesOrder();
 1453        }
 1454
 1455        public override ECPoint ScaleX(ECFieldElement scale)
 1456        {
 1457            if (this.IsInfinity)
 1458                return this;
 1459
 1460            switch (CurveCoordinateSystem)
 1461            {
 1462            case ECCurve.COORD_LAMBDA_AFFINE:
 1463            {
 1464                // Y is actually Lambda (X + Y/X) here
 1465                ECFieldElement X = RawXCoord, L = RawYCoord;
 1466
 1467                ECFieldElement X2 = X.Multiply(scale);
 1468                ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
 1469
 1470                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
 1471            }
 1472            case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1473            {
 1474                // Y is actually Lambda (X + Y/X) here
 1475                ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
 1476
 1477                // We scale the Z coordinate also, to avoid an inversion
 1478                ECFieldElement X2 = X.Multiply(scale.Square());
 1479                ECFieldElement L2 = L.Add(X).Add(X2);
 1480                ECFieldElement Z2 = Z.Multiply(scale);
 1481
 1482                return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
 1483            }
 1484            default:
 1485            {
 1486                return base.ScaleX(scale);
 1487            }
 1488            }
 1489        }
 1490
 1491        public override ECPoint ScaleY(ECFieldElement scale)
 1492        {
 1493            if (this.IsInfinity)
 1494                return this;
 1495
 1496            switch (CurveCoordinateSystem)
 1497            {
 1498            case ECCurve.COORD_LAMBDA_AFFINE:
 1499            case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1500            {
 1501                ECFieldElement X = RawXCoord, L = RawYCoord;
 1502
 1503                // Y is actually Lambda (X + Y/X) here
 1504                ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
 1505
 1506                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
 1507            }
 1508            default:
 1509            {
 1510                return base.ScaleY(scale);
 1511            }
 1512            }
 1513        }
 1514
 1515        public override ECPoint Subtract(ECPoint b)
 1516        {
 1517            if (b.IsInfinity)
 1518                return this;
 1519
 1520            // Add -b
 1521            return Add(b.Negate());
 1522        }
 1523
 1524        public virtual AbstractF2mPoint Tau()
 1525        {
 1526            if (this.IsInfinity)
 1527                return this;
 1528
 1529            ECCurve curve = this.Curve;
 1530            int coord = curve.CoordinateSystem;
 1531
 1532            ECFieldElement X1 = this.RawXCoord;
 1533
 1534            switch (coord)
 1535            {
 1536            case ECCurve.COORD_AFFINE:
 1537            case ECCurve.COORD_LAMBDA_AFFINE:
 1538            {
 1539                ECFieldElement Y1 = this.RawYCoord;
 1540                return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed);
 1541            }
 1542            case ECCurve.COORD_HOMOGENEOUS:
 1543            case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1544            {
 1545                ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1546                return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(),
 1547                    new ECFieldElement[] { Z1.Square() }, IsCompressed);
 1548            }
 1549            default:
 1550            {
 1551                throw new InvalidOperationException("unsupported coordinate system");
 1552            }
 1553            }
 1554        }
 1555
 1556        public virtual AbstractF2mPoint TauPow(int pow)
 1557        {
 1558            if (this.IsInfinity)
 1559                return this;
 1560
 1561            ECCurve curve = this.Curve;
 1562            int coord = curve.CoordinateSystem;
 1563
 1564            ECFieldElement X1 = this.RawXCoord;
 1565
 1566            switch (coord)
 1567            {
 1568            case ECCurve.COORD_AFFINE:
 1569            case ECCurve.COORD_LAMBDA_AFFINE:
 1570            {
 1571                ECFieldElement Y1 = this.RawYCoord;
 1572                return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed);
 1573            }
 1574            case ECCurve.COORD_HOMOGENEOUS:
 1575            case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1576            {
 1577                ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1578                return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow),
 1579                    new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed);
 1580            }
 1581            default:
 1582            {
 1583                throw new InvalidOperationException("unsupported coordinate system");
 1584            }
 1585            }
 1586        }
 1587    }
 1588
 1589    /**
 1590     * Elliptic curve points over F2m
 1591     */
 1592    internal class F2mPoint
 1593        : AbstractF2mPoint
 1594    {
 1595        /**
 1596         * @param curve base curve
 1597         * @param x x point
 1598         * @param y y point
 1599         */
 1600        public F2mPoint(
 1601            ECCurve      curve,
 1602            ECFieldElement  x,
 1603            ECFieldElement  y)
 1604            :  this(curve, x, y, false)
 1605        {
 1606        }
 1607
 1608        /**
 1609         * @param curve base curve
 1610         * @param x x point
 1611         * @param y y point
 1612         * @param withCompression true if encode with point compression.
 1613         */
 1614        public F2mPoint(
 1615            ECCurve      curve,
 1616            ECFieldElement  x,
 1617            ECFieldElement  y,
 1618            bool      withCompression)
 1619            : base(curve, x, y, withCompression)
 1620        {
 1621            if ((x == null) != (y == null))
 1622            {
 1623                throw new ArgumentException("Exactly one of the field elements is null");
 1624            }
 1625
 1626            if (x != null)
 1627            {
 1628                // Check if x and y are elements of the same field
 1629                F2mFieldElement.CheckFieldElements(x, y);
 1630
 1631                // Check if x and a are elements of the same field
 1632                if (curve != null)
 1633                {
 1634                    F2mFieldElement.CheckFieldElements(x, curve.A);
 1635                }
 1636            }
 1637        }
 1638
 1639        internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
 1640            : base(curve, x, y, zs, withCompression)
 1641        {
 1642        }
 1643
 1644        protected override ECPoint Detach()
 1645        {
 1646            return new F2mPoint(null, AffineXCoord, AffineYCoord, false);
 1647        }
 1648
 1649        public override ECFieldElement YCoord
 1650        {
 1651            get
 1652            {
 1653                int coord = this.CurveCoordinateSystem;
 1654
 1655                switch (coord)
 1656                {
 1657                    case ECCurve.COORD_LAMBDA_AFFINE:
 1658                    case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1659                    {
 1660                        ECFieldElement X = RawXCoord, L = RawYCoord;
 1661
 1662                        if (this.IsInfinity || X.IsZero)
 1663                            return L;
 1664
 1665                        // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
 1666                        ECFieldElement Y = L.Add(X).Multiply(X);
 1667                        if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
 1668                        {
 1669                            ECFieldElement Z = RawZCoords[0];
 1670                            if (!Z.IsOne)
 1671                            {
 1672                                Y = Y.Divide(Z);
 1673                            }
 1674                        }
 1675                        return Y;
 1676                    }
 1677                    default:
 1678                    {
 1679                        return RawYCoord;
 1680                    }
 1681                }
 1682            }
 1683        }
 1684
 1685        protected internal override bool CompressionYTilde
 1686        {
 1687            get
 1688            {
 1689                ECFieldElement X = this.RawXCoord;
 1690                if (X.IsZero)
 1691                {
 1692                    return false;
 1693                }
 1694
 1695                ECFieldElement Y = this.RawYCoord;
 1696
 1697                switch (this.CurveCoordinateSystem)
 1698                {
 1699                    case ECCurve.COORD_LAMBDA_AFFINE:
 1700                    case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1701                    {
 1702                        // Y is actually Lambda (X + Y/X) here
 1703                        return Y.TestBitZero() != X.TestBitZero();
 1704                    }
 1705                    default:
 1706                    {
 1707                        return Y.Divide(X).TestBitZero();
 1708                    }
 1709                }
 1710            }
 1711        }
 1712
 1713        public override ECPoint Add(ECPoint b)
 1714        {
 1715            if (this.IsInfinity)
 1716                return b;
 1717            if (b.IsInfinity)
 1718                return this;
 1719
 1720            ECCurve curve = this.Curve;
 1721            int coord = curve.CoordinateSystem;
 1722
 1723            ECFieldElement X1 = this.RawXCoord;
 1724            ECFieldElement X2 = b.RawXCoord;
 1725
 1726            switch (coord)
 1727            {
 1728                case ECCurve.COORD_AFFINE:
 1729                {
 1730                    ECFieldElement Y1 = this.RawYCoord;
 1731                    ECFieldElement Y2 = b.RawYCoord;
 1732
 1733                    ECFieldElement dx = X1.Add(X2), dy = Y1.Add(Y2);
 1734                    if (dx.IsZero)
 1735                    {
 1736                        if (dy.IsZero)
 1737                        {
 1738                            return Twice();
 1739                        }
 1740
 1741                        return curve.Infinity;
 1742                    }
 1743
 1744                    ECFieldElement L = dy.Divide(dx);
 1745
 1746                    ECFieldElement X3 = L.Square().Add(L).Add(dx).Add(curve.A);
 1747                    ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
 1748
 1749                    return new F2mPoint(curve, X3, Y3, IsCompressed);
 1750                }
 1751                case ECCurve.COORD_HOMOGENEOUS:
 1752                {
 1753                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1754                    ECFieldElement Y2 = b.RawYCoord, Z2 = b.RawZCoords[0];
 1755
 1756                    bool Z1IsOne = Z1.IsOne;
 1757                    ECFieldElement U1 = Y2, V1 = X2;
 1758                    if (!Z1IsOne)
 1759                    {
 1760                        U1 = U1.Multiply(Z1);
 1761                        V1 = V1.Multiply(Z1);
 1762                    }
 1763
 1764                    bool Z2IsOne = Z2.IsOne;
 1765                    ECFieldElement U2 = Y1, V2 = X1;
 1766                    if (!Z2IsOne)
 1767                    {
 1768                        U2 = U2.Multiply(Z2);
 1769                        V2 = V2.Multiply(Z2);
 1770                    }
 1771
 1772                    ECFieldElement U = U1.Add(U2);
 1773                    ECFieldElement V = V1.Add(V2);
 1774
 1775                    if (V.IsZero)
 1776                    {
 1777                        if (U.IsZero)
 1778                        {
 1779                            return Twice();
 1780                        }
 1781
 1782                        return curve.Infinity;
 1783                    }
 1784
 1785                    ECFieldElement VSq = V.Square();
 1786                    ECFieldElement VCu = VSq.Multiply(V);
 1787                    ECFieldElement W = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
 1788                    ECFieldElement uv = U.Add(V);
 1789                    ECFieldElement A = uv.MultiplyPlusProduct(U, VSq, curve.A).Multiply(W).Add(VCu);
 1790
 1791                    ECFieldElement X3 = V.Multiply(A);
 1792                    ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.Multiply(Z2);
 1793                    ECFieldElement Y3 = U.MultiplyPlusProduct(X1, V, Y1).MultiplyPlusProduct(VSqZ2, uv, A);
 1794                    ECFieldElement Z3 = VCu.Multiply(W);
 1795
 1796                    return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
 1797                }
 1798                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1799                {
 1800                    if (X1.IsZero)
 1801                    {
 1802                        if (X2.IsZero)
 1803                            return curve.Infinity;
 1804
 1805                        return b.Add(this);
 1806                    }
 1807
 1808                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1809                    ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
 1810
 1811                    bool Z1IsOne = Z1.IsOne;
 1812                    ECFieldElement U2 = X2, S2 = L2;
 1813                    if (!Z1IsOne)
 1814                    {
 1815                        U2 = U2.Multiply(Z1);
 1816                        S2 = S2.Multiply(Z1);
 1817                    }
 1818
 1819                    bool Z2IsOne = Z2.IsOne;
 1820                    ECFieldElement U1 = X1, S1 = L1;
 1821                    if (!Z2IsOne)
 1822                    {
 1823                        U1 = U1.Multiply(Z2);
 1824                        S1 = S1.Multiply(Z2);
 1825                    }
 1826
 1827                    ECFieldElement A = S1.Add(S2);
 1828                    ECFieldElement B = U1.Add(U2);
 1829
 1830                    if (B.IsZero)
 1831                    {
 1832                        if (A.IsZero)
 1833                        {
 1834                            return Twice();
 1835                        }
 1836
 1837                        return curve.Infinity;
 1838                    }
 1839
 1840                    ECFieldElement X3, L3, Z3;
 1841                    if (X2.IsZero)
 1842                    {
 1843                        // TODO This can probably be optimized quite a bit
 1844                        ECPoint p = this.Normalize();
 1845                        X1 = p.RawXCoord;
 1846                        ECFieldElement Y1 = p.YCoord;
 1847
 1848                        ECFieldElement Y2 = L2;
 1849                        ECFieldElement L = Y1.Add(Y2).Divide(X1);
 1850
 1851                        X3 = L.Square().Add(L).Add(X1).Add(curve.A);
 1852                        if (X3.IsZero)
 1853                        {
 1854                            return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
 1855                        }
 1856
 1857                        ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
 1858                        L3 = Y3.Divide(X3).Add(X3);
 1859                        Z3 = curve.FromBigInteger(BigInteger.One);
 1860                    }
 1861                    else
 1862                    {
 1863                        B = B.Square();
 1864
 1865                        ECFieldElement AU1 = A.Multiply(U1);
 1866                        ECFieldElement AU2 = A.Multiply(U2);
 1867
 1868                        X3 = AU1.Multiply(AU2);
 1869                        if (X3.IsZero)
 1870                        {
 1871                            return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
 1872                        }
 1873
 1874                        ECFieldElement ABZ2 = A.Multiply(B);
 1875                        if (!Z2IsOne)
 1876                        {
 1877                            ABZ2 = ABZ2.Multiply(Z2);
 1878                        }
 1879
 1880                        L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
 1881
 1882                        Z3 = ABZ2;
 1883                        if (!Z1IsOne)
 1884                        {
 1885                            Z3 = Z3.Multiply(Z1);
 1886                        }
 1887                    }
 1888
 1889                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
 1890                }
 1891                default:
 1892                {
 1893                    throw new InvalidOperationException("unsupported coordinate system");
 1894                }
 1895            }
 1896        }
 1897
 1898        /* (non-Javadoc)
 1899         * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
 1900         */
 1901        public override ECPoint Twice()
 1902        {
 1903            if (this.IsInfinity)
 1904                return this;
 1905
 1906            ECCurve curve = this.Curve;
 1907
 1908            ECFieldElement X1 = this.RawXCoord;
 1909            if (X1.IsZero)
 1910            {
 1911                // A point with X == 0 is it's own additive inverse
 1912                return curve.Infinity;
 1913            }
 1914
 1915            int coord = curve.CoordinateSystem;
 1916
 1917            switch (coord)
 1918            {
 1919                case ECCurve.COORD_AFFINE:
 1920                {
 1921                    ECFieldElement Y1 = this.RawYCoord;
 1922
 1923                    ECFieldElement L1 = Y1.Divide(X1).Add(X1);
 1924
 1925                    ECFieldElement X3 = L1.Square().Add(L1).Add(curve.A);
 1926                    ECFieldElement Y3 = X1.SquarePlusProduct(X3, L1.AddOne());
 1927
 1928                    return new F2mPoint(curve, X3, Y3, IsCompressed);
 1929                }
 1930                case ECCurve.COORD_HOMOGENEOUS:
 1931                {
 1932                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1933
 1934                    bool Z1IsOne = Z1.IsOne;
 1935                    ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
 1936                    ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.Multiply(Z1);
 1937
 1938                    ECFieldElement X1Sq = X1.Square();
 1939                    ECFieldElement S = X1Sq.Add(Y1Z1);
 1940                    ECFieldElement V = X1Z1;
 1941                    ECFieldElement vSquared = V.Square();
 1942                    ECFieldElement sv = S.Add(V);
 1943                    ECFieldElement h = sv.MultiplyPlusProduct(S, vSquared, curve.A);
 1944
 1945                    ECFieldElement X3 = V.Multiply(h);
 1946                    ECFieldElement Y3 = X1Sq.Square().MultiplyPlusProduct(V, h, sv);
 1947                    ECFieldElement Z3 = V.Multiply(vSquared);
 1948
 1949                    return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
 1950                }
 1951                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 1952                {
 1953                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 1954
 1955                    bool Z1IsOne = Z1.IsOne;
 1956                    ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
 1957                    ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
 1958                    ECFieldElement a = curve.A;
 1959                    ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
 1960                    ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
 1961                    if (T.IsZero)
 1962                    {
 1963                        return new F2mPoint(curve, T, curve.B.Sqrt(), IsCompressed);
 1964                    }
 1965
 1966                    ECFieldElement X3 = T.Square();
 1967                    ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
 1968
 1969                    ECFieldElement b = curve.B;
 1970                    ECFieldElement L3;
 1971                    if (b.BitLength < (curve.FieldSize >> 1))
 1972                    {
 1973                        ECFieldElement t1 = L1.Add(X1).Square();
 1974                        ECFieldElement t2;
 1975                        if (b.IsOne)
 1976                        {
 1977                            t2 = aZ1Sq.Add(Z1Sq).Square();
 1978                        }
 1979                        else
 1980                        {
 1981                            // TODO Can be calculated with one square if we pre-compute sqrt(b)
 1982                            t2 = aZ1Sq.SquarePlusProduct(b, Z1Sq.Square());
 1983                        }
 1984                        L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3);
 1985                        if (a.IsZero)
 1986                        {
 1987                            L3 = L3.Add(Z3);
 1988                        }
 1989                        else if (!a.IsOne)
 1990                        {
 1991                            L3 = L3.Add(a.AddOne().Multiply(Z3));
 1992                        }
 1993                    }
 1994                    else
 1995                    {
 1996                        ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
 1997                        L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
 1998                    }
 1999
 2000                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
 2001                }
 2002                default:
 2003                {
 2004                    throw new InvalidOperationException("unsupported coordinate system");
 2005                }
 2006            }
 2007        }
 2008
 2009        public override ECPoint TwicePlus(ECPoint b)
 2010        {
 2011            if (this.IsInfinity)
 2012                return b;
 2013            if (b.IsInfinity)
 2014                return Twice();
 2015
 2016            ECCurve curve = this.Curve;
 2017
 2018            ECFieldElement X1 = this.RawXCoord;
 2019            if (X1.IsZero)
 2020            {
 2021                // A point with X == 0 is it's own additive inverse
 2022                return b;
 2023            }
 2024
 2025            int coord = curve.CoordinateSystem;
 2026
 2027            switch (coord)
 2028            {
 2029                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 2030                {
 2031                    // NOTE: twicePlus() only optimized for lambda-affine argument
 2032                    ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
 2033                    if (X2.IsZero || !Z2.IsOne)
 2034                    {
 2035                        return Twice().Add(b);
 2036                    }
 2037
 2038                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
 2039                    ECFieldElement L2 = b.RawYCoord;
 2040
 2041                    ECFieldElement X1Sq = X1.Square();
 2042                    ECFieldElement L1Sq = L1.Square();
 2043                    ECFieldElement Z1Sq = Z1.Square();
 2044                    ECFieldElement L1Z1 = L1.Multiply(Z1);
 2045
 2046                    ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
 2047                    ECFieldElement L2plus1 = L2.AddOne();
 2048                    ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
 2049                    ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
 2050                    ECFieldElement B = X2Z1Sq.Add(T).Square();
 2051
 2052                    if (B.IsZero)
 2053                    {
 2054                        if (A.IsZero)
 2055                        {
 2056                            return b.Twice();
 2057                        }
 2058
 2059                        return curve.Infinity;
 2060                    }
 2061
 2062                    if (A.IsZero)
 2063                    {
 2064                        return new F2mPoint(curve, A, curve.B.Sqrt(), IsCompressed);
 2065                    }
 2066
 2067                    ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
 2068                    ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
 2069                    ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
 2070
 2071                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
 2072                }
 2073                default:
 2074                {
 2075                    return Twice().Add(b);
 2076                }
 2077            }
 2078        }
 2079
 2080        public override ECPoint Negate()
 2081        {
 2082            if (this.IsInfinity)
 2083                return this;
 2084
 2085            ECFieldElement X = this.RawXCoord;
 2086            if (X.IsZero)
 2087                return this;
 2088
 2089            ECCurve curve = this.Curve;
 2090            int coord = curve.CoordinateSystem;
 2091
 2092            switch (coord)
 2093            {
 2094                case ECCurve.COORD_AFFINE:
 2095                {
 2096                    ECFieldElement Y = this.RawYCoord;
 2097                    return new F2mPoint(curve, X, Y.Add(X), IsCompressed);
 2098                }
 2099                case ECCurve.COORD_HOMOGENEOUS:
 2100                {
 2101                    ECFieldElement Y = this.RawYCoord, Z = this.RawZCoords[0];
 2102                    return new F2mPoint(curve, X, Y.Add(X), new ECFieldElement[] { Z }, IsCompressed);
 2103                }
 2104                case ECCurve.COORD_LAMBDA_AFFINE:
 2105                {
 2106                    ECFieldElement L = this.RawYCoord;
 2107                    return new F2mPoint(curve, X, L.AddOne(), IsCompressed);
 2108                }
 2109                case ECCurve.COORD_LAMBDA_PROJECTIVE:
 2110                {
 2111                    // L is actually Lambda (X + Y/X) here
 2112                    ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
 2113                    return new F2mPoint(curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
 2114                }
 2115                default:
 2116                {
 2117                    throw new InvalidOperationException("unsupported coordinate system");
 2118                }
 2119            }
 2120        }
 2121    }
 2122}

Methods/Properties

.ctor(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECCurve,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
.ctor(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECCurve,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,System.Boolean)
.ctor(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECCurve,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement[],System.Boolean)
Detach()
GetZCoord(System.Int32)
Add(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECPoint)
Twice()
TwicePlus(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECPoint)
ThreeTimes()
TimesPow2(System.Int32)
Two(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
Three(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
Four(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
Eight(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
DoubleProductFromSquares(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
Negate()
CalculateJacobianModifiedW(Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement,Renci.SshNet.Security.Org.BouncyCastle.Math.EC.ECFieldElement)
GetJacobianModifiedW()
TwiceJacobianModified(System.Boolean)