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