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