ed25519 1.0.0-jruby → 1.1.0-jruby

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGES.md +13 -0
  4. data/README.md +9 -9
  5. data/Rakefile +3 -3
  6. data/ext/ed25519_jruby/LICENSE.txt +123 -0
  7. data/ext/ed25519_jruby/README.md +77 -0
  8. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAEngine.java +491 -0
  9. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAKey.java +31 -0
  10. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPrivateKey.java +338 -0
  11. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPublicKey.java +275 -0
  12. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSASecurityProvider.java +59 -0
  13. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyFactory.java +75 -0
  14. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyPairGenerator.java +97 -0
  15. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/Utils.java +103 -0
  16. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Constants.java +23 -0
  17. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Curve.java +100 -0
  18. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Encoding.java +54 -0
  19. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Field.java +99 -0
  20. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/FieldElement.java +76 -0
  21. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/GroupElement.java +1034 -0
  22. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ScalarOps.java +34 -0
  23. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerFieldElement.java +131 -0
  24. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerLittleEndianEncoding.java +102 -0
  25. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerScalarOps.java +37 -0
  26. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/package.html +6 -0
  27. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519FieldElement.java +988 -0
  28. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519LittleEndianEncoding.java +256 -0
  29. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519ScalarOps.java +693 -0
  30. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAGenParameterSpec.java +32 -0
  31. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveSpec.java +35 -0
  32. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveTable.java +71 -0
  33. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java +97 -0
  34. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java +133 -0
  35. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPublicKeySpec.java +61 -0
  36. data/ext/ed25519_jruby/org/cryptosphere/Ed25519Provider.java +95 -0
  37. data/lib/ed25519.rb +8 -8
  38. data/lib/ed25519/signing_key.rb +9 -0
  39. data/lib/ed25519/version.rb +1 -1
  40. data/lib/ed25519_java.jar +0 -0
  41. metadata +32 -3
  42. data/ext/ed25519_java/org/cryptosphere/ed25519.java +0 -228
  43. data/lib/ed25519/provider/jruby.rb +0 -39
@@ -0,0 +1,54 @@
1
+ /**
2
+ * EdDSA-Java by str4d
3
+ *
4
+ * To the extent possible under law, the person who associated CC0 with
5
+ * EdDSA-Java has waived all copyright and related or neighboring rights
6
+ * to EdDSA-Java.
7
+ *
8
+ * You should have received a copy of the CC0 legalcode along with this
9
+ * work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
10
+ *
11
+ */
12
+ package net.i2p.crypto.eddsa.math;
13
+
14
+ /**
15
+ * Common interface for all $(b-1)$-bit encodings of elements
16
+ * of EdDSA finite fields.
17
+ * @author str4d
18
+ *
19
+ */
20
+ public abstract class Encoding {
21
+ protected Field f;
22
+
23
+ public synchronized void setField(Field f) {
24
+ if (this.f != null)
25
+ throw new IllegalStateException("already set");
26
+ this.f = f;
27
+ }
28
+
29
+ /**
30
+ * Encode a FieldElement in its $(b-1)$-bit encoding.
31
+ * @param x the FieldElement to encode
32
+ * @return the $(b-1)$-bit encoding of this FieldElement.
33
+ */
34
+ public abstract byte[] encode(FieldElement x);
35
+
36
+ /**
37
+ * Decode a FieldElement from its $(b-1)$-bit encoding.
38
+ * The highest bit is masked out.
39
+ * @param in the $(b-1)$-bit encoding of a FieldElement.
40
+ * @return the FieldElement represented by 'val'.
41
+ */
42
+ public abstract FieldElement decode(byte[] in);
43
+
44
+ /**
45
+ * From the Ed25519 paper:<br>
46
+ * $x$ is negative if the $(b-1)$-bit encoding of $x$ is lexicographically larger
47
+ * than the $(b-1)$-bit encoding of -x. If $q$ is an odd prime and the encoding
48
+ * is the little-endian representation of $\{0, 1,\dots, q-1\}$ then the negative
49
+ * elements of $F_q$ are $\{1, 3, 5,\dots, q-2\}$.
50
+ * @param x the FieldElement to check
51
+ * @return true if negative
52
+ */
53
+ public abstract boolean isNegative(FieldElement x);
54
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * EdDSA-Java by str4d
3
+ *
4
+ * To the extent possible under law, the person who associated CC0 with
5
+ * EdDSA-Java has waived all copyright and related or neighboring rights
6
+ * to EdDSA-Java.
7
+ *
8
+ * You should have received a copy of the CC0 legalcode along with this
9
+ * work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
10
+ *
11
+ */
12
+ package net.i2p.crypto.eddsa.math;
13
+
14
+ import java.io.Serializable;
15
+
16
+ /**
17
+ * An EdDSA finite field. Includes several pre-computed values.
18
+ * @author str4d
19
+ *
20
+ */
21
+ public class Field implements Serializable {
22
+ private static final long serialVersionUID = 8746587465875676L;
23
+
24
+ public final FieldElement ZERO;
25
+ public final FieldElement ONE;
26
+ public final FieldElement TWO;
27
+ public final FieldElement FOUR;
28
+ public final FieldElement FIVE;
29
+ public final FieldElement EIGHT;
30
+
31
+ private final int b;
32
+ private final FieldElement q;
33
+ /**
34
+ * q-2
35
+ */
36
+ private final FieldElement qm2;
37
+ /**
38
+ * (q-5) / 8
39
+ */
40
+ private final FieldElement qm5d8;
41
+ private final Encoding enc;
42
+
43
+ public Field(int b, byte[] q, Encoding enc) {
44
+ this.b = b;
45
+ this.enc = enc;
46
+ this.enc.setField(this);
47
+
48
+ this.q = fromByteArray(q);
49
+
50
+ // Set up constants
51
+ ZERO = fromByteArray(Constants.ZERO);
52
+ ONE = fromByteArray(Constants.ONE);
53
+ TWO = fromByteArray(Constants.TWO);
54
+ FOUR = fromByteArray(Constants.FOUR);
55
+ FIVE = fromByteArray(Constants.FIVE);
56
+ EIGHT = fromByteArray(Constants.EIGHT);
57
+
58
+ // Precompute values
59
+ qm2 = this.q.subtract(TWO);
60
+ qm5d8 = this.q.subtract(FIVE).divide(EIGHT);
61
+ }
62
+
63
+ public FieldElement fromByteArray(byte[] x) {
64
+ return enc.decode(x);
65
+ }
66
+
67
+ public int getb() {
68
+ return b;
69
+ }
70
+
71
+ public FieldElement getQ() {
72
+ return q;
73
+ }
74
+
75
+ public FieldElement getQm2() {
76
+ return qm2;
77
+ }
78
+
79
+ public FieldElement getQm5d8() {
80
+ return qm5d8;
81
+ }
82
+
83
+ public Encoding getEncoding(){
84
+ return enc;
85
+ }
86
+
87
+ @Override
88
+ public int hashCode() {
89
+ return q.hashCode();
90
+ }
91
+
92
+ @Override
93
+ public boolean equals(Object obj) {
94
+ if (!(obj instanceof Field))
95
+ return false;
96
+ Field f = (Field) obj;
97
+ return b == f.b && q.equals(f.q);
98
+ }
99
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * EdDSA-Java by str4d
3
+ *
4
+ * To the extent possible under law, the person who associated CC0 with
5
+ * EdDSA-Java has waived all copyright and related or neighboring rights
6
+ * to EdDSA-Java.
7
+ *
8
+ * You should have received a copy of the CC0 legalcode along with this
9
+ * work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
10
+ *
11
+ */
12
+ package net.i2p.crypto.eddsa.math;
13
+
14
+ import java.io.Serializable;
15
+
16
+ /**
17
+ * Note: concrete subclasses must implement hashCode() and equals()
18
+ */
19
+ public abstract class FieldElement implements Serializable {
20
+ private static final long serialVersionUID = 1239527465875676L;
21
+
22
+ protected final Field f;
23
+
24
+ public FieldElement(Field f) {
25
+ if (null == f) {
26
+ throw new IllegalArgumentException("field cannot be null");
27
+ }
28
+ this.f = f;
29
+ }
30
+
31
+ /**
32
+ * Encode a FieldElement in its $(b-1)$-bit encoding.
33
+ * @return the $(b-1)$-bit encoding of this FieldElement.
34
+ */
35
+ public byte[] toByteArray() {
36
+ return f.getEncoding().encode(this);
37
+ }
38
+
39
+ public abstract boolean isNonZero();
40
+
41
+ public boolean isNegative() {
42
+ return f.getEncoding().isNegative(this);
43
+ }
44
+
45
+ public abstract FieldElement add(FieldElement val);
46
+
47
+ public FieldElement addOne() {
48
+ return add(f.ONE);
49
+ }
50
+
51
+ public abstract FieldElement subtract(FieldElement val);
52
+
53
+ public FieldElement subtractOne() {
54
+ return subtract(f.ONE);
55
+ }
56
+
57
+ public abstract FieldElement negate();
58
+
59
+ public FieldElement divide(FieldElement val) {
60
+ return multiply(val.invert());
61
+ }
62
+
63
+ public abstract FieldElement multiply(FieldElement val);
64
+
65
+ public abstract FieldElement square();
66
+
67
+ public abstract FieldElement squareAndDouble();
68
+
69
+ public abstract FieldElement invert();
70
+
71
+ public abstract FieldElement pow22523();
72
+
73
+ public abstract FieldElement cmov(FieldElement val, final int b);
74
+
75
+ // Note: concrete subclasses must implement hashCode() and equals()
76
+ }
@@ -0,0 +1,1034 @@
1
+ /**
2
+ * EdDSA-Java by str4d
3
+ *
4
+ * To the extent possible under law, the person who associated CC0 with
5
+ * EdDSA-Java has waived all copyright and related or neighboring rights
6
+ * to EdDSA-Java.
7
+ *
8
+ * You should have received a copy of the CC0 legalcode along with this
9
+ * work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
10
+ *
11
+ */
12
+ package net.i2p.crypto.eddsa.math;
13
+
14
+ import net.i2p.crypto.eddsa.Utils;
15
+
16
+ import java.io.Serializable;
17
+ import java.util.Arrays;
18
+
19
+ /**
20
+ * A point $(x,y)$ on an EdDSA curve.
21
+ * <p>
22
+ * Reviewed/commented by Bloody Rookie (nemproject@gmx.de)
23
+ * <p>
24
+ * Literature:<br>
25
+ * [1] Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe and Bo-Yin Yang : High-speed high-security signatures<br>
26
+ * [2] Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, Ed Dawson: Twisted Edwards Curves Revisited<br>
27
+ * [3] Daniel J. Bernsteina, Tanja Lange: A complete set of addition laws for incomplete Edwards curves<br>
28
+ * [4] Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange and Christiane Peters: Twisted Edwards Curves<br>
29
+ * [5] Christiane Pascale Peters: Curves, Codes, and Cryptography (PhD thesis)<br>
30
+ * [6] Daniel J. Bernstein, Peter Birkner, Tanja Lange and Christiane Peters: Optimizing double-base elliptic-curve single-scalar multiplication<br>
31
+ *
32
+ * @author str4d
33
+ */
34
+ public class GroupElement implements Serializable {
35
+ private static final long serialVersionUID = 2395879087349587L;
36
+
37
+ /**
38
+ * Available representations for a group element.
39
+ * <ul>
40
+ * <li>P2: Projective representation $(X:Y:Z)$ satisfying $x=X/Z, y=Y/Z$.
41
+ * <li>P3: Extended projective representation $(X:Y:Z:T)$ satisfying $x=X/Z, y=Y/Z, XY=ZT$.
42
+ * <li>P1P1: Completed representation $((X:Z), (Y:T))$ satisfying $x=X/Z, y=Y/T$.
43
+ * <li>PRECOMP: Precomputed representation $(y+x, y-x, 2dxy)$.
44
+ * <li>CACHED: Cached representation $(Y+X, Y-X, Z, 2dT)$
45
+ * </ul>
46
+ */
47
+ public enum Representation {
48
+ /** Projective ($P^2$): $(X:Y:Z)$ satisfying $x=X/Z, y=Y/Z$ */
49
+ P2,
50
+ /** Extended ($P^3$): $(X:Y:Z:T)$ satisfying $x=X/Z, y=Y/Z, XY=ZT$ */
51
+ P3,
52
+ /** Completed ($P \times P$): $((X:Z),(Y:T))$ satisfying $x=X/Z, y=Y/T$ */
53
+ P1P1,
54
+ /** Precomputed (Duif): $(y+x,y-x,2dxy)$ */
55
+ PRECOMP,
56
+ /** Cached: $(Y+X,Y-X,Z,2dT)$ */
57
+ CACHED
58
+ }
59
+
60
+ /**
61
+ * Creates a new group element in P2 representation.
62
+ *
63
+ * @param curve The curve.
64
+ * @param X The $X$ coordinate.
65
+ * @param Y The $Y$ coordinate.
66
+ * @param Z The $Z$ coordinate.
67
+ * @return The group element in P2 representation.
68
+ */
69
+ public static GroupElement p2(
70
+ final Curve curve,
71
+ final FieldElement X,
72
+ final FieldElement Y,
73
+ final FieldElement Z) {
74
+ return new GroupElement(curve, Representation.P2, X, Y, Z, null);
75
+ }
76
+
77
+ /**
78
+ * Creates a new group element in P3 representation.
79
+ *
80
+ * @param curve The curve.
81
+ * @param X The $X$ coordinate.
82
+ * @param Y The $Y$ coordinate.
83
+ * @param Z The $Z$ coordinate.
84
+ * @param T The $T$ coordinate.
85
+ * @return The group element in P3 representation.
86
+ */
87
+ public static GroupElement p3(
88
+ final Curve curve,
89
+ final FieldElement X,
90
+ final FieldElement Y,
91
+ final FieldElement Z,
92
+ final FieldElement T) {
93
+ return new GroupElement(curve, Representation.P3, X, Y, Z, T);
94
+ }
95
+
96
+ /**
97
+ * Creates a new group element in P1P1 representation.
98
+ *
99
+ * @param curve The curve.
100
+ * @param X The $X$ coordinate.
101
+ * @param Y The $Y$ coordinate.
102
+ * @param Z The $Z$ coordinate.
103
+ * @param T The $T$ coordinate.
104
+ * @return The group element in P1P1 representation.
105
+ */
106
+ public static GroupElement p1p1(
107
+ final Curve curve,
108
+ final FieldElement X,
109
+ final FieldElement Y,
110
+ final FieldElement Z,
111
+ final FieldElement T) {
112
+ return new GroupElement(curve, Representation.P1P1, X, Y, Z, T);
113
+ }
114
+
115
+ /**
116
+ * Creates a new group element in PRECOMP representation.
117
+ *
118
+ * @param curve The curve.
119
+ * @param ypx The $y + x$ value.
120
+ * @param ymx The $y - x$ value.
121
+ * @param xy2d The $2 * d * x * y$ value.
122
+ * @return The group element in PRECOMP representation.
123
+ */
124
+ public static GroupElement precomp(
125
+ final Curve curve,
126
+ final FieldElement ypx,
127
+ final FieldElement ymx,
128
+ final FieldElement xy2d) {
129
+ return new GroupElement(curve, Representation.PRECOMP, ypx, ymx, xy2d, null);
130
+ }
131
+
132
+ /**
133
+ * Creates a new group element in CACHED representation.
134
+ *
135
+ * @param curve The curve.
136
+ * @param YpX The $Y + X$ value.
137
+ * @param YmX The $Y - X$ value.
138
+ * @param Z The $Z$ coordinate.
139
+ * @param T2d The $2 * d * T$ value.
140
+ * @return The group element in CACHED representation.
141
+ */
142
+ public static GroupElement cached(
143
+ final Curve curve,
144
+ final FieldElement YpX,
145
+ final FieldElement YmX,
146
+ final FieldElement Z,
147
+ final FieldElement T2d) {
148
+ return new GroupElement(curve, Representation.CACHED, YpX, YmX, Z, T2d);
149
+ }
150
+
151
+ /**
152
+ * Variable is package private only so that tests run.
153
+ */
154
+ final Curve curve;
155
+
156
+ /**
157
+ * Variable is package private only so that tests run.
158
+ */
159
+ final Representation repr;
160
+
161
+ /**
162
+ * Variable is package private only so that tests run.
163
+ */
164
+ final FieldElement X;
165
+
166
+ /**
167
+ * Variable is package private only so that tests run.
168
+ */
169
+ final FieldElement Y;
170
+
171
+ /**
172
+ * Variable is package private only so that tests run.
173
+ */
174
+ final FieldElement Z;
175
+
176
+ /**
177
+ * Variable is package private only so that tests run.
178
+ */
179
+ final FieldElement T;
180
+
181
+ /**
182
+ * Precomputed table for {@link #scalarMultiply(byte[])},
183
+ * filled if necessary.
184
+ * <p>
185
+ * Variable is package private only so that tests run.
186
+ */
187
+ GroupElement[][] precmp;
188
+
189
+ /**
190
+ * Precomputed table for {@link #doubleScalarMultiplyVariableTime(GroupElement, byte[], byte[])},
191
+ * filled if necessary.
192
+ * <p>
193
+ * Variable is package private only so that tests run.
194
+ */
195
+ GroupElement[] dblPrecmp;
196
+
197
+ /**
198
+ * Creates a group element for a curve.
199
+ *
200
+ * @param curve The curve.
201
+ * @param repr The representation used to represent the group element.
202
+ * @param X The $X$ coordinate.
203
+ * @param Y The $Y$ coordinate.
204
+ * @param Z The $Z$ coordinate.
205
+ * @param T The $T$ coordinate.
206
+ */
207
+ public GroupElement(
208
+ final Curve curve,
209
+ final Representation repr,
210
+ final FieldElement X,
211
+ final FieldElement Y,
212
+ final FieldElement Z,
213
+ final FieldElement T) {
214
+ this.curve = curve;
215
+ this.repr = repr;
216
+ this.X = X;
217
+ this.Y = Y;
218
+ this.Z = Z;
219
+ this.T = T;
220
+ }
221
+
222
+ /**
223
+ * Creates a group element for a curve from a given encoded point.
224
+ * <p>
225
+ * A point $(x,y)$ is encoded by storing $y$ in bit 0 to bit 254 and the sign of $x$ in bit 255.
226
+ * $x$ is recovered in the following way:
227
+ * </p><ul>
228
+ * <li>$x = sign(x) * \sqrt{(y^2 - 1) / (d * y^2 + 1)} = sign(x) * \sqrt{u / v}$ with $u = y^2 - 1$ and $v = d * y^2 + 1$.
229
+ * <li>Setting $β = (u * v^3) * (u * v^7)^{((q - 5) / 8)}$ one has $β^2 = \pm(u / v)$.
230
+ * <li>If $v * β = -u$ multiply $β$ with $i=\sqrt{-1}$.
231
+ * <li>Set $x := β$.
232
+ * <li>If $sign(x) \ne$ bit 255 of $s$ then negate $x$.
233
+ * </ul>
234
+ *
235
+ * @param curve The curve.
236
+ * @param s The encoded point.
237
+ */
238
+ public GroupElement(final Curve curve, final byte[] s) {
239
+ FieldElement x, y, yy, u, v, v3, vxx, check;
240
+ y = curve.getField().fromByteArray(s);
241
+ yy = y.square();
242
+
243
+ // u = y^2-1
244
+ u = yy.subtractOne();
245
+
246
+ // v = dy^2+1
247
+ v = yy.multiply(curve.getD()).addOne();
248
+
249
+ // v3 = v^3
250
+ v3 = v.square().multiply(v);
251
+
252
+ // x = (v3^2)vu, aka x = uv^7
253
+ x = v3.square().multiply(v).multiply(u);
254
+
255
+ // x = (uv^7)^((q-5)/8)
256
+ x = x.pow22523();
257
+
258
+ // x = uv^3(uv^7)^((q-5)/8)
259
+ x = v3.multiply(u).multiply(x);
260
+
261
+ vxx = x.square().multiply(v);
262
+ check = vxx.subtract(u); // vx^2-u
263
+ if (check.isNonZero()) {
264
+ check = vxx.add(u); // vx^2+u
265
+
266
+ if (check.isNonZero())
267
+ throw new IllegalArgumentException("not a valid GroupElement");
268
+ x = x.multiply(curve.getI());
269
+ }
270
+
271
+ if ((x.isNegative() ? 1 : 0) != Utils.bit(s, curve.getField().getb()-1)) {
272
+ x = x.negate();
273
+ }
274
+
275
+ this.curve = curve;
276
+ this.repr = Representation.P3;
277
+ this.X = x;
278
+ this.Y = y;
279
+ this.Z = curve.getField().ONE;
280
+ this.T = this.X.multiply(this.Y);
281
+ }
282
+
283
+ /**
284
+ * Gets the curve of the group element.
285
+ *
286
+ * @return The curve.
287
+ */
288
+ public Curve getCurve() {
289
+ return this.curve;
290
+ }
291
+
292
+ /**
293
+ * Gets the representation of the group element.
294
+ *
295
+ * @return The representation.
296
+ */
297
+ public Representation getRepresentation() {
298
+ return this.repr;
299
+ }
300
+
301
+ /**
302
+ * Gets the $X$ value of the group element.
303
+ * This is for most representation the projective $X$ coordinate.
304
+ *
305
+ * @return The $X$ value.
306
+ */
307
+ public FieldElement getX() {
308
+ return this.X;
309
+ }
310
+
311
+ /**
312
+ * Gets the $Y$ value of the group element.
313
+ * This is for most representation the projective $Y$ coordinate.
314
+ *
315
+ * @return The $Y$ value.
316
+ */
317
+ public FieldElement getY() {
318
+ return this.Y;
319
+ }
320
+
321
+ /**
322
+ * Gets the $Z$ value of the group element.
323
+ * This is for most representation the projective $Z$ coordinate.
324
+ *
325
+ * @return The $Z$ value.
326
+ */
327
+ public FieldElement getZ() {
328
+ return this.Z;
329
+ }
330
+
331
+ /**
332
+ * Gets the $T$ value of the group element.
333
+ * This is for most representation the projective $T$ coordinate.
334
+ *
335
+ * @return The $T$ value.
336
+ */
337
+ public FieldElement getT() {
338
+ return this.T;
339
+ }
340
+
341
+ /**
342
+ * Converts the group element to an encoded point on the curve.
343
+ *
344
+ * @return The encoded point as byte array.
345
+ */
346
+ public byte[] toByteArray() {
347
+ switch (this.repr) {
348
+ case P2:
349
+ case P3:
350
+ FieldElement recip = Z.invert();
351
+ FieldElement x = X.multiply(recip);
352
+ FieldElement y = Y.multiply(recip);
353
+ byte[] s = y.toByteArray();
354
+ s[s.length-1] |= (x.isNegative() ? (byte) 0x80 : 0);
355
+ return s;
356
+ default:
357
+ return toP2().toByteArray();
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Converts the group element to the P2 representation.
363
+ *
364
+ * @return The group element in the P2 representation.
365
+ */
366
+ public GroupElement toP2() {
367
+ return toRep(Representation.P2);
368
+ }
369
+
370
+ /**
371
+ * Converts the group element to the P3 representation.
372
+ *
373
+ * @return The group element in the P3 representation.
374
+ */
375
+ public GroupElement toP3() {
376
+ return toRep(Representation.P3);
377
+ }
378
+
379
+ /**
380
+ * Converts the group element to the CACHED representation.
381
+ *
382
+ * @return The group element in the CACHED representation.
383
+ */
384
+ public GroupElement toCached() {
385
+ return toRep(Representation.CACHED);
386
+ }
387
+
388
+ /**
389
+ * Convert a GroupElement from one Representation to another.
390
+ * TODO-CR: Add additional conversion?
391
+ * $r = p$
392
+ * <p>
393
+ * Supported conversions:
394
+ * <p><ul>
395
+ * <li>P3 $\rightarrow$ P2
396
+ * <li>P3 $\rightarrow$ CACHED (1 multiply, 1 add, 1 subtract)
397
+ * <li>P1P1 $\rightarrow$ P2 (3 multiply)
398
+ * <li>P1P1 $\rightarrow$ P3 (4 multiply)
399
+ *
400
+ * @param repr The representation to convert to.
401
+ * @return A new group element in the given representation.
402
+ */
403
+ private GroupElement toRep(final Representation repr) {
404
+ switch (this.repr) {
405
+ case P2:
406
+ switch (repr) {
407
+ case P2:
408
+ return p2(this.curve, this.X, this.Y, this.Z);
409
+ default:
410
+ throw new IllegalArgumentException();
411
+ }
412
+ case P3:
413
+ switch (repr) {
414
+ case P2:
415
+ return p2(this.curve, this.X, this.Y, this.Z);
416
+ case P3:
417
+ return p3(this.curve, this.X, this.Y, this.Z, this.T);
418
+ case CACHED:
419
+ return cached(this.curve, this.Y.add(this.X), this.Y.subtract(this.X), this.Z, this.T.multiply(this.curve.get2D()));
420
+ default:
421
+ throw new IllegalArgumentException();
422
+ }
423
+ case P1P1:
424
+ switch (repr) {
425
+ case P2:
426
+ return p2(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T));
427
+ case P3:
428
+ return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y));
429
+ case P1P1:
430
+ return p1p1(this.curve, this.X, this.Y, this.Z, this.T);
431
+ default:
432
+ throw new IllegalArgumentException();
433
+ }
434
+ case PRECOMP:
435
+ switch (repr) {
436
+ case PRECOMP:
437
+ return precomp(this.curve, this.X, this.Y, this.Z);
438
+ default:
439
+ throw new IllegalArgumentException();
440
+ }
441
+ case CACHED:
442
+ switch (repr) {
443
+ case CACHED:
444
+ return cached(this.curve, this.X, this.Y, this.Z, this.T);
445
+ default:
446
+ throw new IllegalArgumentException();
447
+ }
448
+ default:
449
+ throw new UnsupportedOperationException();
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Precomputes several tables.
455
+ * <p>
456
+ * The precomputed tables are used for {@link #scalarMultiply(byte[])}
457
+ * and {@link #doubleScalarMultiplyVariableTime(GroupElement, byte[], byte[])}.
458
+ *
459
+ * @param precomputeSingle should the matrix for scalarMultiply() be precomputed?
460
+ */
461
+ public synchronized void precompute(final boolean precomputeSingle) {
462
+ GroupElement Bi;
463
+
464
+ if (precomputeSingle && this.precmp == null) {
465
+ // Precomputation for single scalar multiplication.
466
+ this.precmp = new GroupElement[32][8];
467
+ // TODO-CR BR: check that this == base point when the method is called.
468
+ Bi = this;
469
+ for (int i = 0; i < 32; i++) {
470
+ GroupElement Bij = Bi;
471
+ for (int j = 0; j < 8; j++) {
472
+ final FieldElement recip = Bij.Z.invert();
473
+ final FieldElement x = Bij.X.multiply(recip);
474
+ final FieldElement y = Bij.Y.multiply(recip);
475
+ this.precmp[i][j] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
476
+ Bij = Bij.add(Bi.toCached()).toP3();
477
+ }
478
+ // Only every second summand is precomputed (16^2 = 256)
479
+ for (int k = 0; k < 8; k++) {
480
+ Bi = Bi.add(Bi.toCached()).toP3();
481
+ }
482
+ }
483
+ }
484
+
485
+ // Precomputation for double scalar multiplication.
486
+ // P,3P,5P,7P,9P,11P,13P,15P
487
+ if (this.dblPrecmp != null)
488
+ return;
489
+ this.dblPrecmp = new GroupElement[8];
490
+ Bi = this;
491
+ for (int i = 0; i < 8; i++) {
492
+ final FieldElement recip = Bi.Z.invert();
493
+ final FieldElement x = Bi.X.multiply(recip);
494
+ final FieldElement y = Bi.Y.multiply(recip);
495
+ this.dblPrecmp[i] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
496
+ // Bi = edwards(B,edwards(B,Bi))
497
+ Bi = this.add(this.add(Bi.toCached()).toP3().toCached()).toP3();
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Doubles a given group element $p$ in $P^2$ or $P^3$ representation and returns the result in $P \times P$ representation.
503
+ * $r = 2 * p$ where $p = (X : Y : Z)$ or $p = (X : Y : Z : T)$
504
+ * <p>
505
+ * $r$ in $P \times P$ representation:
506
+ * <p>
507
+ * $r = ((X' : Z'), (Y' : T'))$ where
508
+ * </p><ul>
509
+ * <li>$X' = (X + Y)^2 - (Y^2 + X^2)$
510
+ * <li>$Y' = Y^2 + X^2$
511
+ * <li>$Z' = y^2 - X^2$
512
+ * <li>$T' = 2 * Z^2 - (y^2 - X^2)$
513
+ * </ul><p>
514
+ * $r$ converted from $P \times P$ to $P^2$ representation:
515
+ * <p>
516
+ * $r = (X'' : Y'' : Z'')$ where
517
+ * </p><ul>
518
+ * <li>$X'' = X' * Z' = ((X + Y)^2 - Y^2 - X^2) * (2 * Z^2 - (y^2 - X^2))$
519
+ * <li>$Y'' = Y' * T' = (Y^2 + X^2) * (2 * Z^2 - (y^2 - X^2))$
520
+ * <li>$Z'' = Z' * T' = (y^2 - X^2) * (2 * Z^2 - (y^2 - X^2))$
521
+ * </ul><p>
522
+ * Formula for the $P^2$ representation is in agreement with the formula given in [4] page 12 (with $a = -1$)
523
+ * up to a common factor -1 which does not matter:
524
+ * <p>
525
+ * $$
526
+ * B = (X + Y)^2; C = X^2; D = Y^2; E = -C = -X^2; F := E + D = Y^2 - X^2; H = Z^2; J = F − 2 * H; \\
527
+ * X3 = (B − C − D) · J = X' * (-T'); \\
528
+ * Y3 = F · (E − D) = Z' * (-Y'); \\
529
+ * Z3 = F · J = Z' * (-T').
530
+ * $$
531
+ *
532
+ * @return The P1P1 representation
533
+ */
534
+ public GroupElement dbl() {
535
+ switch (this.repr) {
536
+ case P2:
537
+ case P3: // Ignore T for P3 representation
538
+ FieldElement XX, YY, B, A, AA, Yn, Zn;
539
+ XX = this.X.square();
540
+ YY = this.Y.square();
541
+ B = this.Z.squareAndDouble();
542
+ A = this.X.add(this.Y);
543
+ AA = A.square();
544
+ Yn = YY.add(XX);
545
+ Zn = YY.subtract(XX);
546
+ return p1p1(this.curve, AA.subtract(Yn), Yn, Zn, B.subtract(Zn));
547
+ default:
548
+ throw new UnsupportedOperationException();
549
+ }
550
+ }
551
+
552
+ /**
553
+ * GroupElement addition using the twisted Edwards addition law with
554
+ * extended coordinates (Hisil2008).
555
+ * <p>
556
+ * this must be in $P^3$ representation and $q$ in PRECOMP representation.
557
+ * $r = p + q$ where $p = this = (X1 : Y1 : Z1 : T1), q = (q.X, q.Y, q.Z) = (Y2/Z2 + X2/Z2, Y2/Z2 - X2/Z2, 2 * d * X2/Z2 * Y2/Z2)$
558
+ * <p>
559
+ * $r$ in $P \times P$ representation:
560
+ * <p>
561
+ * $r = ((X' : Z'), (Y' : T'))$ where
562
+ * <p><ul>
563
+ * <li>$X' = (Y1 + X1) * q.X - (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2)) * 1/Z2$
564
+ * <li>$Y' = (Y1 + X1) * q.X + (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2)) * 1/Z2$
565
+ * <li>$Z' = 2 * Z1 + T1 * q.Z = 2 * Z1 + T1 * 2 * d * X2 * Y2 * 1/Z2^2 = (2 * Z1 * Z2 + 2 * d * T1 * T2) * 1/Z2$
566
+ * <li>$T' = 2 * Z1 - T1 * q.Z = 2 * Z1 - T1 * 2 * d * X2 * Y2 * 1/Z2^2 = (2 * Z1 * Z2 - 2 * d * T1 * T2) * 1/Z2$
567
+ * </ul><p>
568
+ * Setting $A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2$ we get
569
+ * <p><ul>
570
+ * <li>$X' = (B - A) * 1/Z2$
571
+ * <li>$Y' = (B + A) * 1/Z2$
572
+ * <li>$Z' = (D + C) * 1/Z2$
573
+ * <li>$T' = (D - C) * 1/Z2$
574
+ * </ul><p>
575
+ * $r$ converted from $P \times P$ to $P^2$ representation:
576
+ * <p>
577
+ * $r = (X'' : Y'' : Z'' : T'')$ where
578
+ * <p><ul>
579
+ * <li>$X'' = X' * Z' = (B - A) * (D + C) * 1/Z2^2$
580
+ * <li>$Y'' = Y' * T' = (B + A) * (D - C) * 1/Z2^2$
581
+ * <li>$Z'' = Z' * T' = (D + C) * (D - C) * 1/Z2^2$
582
+ * <li>$T'' = X' * Y' = (B - A) * (B + A) * 1/Z2^2$
583
+ * </ul><p>
584
+ * TODO-CR BR: Formula for the $P^2$ representation is not in agreement with the formula given in [2] page 6<br>
585
+ * TODO-CR BR: (the common factor $1/Z2^2$ does not matter):<br>
586
+ * $$
587
+ * E = B - A, F = D - C, G = D + C, H = B + A \\
588
+ * X3 = E * F = (B - A) * (D - C); \\
589
+ * Y3 = G * H = (D + C) * (B + A); \\
590
+ * Z3 = F * G = (D - C) * (D + C); \\
591
+ * T3 = E * H = (B - A) * (B + A);
592
+ * $$
593
+ *
594
+ * @param q the PRECOMP representation of the GroupElement to add.
595
+ * @return the P1P1 representation of the result.
596
+ */
597
+ private GroupElement madd(GroupElement q) {
598
+ if (this.repr != Representation.P3)
599
+ throw new UnsupportedOperationException();
600
+ if (q.repr != Representation.PRECOMP)
601
+ throw new IllegalArgumentException();
602
+
603
+ FieldElement YpX, YmX, A, B, C, D;
604
+ YpX = this.Y.add(this.X);
605
+ YmX = this.Y.subtract(this.X);
606
+ A = YpX.multiply(q.X); // q->y+x
607
+ B = YmX.multiply(q.Y); // q->y-x
608
+ C = q.Z.multiply(this.T); // q->2dxy
609
+ D = this.Z.add(this.Z);
610
+ return p1p1(this.curve, A.subtract(B), A.add(B), D.add(C), D.subtract(C));
611
+ }
612
+
613
+ /**
614
+ * GroupElement subtraction using the twisted Edwards addition law with
615
+ * extended coordinates (Hisil2008).
616
+ * <p>
617
+ * this must be in $P^3$ representation and $q$ in PRECOMP representation.
618
+ * $r = p - q$ where $p = this = (X1 : Y1 : Z1 : T1), q = (q.X, q.Y, q.Z) = (Y2/Z2 + X2/Z2, Y2/Z2 - X2/Z2, 2 * d * X2/Z2 * Y2/Z2)$
619
+ * <p>
620
+ * Negating $q$ means negating the value of $X2$ and $T2$ (the latter is irrelevant here).
621
+ * The formula is in accordance to {@link #madd the above addition}.
622
+ *
623
+ * @param q the PRECOMP representation of the GroupElement to subtract.
624
+ * @return the P1P1 representation of the result.
625
+ */
626
+ private GroupElement msub(GroupElement q) {
627
+ if (this.repr != Representation.P3)
628
+ throw new UnsupportedOperationException();
629
+ if (q.repr != Representation.PRECOMP)
630
+ throw new IllegalArgumentException();
631
+
632
+ FieldElement YpX, YmX, A, B, C, D;
633
+ YpX = this.Y.add(this.X);
634
+ YmX = this.Y.subtract(this.X);
635
+ A = YpX.multiply(q.Y); // q->y-x
636
+ B = YmX.multiply(q.X); // q->y+x
637
+ C = q.Z.multiply(this.T); // q->2dxy
638
+ D = this.Z.add(this.Z);
639
+ return p1p1(this.curve, A.subtract(B), A.add(B), D.subtract(C), D.add(C));
640
+ }
641
+
642
+ /**
643
+ * GroupElement addition using the twisted Edwards addition law with
644
+ * extended coordinates (Hisil2008).
645
+ * <p>
646
+ * this must be in $P^3$ representation and $q$ in CACHED representation.
647
+ * $r = p + q$ where $p = this = (X1 : Y1 : Z1 : T1), q = (q.X, q.Y, q.Z, q.T) = (Y2 + X2, Y2 - X2, Z2, 2 * d * T2)$
648
+ * <p>
649
+ * $r$ in $P \times P$ representation:
650
+ * </p><ul>
651
+ * <li>$X' = (Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2)$
652
+ * <li>$Y' = (Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2)$
653
+ * <li>$Z' = 2 * Z1 * Z2 + 2 * d * T1 * T2$
654
+ * <li>$T' = 2 * Z1 * T2 - 2 * d * T1 * T2$
655
+ * </ul><p>
656
+ * Setting $A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2$ we get
657
+ * </p><ul>
658
+ * <li>$X' = (B - A)$
659
+ * <li>$Y' = (B + A)$
660
+ * <li>$Z' = (D + C)$
661
+ * <li>$T' = (D - C)$
662
+ * </ul><p>
663
+ * Same result as in {@link #madd} (up to a common factor which does not matter).
664
+ *
665
+ * @param q the CACHED representation of the GroupElement to add.
666
+ * @return the P1P1 representation of the result.
667
+ */
668
+ public GroupElement add(GroupElement q) {
669
+ if (this.repr != Representation.P3)
670
+ throw new UnsupportedOperationException();
671
+ if (q.repr != Representation.CACHED)
672
+ throw new IllegalArgumentException();
673
+
674
+ FieldElement YpX, YmX, A, B, C, ZZ, D;
675
+ YpX = this.Y.add(this.X);
676
+ YmX = this.Y.subtract(this.X);
677
+ A = YpX.multiply(q.X); // q->Y+X
678
+ B = YmX.multiply(q.Y); // q->Y-X
679
+ C = q.T.multiply(this.T); // q->2dT
680
+ ZZ = this.Z.multiply(q.Z);
681
+ D = ZZ.add(ZZ);
682
+ return p1p1(this.curve, A.subtract(B), A.add(B), D.add(C), D.subtract(C));
683
+ }
684
+
685
+ /**
686
+ * GroupElement subtraction using the twisted Edwards addition law with
687
+ * extended coordinates (Hisil2008).
688
+ * <p>
689
+ * $r = p - q$
690
+ * <p>
691
+ * Negating $q$ means negating the value of the coordinate $X2$ and $T2$.
692
+ * The formula is in accordance to {@link #add the above addition}.
693
+ *
694
+ * @param q the PRECOMP representation of the GroupElement to subtract.
695
+ * @return the P1P1 representation of the result.
696
+ */
697
+ public GroupElement sub(GroupElement q) {
698
+ if (this.repr != Representation.P3)
699
+ throw new UnsupportedOperationException();
700
+ if (q.repr != Representation.CACHED)
701
+ throw new IllegalArgumentException();
702
+
703
+ FieldElement YpX, YmX, A, B, C, ZZ, D;
704
+ YpX = Y.add(X);
705
+ YmX = Y.subtract(X);
706
+ A = YpX.multiply(q.Y); // q->Y-X
707
+ B = YmX.multiply(q.X); // q->Y+X
708
+ C = q.T.multiply(T); // q->2dT
709
+ ZZ = Z.multiply(q.Z);
710
+ D = ZZ.add(ZZ);
711
+ return p1p1(curve, A.subtract(B), A.add(B), D.subtract(C), D.add(C));
712
+ }
713
+
714
+ /**
715
+ * Negates this group element by subtracting it from the neutral group element.
716
+ * <p>
717
+ * TODO-CR BR: why not simply negate the coordinates $X$ and $T$?
718
+ *
719
+ * @return The negative of this group element.
720
+ */
721
+ public GroupElement negate() {
722
+ if (this.repr != Representation.P3)
723
+ throw new UnsupportedOperationException();
724
+ return this.curve.getZero(Representation.P3).sub(toCached()).toP3();
725
+ }
726
+
727
+ @Override
728
+ public int hashCode() {
729
+ return Arrays.hashCode(this.toByteArray());
730
+ }
731
+
732
+ @Override
733
+ public boolean equals(Object obj) {
734
+ if (obj == this)
735
+ return true;
736
+ if (!(obj instanceof GroupElement))
737
+ return false;
738
+ GroupElement ge = (GroupElement) obj;
739
+ if (!this.repr.equals(ge.repr)) {
740
+ try {
741
+ ge = ge.toRep(this.repr);
742
+ } catch (RuntimeException e) {
743
+ return false;
744
+ }
745
+ }
746
+ switch (this.repr) {
747
+ case P2:
748
+ case P3:
749
+ // Try easy way first
750
+ if (this.Z.equals(ge.Z))
751
+ return this.X.equals(ge.X) && this.Y.equals(ge.Y);
752
+ // X1/Z1 = X2/Z2 --> X1*Z2 = X2*Z1
753
+ final FieldElement x1 = this.X.multiply(ge.Z);
754
+ final FieldElement y1 = this.Y.multiply(ge.Z);
755
+ final FieldElement x2 = ge.X.multiply(this.Z);
756
+ final FieldElement y2 = ge.Y.multiply(this.Z);
757
+ return x1.equals(x2) && y1.equals(y2);
758
+ case P1P1:
759
+ return toP2().equals(ge);
760
+ case PRECOMP:
761
+ // Compare directly, PRECOMP is derived directly from x and y
762
+ return this.X.equals(ge.X) && this.Y.equals(ge.Y) && this.Z.equals(ge.Z);
763
+ case CACHED:
764
+ // Try easy way first
765
+ if (this.Z.equals(ge.Z))
766
+ return this.X.equals(ge.X) && this.Y.equals(ge.Y) && this.T.equals(ge.T);
767
+ // (Y+X)/Z = y+x etc.
768
+ final FieldElement x3 = this.X.multiply(ge.Z);
769
+ final FieldElement y3 = this.Y.multiply(ge.Z);
770
+ final FieldElement t3 = this.T.multiply(ge.Z);
771
+ final FieldElement x4 = ge.X.multiply(this.Z);
772
+ final FieldElement y4 = ge.Y.multiply(this.Z);
773
+ final FieldElement t4 = ge.T.multiply(this.Z);
774
+ return x3.equals(x4) && y3.equals(y4) && t3.equals(t4);
775
+ default:
776
+ return false;
777
+ }
778
+ }
779
+
780
+ /**
781
+ * Convert a to radix 16.
782
+ * <p>
783
+ * Method is package private only so that tests run.
784
+ *
785
+ * @param a $= a[0]+256*a[1]+...+256^{31} a[31]$
786
+ * @return 64 bytes, each between -8 and 7
787
+ */
788
+ static byte[] toRadix16(final byte[] a) {
789
+ final byte[] e = new byte[64];
790
+ int i;
791
+ // Radix 16 notation
792
+ for (i = 0; i < 32; i++) {
793
+ e[2*i+0] = (byte) (a[i] & 15);
794
+ e[2*i+1] = (byte) ((a[i] >> 4) & 15);
795
+ }
796
+ /* each e[i] is between 0 and 15 */
797
+ /* e[63] is between 0 and 7 */
798
+ int carry = 0;
799
+ for (i = 0; i < 63; i++) {
800
+ e[i] += carry;
801
+ carry = e[i] + 8;
802
+ carry >>= 4;
803
+ e[i] -= carry << 4;
804
+ }
805
+ e[63] += carry;
806
+ /* each e[i] is between -8 and 7 */
807
+ return e;
808
+ }
809
+
810
+ /**
811
+ * Constant-time conditional move.
812
+ * <p>
813
+ * Replaces this with $u$ if $b == 1$.<br>
814
+ * Replaces this with this if $b == 0$.
815
+ * <p>
816
+ * Method is package private only so that tests run.
817
+ *
818
+ * @param u The group element to return if $b == 1$.
819
+ * @param b in $\{0, 1\}$
820
+ * @return $u$ if $b == 1$; this if $b == 0$. Results undefined if $b$ is not in $\{0, 1\}$.
821
+ */
822
+ GroupElement cmov(final GroupElement u, final int b) {
823
+ return precomp(curve, X.cmov(u.X, b), Y.cmov(u.Y, b), Z.cmov(u.Z, b));
824
+ }
825
+
826
+ /**
827
+ * Look up $16^i r_i B$ in the precomputed table.
828
+ * <p>
829
+ * No secret array indices, no secret branching.
830
+ * Constant time.
831
+ * <p>
832
+ * Must have previously precomputed.
833
+ * <p>
834
+ * Method is package private only so that tests run.
835
+ *
836
+ * @param pos $= i/2$ for $i$ in $\{0, 2, 4,..., 62\}$
837
+ * @param b $= r_i$
838
+ * @return the GroupElement
839
+ */
840
+ GroupElement select(final int pos, final int b) {
841
+ // Is r_i negative?
842
+ final int bnegative = Utils.negative(b);
843
+ // |r_i|
844
+ final int babs = b - (((-bnegative) & b) << 1);
845
+
846
+ // 16^i |r_i| B
847
+ final GroupElement t = this.curve.getZero(Representation.PRECOMP)
848
+ .cmov(this.precmp[pos][0], Utils.equal(babs, 1))
849
+ .cmov(this.precmp[pos][1], Utils.equal(babs, 2))
850
+ .cmov(this.precmp[pos][2], Utils.equal(babs, 3))
851
+ .cmov(this.precmp[pos][3], Utils.equal(babs, 4))
852
+ .cmov(this.precmp[pos][4], Utils.equal(babs, 5))
853
+ .cmov(this.precmp[pos][5], Utils.equal(babs, 6))
854
+ .cmov(this.precmp[pos][6], Utils.equal(babs, 7))
855
+ .cmov(this.precmp[pos][7], Utils.equal(babs, 8));
856
+ // -16^i |r_i| B
857
+ final GroupElement tminus = precomp(curve, t.Y, t.X, t.Z.negate());
858
+ // 16^i r_i B
859
+ return t.cmov(tminus, bnegative);
860
+ }
861
+
862
+ /**
863
+ * $h = a * B$ where $a = a[0]+256*a[1]+\dots+256^{31} a[31]$ and
864
+ * $B$ is this point. If its lookup table has not been precomputed, it
865
+ * will be at the start of the method (and cached for later calls).
866
+ * Constant time.
867
+ * <p>
868
+ * Preconditions: (TODO: Check this applies here)
869
+ * $a[31] \le 127$
870
+ * @param a $= a[0]+256*a[1]+\dots+256^{31} a[31]$
871
+ * @return the GroupElement
872
+ */
873
+ public GroupElement scalarMultiply(final byte[] a) {
874
+ GroupElement t;
875
+ int i;
876
+
877
+ final byte[] e = toRadix16(a);
878
+
879
+ GroupElement h = this.curve.getZero(Representation.P3);
880
+ synchronized(this) {
881
+ // TODO: Get opinion from a crypto professional.
882
+ // This should in practice never be necessary, the only point that
883
+ // this should get called on is EdDSA's B.
884
+ //precompute();
885
+ for (i = 1; i < 64; i += 2) {
886
+ t = select(i/2, e[i]);
887
+ h = h.madd(t).toP3();
888
+ }
889
+
890
+ h = h.dbl().toP2().dbl().toP2().dbl().toP2().dbl().toP3();
891
+
892
+ for (i = 0; i < 64; i += 2) {
893
+ t = select(i/2, e[i]);
894
+ h = h.madd(t).toP3();
895
+ }
896
+ }
897
+
898
+ return h;
899
+ }
900
+
901
+ /**
902
+ * Calculates a sliding-windows base 2 representation for a given value $a$.
903
+ * To learn more about it see [6] page 8.
904
+ * <p>
905
+ * Output: $r$ which satisfies
906
+ * $a = r0 * 2^0 + r1 * 2^1 + \dots + r255 * 2^{255}$ with $ri$ in $\{-15, -13, -11, -9, -7, -5, -3, -1, 0, 1, 3, 5, 7, 9, 11, 13, 15\}$
907
+ * <p>
908
+ * Method is package private only so that tests run.
909
+ *
910
+ * @param a $= a[0]+256*a[1]+\dots+256^{31} a[31]$.
911
+ * @return The byte array $r$ in the above described form.
912
+ */
913
+ static byte[] slide(final byte[] a) {
914
+ byte[] r = new byte[256];
915
+
916
+ // Put each bit of 'a' into a separate byte, 0 or 1
917
+ for (int i = 0; i < 256; ++i) {
918
+ r[i] = (byte) (1 & (a[i >> 3] >> (i & 7)));
919
+ }
920
+
921
+ // Note: r[i] will always be odd.
922
+ for (int i = 0; i < 256; ++i) {
923
+ if (r[i] != 0) {
924
+ for (int b = 1; b <= 6 && i + b < 256; ++b) {
925
+ // Accumulate bits if possible
926
+ if (r[i + b] != 0) {
927
+ if (r[i] + (r[i + b] << b) <= 15) {
928
+ r[i] += r[i + b] << b;
929
+ r[i + b] = 0;
930
+ } else if (r[i] - (r[i + b] << b) >= -15) {
931
+ r[i] -= r[i + b] << b;
932
+ for (int k = i + b; k < 256; ++k) {
933
+ if (r[k] == 0) {
934
+ r[k] = 1;
935
+ break;
936
+ }
937
+ r[k] = 0;
938
+ }
939
+ } else
940
+ break;
941
+ }
942
+ }
943
+ }
944
+ }
945
+
946
+ return r;
947
+ }
948
+
949
+ /**
950
+ * $r = a * A + b * B$ where $a = a[0]+256*a[1]+\dots+256^{31} a[31]$,
951
+ * $b = b[0]+256*b[1]+\dots+256^{31} b[31]$ and $B$ is this point.
952
+ * <p>
953
+ * $A$ must have been previously precomputed.
954
+ *
955
+ * @param A in P3 representation.
956
+ * @param a $= a[0]+256*a[1]+\dots+256^{31} a[31]$
957
+ * @param b $= b[0]+256*b[1]+\dots+256^{31} b[31]$
958
+ * @return the GroupElement
959
+ */
960
+ public GroupElement doubleScalarMultiplyVariableTime(final GroupElement A, final byte[] a, final byte[] b) {
961
+ // TODO-CR BR: A check that this is the base point is needed.
962
+ final byte[] aslide = slide(a);
963
+ final byte[] bslide = slide(b);
964
+
965
+ GroupElement r = this.curve.getZero(Representation.P2);
966
+
967
+ int i;
968
+ for (i = 255; i >= 0; --i) {
969
+ if (aslide[i] != 0 || bslide[i] != 0) break;
970
+ }
971
+
972
+ synchronized(this) {
973
+ // TODO-CR BR strange comment below.
974
+ // TODO: Get opinion from a crypto professional.
975
+ // This should in practice never be necessary, the only point that
976
+ // this should get called on is EdDSA's B.
977
+ //precompute();
978
+ for (; i >= 0; --i) {
979
+ GroupElement t = r.dbl();
980
+
981
+ if (aslide[i] > 0) {
982
+ t = t.toP3().madd(A.dblPrecmp[aslide[i]/2]);
983
+ } else if(aslide[i] < 0) {
984
+ t = t.toP3().msub(A.dblPrecmp[(-aslide[i])/2]);
985
+ }
986
+
987
+ if (bslide[i] > 0) {
988
+ t = t.toP3().madd(this.dblPrecmp[bslide[i]/2]);
989
+ } else if(bslide[i] < 0) {
990
+ t = t.toP3().msub(this.dblPrecmp[(-bslide[i])/2]);
991
+ }
992
+
993
+ r = t.toP2();
994
+ }
995
+ }
996
+
997
+ return r;
998
+ }
999
+
1000
+ /**
1001
+ * Verify that a point is on its curve.
1002
+ * @return true if the point lies on its curve.
1003
+ */
1004
+ public boolean isOnCurve() {
1005
+ return isOnCurve(curve);
1006
+ }
1007
+
1008
+ /**
1009
+ * Verify that a point is on the curve.
1010
+ * @param curve The curve to check.
1011
+ * @return true if the point lies on the curve.
1012
+ */
1013
+ public boolean isOnCurve(Curve curve) {
1014
+ switch (repr) {
1015
+ case P2:
1016
+ case P3:
1017
+ FieldElement recip = Z.invert();
1018
+ FieldElement x = X.multiply(recip);
1019
+ FieldElement y = Y.multiply(recip);
1020
+ FieldElement xx = x.square();
1021
+ FieldElement yy = y.square();
1022
+ FieldElement dxxyy = curve.getD().multiply(xx).multiply(yy);
1023
+ return curve.getField().ONE.add(dxxyy).add(xx).equals(yy);
1024
+
1025
+ default:
1026
+ return toP2().isOnCurve(curve);
1027
+ }
1028
+ }
1029
+
1030
+ @Override
1031
+ public String toString() {
1032
+ return "[GroupElement\nX="+X+"\nY="+Y+"\nZ="+Z+"\nT="+T+"\n]";
1033
+ }
1034
+ }