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.Nat224;
8d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
9d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootpublic class SecP224R1Point 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 SecP224R1Point(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 SecP224R1Point(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    SecP224R1Point(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 SecP224R1Point(null, getAffineXCoord(), getAffineYCoord());
65d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
66d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
67d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint add(ECPoint b)
68d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
69d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
70d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
71d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
72d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
73d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (b.isInfinity())
74d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
75d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
76d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
77d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this == b)
78d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
79d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return twice();
80d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
81d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
82d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECCurve curve = this.getCurve();
83d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
84d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Y1 = (SecP224R1FieldElement)this.y;
85d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.getXCoord(), Y2 = (SecP224R1FieldElement)b.getYCoord();
86d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
87d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.zs[0];
88d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.getZCoord(0);
89d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
90d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int c;
91d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] tt1 = Nat224.createExt();
92d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t2 = Nat224.create();
93d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t3 = Nat224.create();
94d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t4 = Nat224.create();
95d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
96d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z1IsOne = Z1.isOne();
97d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] U2, S2;
98d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Z1IsOne)
99d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
100d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U2 = X2.x;
101d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S2 = Y2.x;
102d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
103d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        else
104d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
105d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S2 = t3;
106d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.square(Z1.x, S2);
107d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
108d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U2 = t2;
109d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S2, X2.x, U2);
110d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
111d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S2, Z1.x, S2);
112d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S2, Y2.x, S2);
113d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
114d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
115d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z2IsOne = Z2.isOne();
116d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] U1, S1;
117d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Z2IsOne)
118d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
119d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U1 = X1.x;
120d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S1 = Y1.x;
121d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
122d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        else
123d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
124d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            S1 = t4;
125d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.square(Z2.x, S1);
126d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
127d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            U1 = tt1;
128d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S1, X1.x, U1);
129d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
130d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S1, Z2.x, S1);
131d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(S1, Y1.x, S1);
132d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
133d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
134d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] H = Nat224.create();
135d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(U1, U2, H);
136d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
137d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] R = t2;
138d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(S1, S2, R);
139d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
140d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        // Check if b == this or b == -this
141d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Nat224.isZero(H))
142d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
143d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (Nat224.isZero(R))
144d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
145d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                // this == b, i.e. this must be doubled
146d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                return this.twice();
147d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
148d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
149d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            // this == -b, i.e. the result is the point at infinity
150d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return curve.getInfinity();
151d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
152d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
153d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] HSquared = t3;
154d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.square(H, HSquared);
155d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
156d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] G = Nat224.create();
157d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiply(HSquared, H, G);
158d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
159d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] V = t3;
160d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiply(HSquared, U1, V);
161d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
162d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.negate(G, G);
163d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        Nat224.mul(S1, G, tt1);
164d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
165d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat224.addBothTo(V, V, G);
166d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.reduce32(c, G);
167d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
168d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4);
169d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.square(R, X3.x);
170d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(X3.x, G, X3.x);
171d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
172d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G);
173d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(V, X3.x, Y3.x);
174d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiplyAddToExt(Y3.x, R, tt1);
175d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.reduce(tt1, Y3.x);
176d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
177d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H);
178d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
179d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
180d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
181d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
182d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z2IsOne)
183d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
184d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(Z3.x, Z2.x, Z3.x);
185d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
186d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
187d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
188d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
189d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression);
190d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
191d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
192d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint twice()
193d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
194d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
195d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
196d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
197d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
198d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
199d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECCurve curve = this.getCurve();
200d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
201d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.y;
202d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Y1.isZero())
203d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
204d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return curve.getInfinity();
205d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
206d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
207d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Z1 = (SecP224R1FieldElement)this.zs[0];
208d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
209d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int c;
210d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t1 = Nat224.create();
211d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] t2 = Nat224.create();
212d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
213d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] Y1Squared = Nat224.create();
214d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.square(Y1.x, Y1Squared);
215d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
216d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] T = Nat224.create();
217d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.square(Y1Squared, T);
218d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
219d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        boolean Z1IsOne = Z1.isOne();
220d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
221d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] Z1Squared = Z1.x;
222d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
223d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
224d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            Z1Squared = t2;
225d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.square(Z1.x, Z1Squared);
226d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
227d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
228d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(X1.x, Z1Squared, t1);
229d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
230d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] M = t2;
231d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.add(X1.x, Z1Squared, M);
232d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiply(M, t1, M);
233d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat224.addBothTo(M, M, M);
234d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.reduce32(c, M);
235d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
236d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        int[] S = Y1Squared;
237d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiply(Y1Squared, X1.x, S);
238d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat.shiftUpBits(7, S, 2, 0);
239d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.reduce32(c, S);
240d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
241d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        c = Nat.shiftUpBits(7, T, 3, 0, t1);
242d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.reduce32(c, t1);
243d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
244d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement X3 = new SecP224R1FieldElement(T);
245d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.square(M, X3.x);
246d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(X3.x, S, X3.x);
247d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(X3.x, S, X3.x);
248d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
249d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S);
250d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(S, X3.x, Y3.x);
251d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.multiply(Y3.x, M, Y3.x);
252d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.subtract(Y3.x, t1, Y3.x);
253d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
254d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M);
255d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        SecP224R1Field.twice(Y1.x, Z3.x);
256d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!Z1IsOne)
257d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
258d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
259d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
260d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
261d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
262d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
263d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
264d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint twicePlus(ECPoint b)
265d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
266d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this == b)
267d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
268d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return threeTimes();
269d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
270d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
271d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
272d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
273d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
274d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (b.isInfinity())
275d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
276d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return twice();
277d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
278d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
279d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECFieldElement Y1 = this.y;
280d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (Y1.isZero())
281d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
282d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return b;
283d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
284d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
285d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return twice().add(b);
286d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
287d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
288d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint threeTimes()
289d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
290d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity() || this.y.isZero())
291d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
292d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
293d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
294d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
295d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        // NOTE: Be careful about recursions between twicePlus and threeTimes
296d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return twice().add(this);
297d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
298d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
299d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint negate()
300d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
301d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (this.isInfinity())
302d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
303d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
304d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
305d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
306d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
307d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
308d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root}
309