Skip to content

Commit ffd0b9b

Browse files
authored
Merge pull request #58 from corda/parkri-rebase-against-upstream
De-contend code paths to support greater throughput in multi-threaded environments
2 parents 1b6e8c3 + 5ab6cba commit ffd0b9b

File tree

12 files changed

+274
-102
lines changed

12 files changed

+274
-102
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Download the latest .jar from the releases tab and place it in your classpath.
1818
Gradle users:
1919

2020
```
21-
compile 'net.i2p.crypto:eddsa:0.2.0'
21+
compile 'net.i2p.crypto:eddsa:0.3.0'
2222
```
2323

2424
The code requires Java 6 (for e.g. the `Arrays.copyOfRange()` calls in `EdDSAEngine.engineVerify()`).
@@ -64,6 +64,19 @@ For ease of following, here are the main methods in ref10 and their equivalents
6464
Important changes
6565
-----------------
6666

67+
### 0.3.0
68+
69+
- The library has been extensively profiled for contention issues in a multi-threaded environment. The only remaining potential
70+
contention is in `EdDSANamedCurveTable.defineCurve()`, which will be rarely called.
71+
- The public constant for the curve name has returned as `ED_25519` and the curve specification has a public constant
72+
`ED_25519_CURVE_SPEC` to avoid repeated lookups when converting to and from encoded form for the public or private keys.
73+
- `GroupElement` is now completely immutable and all fields final to avoid the need for `synchronized` blocks over mutable fields.
74+
This required some new constructors and paths to construction.
75+
- `EdDSAPublicKeySpec.getNegativeA()` and `EdDSAPublicKey.getNegativeA()` now evaluate lazily, taking advantage of the
76+
immutability of `GroupElement.negate()` which boosts the performance of the public key constructor when the key is just
77+
being passed around rather than used.
78+
- Support for X509Key wrapped EdDSA public keys.
79+
6780
### 0.2.0
6881

6982
- Ed25519 is now named `Ed25519` in `EdDSANamedCurveTable`, and the previous public constant

jitpack.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
jdk:
2+
- oraclejdk8

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>net.i2p.crypto</groupId>
55
<artifactId>eddsa</artifactId>
6-
<version>0.2.0</version>
6+
<version>0.3.0</version>
77
<name>EdDSA-Java</name>
88
<packaging>bundle</packaging>
99
<description>Implementation of EdDSA in Java</description>
@@ -104,6 +104,7 @@
104104
<charset>UTF-8</charset>
105105
<docencoding>UTF-8</docencoding>
106106
<encoding>UTF-8</encoding>
107+
<additionalparam>--allow-script-in-comments</additionalparam>
107108
<header>&lt;script type='text/x-mathjax-config'&gt;
108109
MathJax.Hub.Config({
109110
tex2jax: {

src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public EdDSAPrivateKey(EdDSAPrivateKeySpec spec) {
6363

6464
public EdDSAPrivateKey(PKCS8EncodedKeySpec spec) throws InvalidKeySpecException {
6565
this(new EdDSAPrivateKeySpec(decode(spec.getEncoded()),
66-
EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)));
66+
EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
6767
}
6868

6969
@Override
@@ -82,10 +82,10 @@ public String getFormat() {
8282
* This implements the following specs:
8383
*<ul><li>
8484
* General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
85-
*</li></li>
85+
*</li><li>
8686
* Key encoding: https://tools.ietf.org/html/rfc8032
8787
*</li></ul>
88-
*</p><p>
88+
*<p>
8989
* This encodes the seed. It will return null if constructed from
9090
* a spec which was directly constructed from H, in which case seed is null.
9191
*</p><p>
@@ -136,7 +136,7 @@ public String getFormat() {
136136
*/
137137
@Override
138138
public byte[] getEncoded() {
139-
if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)))
139+
if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
140140
return null;
141141
if (seed == null)
142142
return null;

src/net/i2p/crypto/eddsa/EdDSAPublicKey.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
public class EdDSAPublicKey implements EdDSAKey, PublicKey {
4141
private static final long serialVersionUID = 9837459837498475L;
4242
private final GroupElement A;
43-
private final GroupElement Aneg;
43+
private GroupElement Aneg = null;
4444
private final byte[] Abyte;
4545
private final EdDSAParameterSpec edDsaSpec;
4646

@@ -52,14 +52,13 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey {
5252

5353
public EdDSAPublicKey(EdDSAPublicKeySpec spec) {
5454
this.A = spec.getA();
55-
this.Aneg = spec.getNegativeA();
5655
this.Abyte = this.A.toByteArray();
5756
this.edDsaSpec = spec.getParams();
5857
}
5958

6059
public EdDSAPublicKey(X509EncodedKeySpec spec) throws InvalidKeySpecException {
6160
this(new EdDSAPublicKeySpec(decode(spec.getEncoded()),
62-
EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)));
61+
EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
6362
}
6463

6564
@Override
@@ -78,10 +77,10 @@ public String getFormat() {
7877
* This implements the following specs:
7978
*<ul><li>
8079
* General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
81-
*</li></li>
80+
*</li><li>
8281
* Key encoding: https://tools.ietf.org/html/rfc8032
8382
*</li></ul>
84-
*</p><p>
83+
*<p>
8584
* For keys in older formats, decoding and then re-encoding is sufficient to
8685
* migrate them to the canonical encoding.
8786
*</p>
@@ -113,7 +112,7 @@ public String getFormat() {
113112
*/
114113
@Override
115114
public byte[] getEncoded() {
116-
if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)))
115+
if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
117116
return null;
118117
int totlen = 12 + Abyte.length;
119118
byte[] rv = new byte[totlen];
@@ -250,7 +249,13 @@ public GroupElement getA() {
250249
}
251250

252251
public GroupElement getNegativeA() {
253-
return Aneg;
252+
// Only read Aneg once, otherwise read re-ordering might occur between here and return. Requires all GroupElement's fields to be final.
253+
GroupElement ourAneg = Aneg;
254+
if(ourAneg == null) {
255+
ourAneg = A.negate();
256+
Aneg = ourAneg;
257+
}
258+
return ourAneg;
254259
}
255260

256261
public byte[] getAbyte() {

src/net/i2p/crypto/eddsa/math/Curve.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class Curve implements Serializable {
2828

2929
private final GroupElement zeroP2;
3030
private final GroupElement zeroP3;
31+
private final GroupElement zeroP3PrecomputedDouble;
3132
private final GroupElement zeroPrecomp;
3233

3334
public Curve(Field f, byte[] d, FieldElement I) {
@@ -39,7 +40,8 @@ public Curve(Field f, byte[] d, FieldElement I) {
3940
FieldElement zero = f.ZERO;
4041
FieldElement one = f.ONE;
4142
zeroP2 = GroupElement.p2(this, zero, one, one);
42-
zeroP3 = GroupElement.p3(this, zero, one, one, zero);
43+
zeroP3 = GroupElement.p3(this, zero, one, one, zero, false);
44+
zeroP3PrecomputedDouble = GroupElement.p3(this, zero, one, one, zero, true);
4345
zeroPrecomp = GroupElement.precomp(this, one, one, zero);
4446
}
4547

@@ -65,6 +67,8 @@ public GroupElement getZero(GroupElement.Representation repr) {
6567
return zeroP2;
6668
case P3:
6769
return zeroP3;
70+
case P3PrecomputedDouble:
71+
return zeroP3PrecomputedDouble;
6872
case PRECOMP:
6973
return zeroPrecomp;
7074
default:
@@ -73,9 +77,7 @@ public GroupElement getZero(GroupElement.Representation repr) {
7377
}
7478

7579
public GroupElement createPoint(byte[] P, boolean precompute) {
76-
GroupElement ge = new GroupElement(this, P);
77-
if (precompute)
78-
ge.precompute(true);
80+
GroupElement ge = new GroupElement(this, P, precompute);
7981
return ge;
8082
}
8183

0 commit comments

Comments
 (0)