1d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootpackage org.bouncycastle.math.ec.custom.sec;
2d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
3d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.ec.ECCurve;
4d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.ec.ECFieldElement;
5d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.ec.ECPoint;
6d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.raw.Nat;
7d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.raw.Nat192;
8d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
9d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootpublic class SecP192R1Point extends ECPoint.AbstractFp
10d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root{
11d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    /**
12d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * Create a point which encodes with point compression.
1379d3bf2425a53baab7feb744dad710b6c15533c9Sergio Giro     *
14d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param curve
15d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            the curve to use
16d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param x
17d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            affine x co-ordinate
18d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param y
19d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            affine y co-ordinate
2079d3bf2425a53baab7feb744dad710b6c15533c9Sergio Giro     *
21d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @deprecated Use ECCurve.createPoint to construct points
22d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     */
23d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
24d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
25d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        this(curve, x, y, false);
26d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
27d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
28d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    /**
29d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * Create a point that encodes with or without point compresion.
3079d3bf2425a53baab7feb744dad710b6c15533c9Sergio Giro     *
31d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param curve
32d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            the curve to use
33d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param x
34d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            affine x co-ordinate
35d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param y
36d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            affine y co-ordinate
37d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param withCompression
38d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            if true encode with point compression
3979d3bf2425a53baab7feb744dad710b6c15533c9Sergio Giro     *
40d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @deprecated per-point compression property will be removed, refer
41d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *             {@link #getEncoded(boolean)}
42d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     */
43d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
44d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
45d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        super(curve, x, y);
46d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
47d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if ((x == null) != (y == null))
48d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
49d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            throw new IllegalArgumentException("Exactly one of the field elements is null");
50d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
51d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
52d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        this.withCompression = withCompression;
53d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
54d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
55d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
56d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
57d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        super(curve, x, y, zs);
58d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
59d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        this.withCompression = withCompression;
60d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
61d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
62d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected ECPoint detach()
63d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
64d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP192R1Point(null, getAffineXCoord(), getAffineYCoord());
65d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
66d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
67d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    // B.3 pg 62
68d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint add(ECPoint b)
69d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
70d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
71d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
72d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
73d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
74d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (b.isInfinity())
75d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
76d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
77d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
78d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this == b)
79d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
80d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return twice();
81d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
82d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
83d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECCurve curve = this.getCurve();
84d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
85d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Y1 = (SecP192R1FieldElement)this.y;
86d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement X2 = (SecP192R1FieldElement)b.getXCoord(), Y2 = (SecP192R1FieldElement)b.getYCoord();
87d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
88d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.zs[0];
89d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.getZCoord(0);
90d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
91d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int c;
92d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] tt1 = Nat192.createExt();
93d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t2 = Nat192.create();
94d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t3 = Nat192.create();
95d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t4 = Nat192.create();
96d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
97d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z1IsOne = Z1.isOne();
98d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] U2, S2;
99d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Z1IsOne)
100d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
101d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U2 = X2.x;
102d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S2 = Y2.x;
103d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
104d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        else
105d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
106d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S2 = t3;
107d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.square(Z1.x, S2);
108d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
109d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U2 = t2;
110d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S2, X2.x, U2);
111d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
112d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S2, Z1.x, S2);
113d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S2, Y2.x, S2);
114d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
115d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
116d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z2IsOne = Z2.isOne();
117d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] U1, S1;
118d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Z2IsOne)
119d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
120d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U1 = X1.x;
121d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S1 = Y1.x;
122d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
123d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        else
124d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
125d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S1 = t4;
126d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.square(Z2.x, S1);
127d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
128d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U1 = tt1;
129d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S1, X1.x, U1);
130d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
131d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S1, Z2.x, S1);
132d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(S1, Y1.x, S1);
133d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
134d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
135d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] H = Nat192.create();
136d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(U1, U2, H);
137d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
138d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] R = t2;
139d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(S1, S2, R);
140d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
141d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        // Check if b == this or b == -this
142d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Nat192.isZero(H))
143d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
144d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (Nat192.isZero(R))
145d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
146d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                // this == b, i.e. this must be doubled
147d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                return this.twice();
148d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
149d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
150d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            // this == -b, i.e. the result is the point at infinity
151d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return curve.getInfinity();
152d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
153d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
154d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] HSquared = t3;
155d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.square(H, HSquared);
156d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
157d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] G = Nat192.create();
158d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiply(HSquared, H, G);
159d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
160d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] V = t3;
161d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiply(HSquared, U1, V);
162d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
163d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.negate(G, G);
164d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        Nat192.mul(S1, G, tt1);
165d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
166d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat192.addBothTo(V, V, G);
167d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.reduce32(c, G);
168d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
169d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4);
170d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.square(R, X3.x);
171d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(X3.x, G, X3.x);
172d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
173d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G);
174d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(V, X3.x, Y3.x);
175d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiplyAddToExt(Y3.x, R, tt1);
176d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.reduce(tt1, Y3.x);
177d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
178d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H);
179d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
180d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
181d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x);
182d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
183d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z2IsOne)
184d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
185d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(Z3.x, Z2.x, Z3.x);
186d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
187d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
188d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
189d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
190d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP192R1Point(curve, X3, Y3, zs, this.withCompression);
191d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
192d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
193d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    // B.3 pg 62
194d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint twice()
195d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
196d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
197d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
198d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
199d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
200d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
201d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECCurve curve = this.getCurve();
202d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
203d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Y1 = (SecP192R1FieldElement)this.y;
204d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Y1.isZero())
205d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
206d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return curve.getInfinity();
207d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
208d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
209d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Z1 = (SecP192R1FieldElement)this.zs[0];
210d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
211d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int c;
212d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t1 = Nat192.create();
213d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t2 = Nat192.create();
214d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
215d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] Y1Squared = Nat192.create();
216d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.square(Y1.x, Y1Squared);
217d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
218d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] T = Nat192.create();
219d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.square(Y1Squared, T);
220d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
221d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z1IsOne = Z1.isOne();
222d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
223d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] Z1Squared = Z1.x;
224d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
225d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
226d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            Z1Squared = t2;
227d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.square(Z1.x, Z1Squared);
228d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
229d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
230d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(X1.x, Z1Squared, t1);
231d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
232d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] M = t2;
233d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.add(X1.x, Z1Squared, M);
234d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiply(M, t1, M);
235d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat192.addBothTo(M, M, M);
236d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.reduce32(c, M);
237d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
238d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] S = Y1Squared;
239d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiply(Y1Squared, X1.x, S);
240d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat.shiftUpBits(6, S, 2, 0);
241d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.reduce32(c, S);
242d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
243d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat.shiftUpBits(6, T, 3, 0, t1);
244d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.reduce32(c, t1);
245d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
246d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement X3 = new SecP192R1FieldElement(T);
247d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.square(M, X3.x);
248d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(X3.x, S, X3.x);
249d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(X3.x, S, X3.x);
250d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
251d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Y3 = new SecP192R1FieldElement(S);
252d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(S, X3.x, Y3.x);
253d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.multiply(Y3.x, M, Y3.x);
254d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.subtract(Y3.x, t1, Y3.x);
255d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
256d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1FieldElement Z3 = new SecP192R1FieldElement(M);
257d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP192R1Field.twice(Y1.x, Z3.x);
258d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
259d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
260d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x);
261d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
262d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
263d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
264d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
265d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
266d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint twicePlus(ECPoint b)
267d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
268d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this == b)
269d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
270d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return threeTimes();
271d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
272d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
273d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
274d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
275d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
276d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (b.isInfinity())
277d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
278d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return twice();
279d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
280d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
281d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECFieldElement Y1 = this.y;
282d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Y1.isZero())
283d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
284d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
285d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
286d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
287d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return twice().add(b);
288d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
289d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
290d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint threeTimes()
291d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
292d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity() || this.y.isZero())
293d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
294d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
295d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
296d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
297d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        // NOTE: Be careful about recursions between twicePlus and threeTimes
298d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return twice().add(this);
299d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
300d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
301d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint negate()
302d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
303d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
304d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
305d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
306d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
307d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
308d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP192R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
309d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
310d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root}
311