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