Skip to content

Commit

Permalink
Merge pull request #58 from corda/parkri-rebase-against-upstream
Browse files Browse the repository at this point in the history
De-contend code paths to support greater throughput in multi-threaded environments
  • Loading branch information
str4d authored May 5, 2018
2 parents 1b6e8c3 + 5ab6cba commit ffd0b9b
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 102 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Download the latest .jar from the releases tab and place it in your classpath.
Gradle users:

```
compile 'net.i2p.crypto:eddsa:0.2.0'
compile 'net.i2p.crypto:eddsa:0.3.0'
```

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

### 0.3.0

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

### 0.2.0

- Ed25519 is now named `Ed25519` in `EdDSANamedCurveTable`, and the previous public constant
Expand Down
2 changes: 2 additions & 0 deletions jitpack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
jdk:
- oraclejdk8
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>0.2.0</version>
<version>0.3.0</version>
<name>EdDSA-Java</name>
<packaging>bundle</packaging>
<description>Implementation of EdDSA in Java</description>
Expand Down Expand Up @@ -104,6 +104,7 @@
<charset>UTF-8</charset>
<docencoding>UTF-8</docencoding>
<encoding>UTF-8</encoding>
<additionalparam>--allow-script-in-comments</additionalparam>
<header>&lt;script type='text/x-mathjax-config'&gt;
MathJax.Hub.Config({
tex2jax: {
Expand Down
8 changes: 4 additions & 4 deletions src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public EdDSAPrivateKey(EdDSAPrivateKeySpec spec) {

public EdDSAPrivateKey(PKCS8EncodedKeySpec spec) throws InvalidKeySpecException {
this(new EdDSAPrivateKeySpec(decode(spec.getEncoded()),
EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)));
EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
}

@Override
Expand All @@ -82,10 +82,10 @@ public String getFormat() {
* This implements the following specs:
*<ul><li>
* General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
*</li></li>
*</li><li>
* Key encoding: https://tools.ietf.org/html/rfc8032
*</li></ul>
*</p><p>
*<p>
* This encodes the seed. It will return null if constructed from
* a spec which was directly constructed from H, in which case seed is null.
*</p><p>
Expand Down Expand Up @@ -136,7 +136,7 @@ public String getFormat() {
*/
@Override
public byte[] getEncoded() {
if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)))
if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
return null;
if (seed == null)
return null;
Expand Down
19 changes: 12 additions & 7 deletions src/net/i2p/crypto/eddsa/EdDSAPublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
public class EdDSAPublicKey implements EdDSAKey, PublicKey {
private static final long serialVersionUID = 9837459837498475L;
private final GroupElement A;
private final GroupElement Aneg;
private GroupElement Aneg = null;
private final byte[] Abyte;
private final EdDSAParameterSpec edDsaSpec;

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

public EdDSAPublicKey(EdDSAPublicKeySpec spec) {
this.A = spec.getA();
this.Aneg = spec.getNegativeA();
this.Abyte = this.A.toByteArray();
this.edDsaSpec = spec.getParams();
}

public EdDSAPublicKey(X509EncodedKeySpec spec) throws InvalidKeySpecException {
this(new EdDSAPublicKeySpec(decode(spec.getEncoded()),
EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)));
EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
}

@Override
Expand All @@ -78,10 +77,10 @@ public String getFormat() {
* This implements the following specs:
*<ul><li>
* General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
*</li></li>
*</li><li>
* Key encoding: https://tools.ietf.org/html/rfc8032
*</li></ul>
*</p><p>
*<p>
* For keys in older formats, decoding and then re-encoding is sufficient to
* migrate them to the canonical encoding.
*</p>
Expand Down Expand Up @@ -113,7 +112,7 @@ public String getFormat() {
*/
@Override
public byte[] getEncoded() {
if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)))
if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
return null;
int totlen = 12 + Abyte.length;
byte[] rv = new byte[totlen];
Expand Down Expand Up @@ -250,7 +249,13 @@ public GroupElement getA() {
}

public GroupElement getNegativeA() {
return Aneg;
// Only read Aneg once, otherwise read re-ordering might occur between here and return. Requires all GroupElement's fields to be final.
GroupElement ourAneg = Aneg;
if(ourAneg == null) {
ourAneg = A.negate();
Aneg = ourAneg;
}
return ourAneg;
}

public byte[] getAbyte() {
Expand Down
10 changes: 6 additions & 4 deletions src/net/i2p/crypto/eddsa/math/Curve.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class Curve implements Serializable {

private final GroupElement zeroP2;
private final GroupElement zeroP3;
private final GroupElement zeroP3PrecomputedDouble;
private final GroupElement zeroPrecomp;

public Curve(Field f, byte[] d, FieldElement I) {
Expand All @@ -39,7 +40,8 @@ public Curve(Field f, byte[] d, FieldElement I) {
FieldElement zero = f.ZERO;
FieldElement one = f.ONE;
zeroP2 = GroupElement.p2(this, zero, one, one);
zeroP3 = GroupElement.p3(this, zero, one, one, zero);
zeroP3 = GroupElement.p3(this, zero, one, one, zero, false);
zeroP3PrecomputedDouble = GroupElement.p3(this, zero, one, one, zero, true);
zeroPrecomp = GroupElement.precomp(this, one, one, zero);
}

Expand All @@ -65,6 +67,8 @@ public GroupElement getZero(GroupElement.Representation repr) {
return zeroP2;
case P3:
return zeroP3;
case P3PrecomputedDouble:
return zeroP3PrecomputedDouble;
case PRECOMP:
return zeroPrecomp;
default:
Expand All @@ -73,9 +77,7 @@ public GroupElement getZero(GroupElement.Representation repr) {
}

public GroupElement createPoint(byte[] P, boolean precompute) {
GroupElement ge = new GroupElement(this, P);
if (precompute)
ge.precompute(true);
GroupElement ge = new GroupElement(this, P, precompute);
return ge;
}

Expand Down
Loading

0 comments on commit ffd0b9b

Please sign in to comment.