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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGES.md +13 -0
- data/README.md +9 -9
- data/Rakefile +3 -3
- data/ext/ed25519_jruby/LICENSE.txt +123 -0
- data/ext/ed25519_jruby/README.md +77 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAEngine.java +491 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAKey.java +31 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPrivateKey.java +338 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPublicKey.java +275 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSASecurityProvider.java +59 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyFactory.java +75 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyPairGenerator.java +97 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/Utils.java +103 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Constants.java +23 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Curve.java +100 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Encoding.java +54 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Field.java +99 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/FieldElement.java +76 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/GroupElement.java +1034 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ScalarOps.java +34 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerFieldElement.java +131 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerLittleEndianEncoding.java +102 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerScalarOps.java +37 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/package.html +6 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519FieldElement.java +988 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519LittleEndianEncoding.java +256 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519ScalarOps.java +693 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAGenParameterSpec.java +32 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveSpec.java +35 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveTable.java +71 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java +97 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java +133 -0
- data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPublicKeySpec.java +61 -0
- data/ext/ed25519_jruby/org/cryptosphere/Ed25519Provider.java +95 -0
- data/lib/ed25519.rb +8 -8
- data/lib/ed25519/signing_key.rb +9 -0
- data/lib/ed25519/version.rb +1 -1
- data/lib/ed25519_java.jar +0 -0
- metadata +32 -3
- data/ext/ed25519_java/org/cryptosphere/ed25519.java +0 -228
- data/lib/ed25519/provider/jruby.rb +0 -39
@@ -0,0 +1,32 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import java.security.spec.AlgorithmParameterSpec;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Implementation of AlgorithmParameterSpec that holds the name of a named
|
18
|
+
* EdDSA curve specification.
|
19
|
+
* @author str4d
|
20
|
+
*
|
21
|
+
*/
|
22
|
+
public class EdDSAGenParameterSpec implements AlgorithmParameterSpec {
|
23
|
+
private final String name;
|
24
|
+
|
25
|
+
public EdDSAGenParameterSpec(String stdName) {
|
26
|
+
name = stdName;
|
27
|
+
}
|
28
|
+
|
29
|
+
public String getName() {
|
30
|
+
return name;
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,35 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import net.i2p.crypto.eddsa.math.Curve;
|
15
|
+
import net.i2p.crypto.eddsa.math.GroupElement;
|
16
|
+
import net.i2p.crypto.eddsa.math.ScalarOps;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* EdDSA Curve specification that can also be referred to by name.
|
20
|
+
* @author str4d
|
21
|
+
*
|
22
|
+
*/
|
23
|
+
public class EdDSANamedCurveSpec extends EdDSAParameterSpec {
|
24
|
+
private final String name;
|
25
|
+
|
26
|
+
public EdDSANamedCurveSpec(String name, Curve curve,
|
27
|
+
String hashAlgo, ScalarOps sc, GroupElement B) {
|
28
|
+
super(curve, hashAlgo, sc, B);
|
29
|
+
this.name = name;
|
30
|
+
}
|
31
|
+
|
32
|
+
public String getName() {
|
33
|
+
return name;
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,71 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import java.util.Hashtable;
|
15
|
+
import java.util.Locale;
|
16
|
+
|
17
|
+
import net.i2p.crypto.eddsa.Utils;
|
18
|
+
import net.i2p.crypto.eddsa.math.Curve;
|
19
|
+
import net.i2p.crypto.eddsa.math.Field;
|
20
|
+
import net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding;
|
21
|
+
import net.i2p.crypto.eddsa.math.ed25519.Ed25519ScalarOps;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* The named EdDSA curves.
|
25
|
+
* @author str4d
|
26
|
+
*
|
27
|
+
*/
|
28
|
+
public class EdDSANamedCurveTable {
|
29
|
+
public static final String ED_25519 = "Ed25519";
|
30
|
+
|
31
|
+
private static final Field ed25519field = new Field(
|
32
|
+
256, // b
|
33
|
+
Utils.hexToBytes("edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), // q
|
34
|
+
new Ed25519LittleEndianEncoding());
|
35
|
+
|
36
|
+
private static final Curve ed25519curve = new Curve(ed25519field,
|
37
|
+
Utils.hexToBytes("a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"), // d
|
38
|
+
ed25519field.fromByteArray(Utils.hexToBytes("b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"))); // I
|
39
|
+
|
40
|
+
private static final EdDSANamedCurveSpec ed25519 = new EdDSANamedCurveSpec(
|
41
|
+
ED_25519,
|
42
|
+
ed25519curve,
|
43
|
+
"SHA-512", // H
|
44
|
+
new Ed25519ScalarOps(), // l
|
45
|
+
ed25519curve.createPoint( // B
|
46
|
+
Utils.hexToBytes("5866666666666666666666666666666666666666666666666666666666666666"),
|
47
|
+
true)); // Precompute tables for B
|
48
|
+
|
49
|
+
private static final Hashtable<String, EdDSANamedCurveSpec> curves = new Hashtable<String, EdDSANamedCurveSpec>();
|
50
|
+
|
51
|
+
public static void defineCurve(EdDSANamedCurveSpec curve) {
|
52
|
+
curves.put(curve.getName().toLowerCase(Locale.ENGLISH), curve);
|
53
|
+
}
|
54
|
+
|
55
|
+
static void defineCurveAlias(String name, String alias) {
|
56
|
+
EdDSANamedCurveSpec curve = curves.get(name.toLowerCase(Locale.ENGLISH));
|
57
|
+
if (curve == null) {
|
58
|
+
throw new IllegalStateException();
|
59
|
+
}
|
60
|
+
curves.put(alias.toLowerCase(Locale.ENGLISH), curve);
|
61
|
+
}
|
62
|
+
|
63
|
+
static {
|
64
|
+
// RFC 8032
|
65
|
+
defineCurve(ed25519);
|
66
|
+
}
|
67
|
+
|
68
|
+
public static EdDSANamedCurveSpec getByName(String name) {
|
69
|
+
return curves.get(name.toLowerCase(Locale.ENGLISH));
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,97 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import java.security.MessageDigest;
|
15
|
+
import java.security.NoSuchAlgorithmException;
|
16
|
+
import java.security.spec.AlgorithmParameterSpec;
|
17
|
+
|
18
|
+
import net.i2p.crypto.eddsa.math.Curve;
|
19
|
+
import net.i2p.crypto.eddsa.math.GroupElement;
|
20
|
+
import net.i2p.crypto.eddsa.math.ScalarOps;
|
21
|
+
|
22
|
+
import java.io.Serializable;
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Parameter specification for an EdDSA algorithm.
|
26
|
+
* @author str4d
|
27
|
+
*
|
28
|
+
*/
|
29
|
+
public class EdDSAParameterSpec implements AlgorithmParameterSpec, Serializable {
|
30
|
+
private static final long serialVersionUID = 8274987108472012L;
|
31
|
+
private final Curve curve;
|
32
|
+
private final String hashAlgo;
|
33
|
+
private final ScalarOps sc;
|
34
|
+
private final GroupElement B;
|
35
|
+
|
36
|
+
/**
|
37
|
+
* @param curve the curve
|
38
|
+
* @param hashAlgo the JCA string for the hash algorithm
|
39
|
+
* @param sc the parameter L represented as ScalarOps
|
40
|
+
* @param B the parameter B
|
41
|
+
* @throws IllegalArgumentException if hash algorithm is unsupported or length is wrong
|
42
|
+
*/
|
43
|
+
public EdDSAParameterSpec(Curve curve, String hashAlgo,
|
44
|
+
ScalarOps sc, GroupElement B) {
|
45
|
+
try {
|
46
|
+
MessageDigest hash = MessageDigest.getInstance(hashAlgo);
|
47
|
+
// EdDSA hash function must produce 2b-bit output
|
48
|
+
if (curve.getField().getb()/4 != hash.getDigestLength())
|
49
|
+
throw new IllegalArgumentException("Hash output is not 2b-bit");
|
50
|
+
} catch (NoSuchAlgorithmException e) {
|
51
|
+
throw new IllegalArgumentException("Unsupported hash algorithm");
|
52
|
+
}
|
53
|
+
|
54
|
+
this.curve = curve;
|
55
|
+
this.hashAlgo = hashAlgo;
|
56
|
+
this.sc = sc;
|
57
|
+
this.B = B;
|
58
|
+
}
|
59
|
+
|
60
|
+
public Curve getCurve() {
|
61
|
+
return curve;
|
62
|
+
}
|
63
|
+
|
64
|
+
public String getHashAlgorithm() {
|
65
|
+
return hashAlgo;
|
66
|
+
}
|
67
|
+
|
68
|
+
public ScalarOps getScalarOps() {
|
69
|
+
return sc;
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* @return the base (generator)
|
74
|
+
*/
|
75
|
+
public GroupElement getB() {
|
76
|
+
return B;
|
77
|
+
}
|
78
|
+
|
79
|
+
@Override
|
80
|
+
public int hashCode() {
|
81
|
+
return hashAlgo.hashCode() ^
|
82
|
+
curve.hashCode() ^
|
83
|
+
B.hashCode();
|
84
|
+
}
|
85
|
+
|
86
|
+
@Override
|
87
|
+
public boolean equals(Object o) {
|
88
|
+
if (o == this)
|
89
|
+
return true;
|
90
|
+
if (!(o instanceof EdDSAParameterSpec))
|
91
|
+
return false;
|
92
|
+
EdDSAParameterSpec s = (EdDSAParameterSpec) o;
|
93
|
+
return hashAlgo.equals(s.getHashAlgorithm()) &&
|
94
|
+
curve.equals(s.getCurve()) &&
|
95
|
+
B.equals(s.getB());
|
96
|
+
}
|
97
|
+
}
|
@@ -0,0 +1,133 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import java.security.MessageDigest;
|
15
|
+
import java.security.NoSuchAlgorithmException;
|
16
|
+
import java.security.spec.KeySpec;
|
17
|
+
import java.util.Arrays;
|
18
|
+
|
19
|
+
import net.i2p.crypto.eddsa.math.GroupElement;
|
20
|
+
|
21
|
+
/**
|
22
|
+
* @author str4d
|
23
|
+
*
|
24
|
+
*/
|
25
|
+
public class EdDSAPrivateKeySpec implements KeySpec {
|
26
|
+
private final byte[] seed;
|
27
|
+
private final byte[] h;
|
28
|
+
private final byte[] a;
|
29
|
+
private final GroupElement A;
|
30
|
+
private final EdDSAParameterSpec spec;
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @param seed the private key
|
34
|
+
* @param spec the parameter specification for this key
|
35
|
+
* @throws IllegalArgumentException if seed length is wrong or hash algorithm is unsupported
|
36
|
+
*/
|
37
|
+
public EdDSAPrivateKeySpec(byte[] seed, EdDSAParameterSpec spec) {
|
38
|
+
if (seed.length != spec.getCurve().getField().getb()/8)
|
39
|
+
throw new IllegalArgumentException("seed length is wrong");
|
40
|
+
|
41
|
+
this.spec = spec;
|
42
|
+
this.seed = seed;
|
43
|
+
|
44
|
+
try {
|
45
|
+
MessageDigest hash = MessageDigest.getInstance(spec.getHashAlgorithm());
|
46
|
+
int b = spec.getCurve().getField().getb();
|
47
|
+
|
48
|
+
// H(k)
|
49
|
+
h = hash.digest(seed);
|
50
|
+
|
51
|
+
/*a = BigInteger.valueOf(2).pow(b-2);
|
52
|
+
for (int i=3;i<(b-2);i++) {
|
53
|
+
a = a.add(BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(Utils.bit(h,i))));
|
54
|
+
}*/
|
55
|
+
// Saves ~0.4ms per key when running signing tests.
|
56
|
+
// TODO: are these bitflips the same for any hash function?
|
57
|
+
h[0] &= 248;
|
58
|
+
h[(b/8)-1] &= 63;
|
59
|
+
h[(b/8)-1] |= 64;
|
60
|
+
a = Arrays.copyOfRange(h, 0, b/8);
|
61
|
+
|
62
|
+
A = spec.getB().scalarMultiply(a);
|
63
|
+
} catch (NoSuchAlgorithmException e) {
|
64
|
+
throw new IllegalArgumentException("Unsupported hash algorithm");
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Initialize directly from the hash.
|
70
|
+
* getSeed() will return null if this constructor is used.
|
71
|
+
*
|
72
|
+
* @param spec the parameter specification for this key
|
73
|
+
* @param h the private key
|
74
|
+
* @throws IllegalArgumentException if hash length is wrong
|
75
|
+
* @since 0.1.1
|
76
|
+
*/
|
77
|
+
public EdDSAPrivateKeySpec(EdDSAParameterSpec spec, byte[] h) {
|
78
|
+
if (h.length != spec.getCurve().getField().getb()/4)
|
79
|
+
throw new IllegalArgumentException("hash length is wrong");
|
80
|
+
|
81
|
+
this.seed = null;
|
82
|
+
this.h = h;
|
83
|
+
this.spec = spec;
|
84
|
+
int b = spec.getCurve().getField().getb();
|
85
|
+
|
86
|
+
h[0] &= 248;
|
87
|
+
h[(b/8)-1] &= 63;
|
88
|
+
h[(b/8)-1] |= 64;
|
89
|
+
a = Arrays.copyOfRange(h, 0, b/8);
|
90
|
+
|
91
|
+
A = spec.getB().scalarMultiply(a);
|
92
|
+
}
|
93
|
+
|
94
|
+
public EdDSAPrivateKeySpec(byte[] seed, byte[] h, byte[] a, GroupElement A, EdDSAParameterSpec spec) {
|
95
|
+
this.seed = seed;
|
96
|
+
this.h = h;
|
97
|
+
this.a = a;
|
98
|
+
this.A = A;
|
99
|
+
this.spec = spec;
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* @return will be null if constructed directly from the private key
|
104
|
+
*/
|
105
|
+
public byte[] getSeed() {
|
106
|
+
return seed;
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* @return the hash
|
111
|
+
*/
|
112
|
+
public byte[] getH() {
|
113
|
+
return h;
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* @return the private key
|
118
|
+
*/
|
119
|
+
public byte[] geta() {
|
120
|
+
return a;
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* @return the public key
|
125
|
+
*/
|
126
|
+
public GroupElement getA() {
|
127
|
+
return A;
|
128
|
+
}
|
129
|
+
|
130
|
+
public EdDSAParameterSpec getParams() {
|
131
|
+
return spec;
|
132
|
+
}
|
133
|
+
}
|
@@ -0,0 +1,61 @@
|
|
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.spec;
|
13
|
+
|
14
|
+
import java.security.spec.KeySpec;
|
15
|
+
|
16
|
+
import net.i2p.crypto.eddsa.math.GroupElement;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @author str4d
|
20
|
+
*
|
21
|
+
*/
|
22
|
+
public class EdDSAPublicKeySpec implements KeySpec {
|
23
|
+
private final GroupElement A;
|
24
|
+
private final GroupElement Aneg;
|
25
|
+
private final EdDSAParameterSpec spec;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @param pk the public key
|
29
|
+
* @param spec the parameter specification for this key
|
30
|
+
* @throws IllegalArgumentException if key length is wrong
|
31
|
+
*/
|
32
|
+
public EdDSAPublicKeySpec(byte[] pk, EdDSAParameterSpec spec) {
|
33
|
+
if (pk.length != spec.getCurve().getField().getb()/8)
|
34
|
+
throw new IllegalArgumentException("public-key length is wrong");
|
35
|
+
|
36
|
+
this.A = new GroupElement(spec.getCurve(), pk);
|
37
|
+
// Precompute -A for use in verification.
|
38
|
+
this.Aneg = A.negate();
|
39
|
+
Aneg.precompute(false);
|
40
|
+
this.spec = spec;
|
41
|
+
}
|
42
|
+
|
43
|
+
public EdDSAPublicKeySpec(GroupElement A, EdDSAParameterSpec spec) {
|
44
|
+
this.A = A;
|
45
|
+
this.Aneg = A.negate();
|
46
|
+
Aneg.precompute(false);
|
47
|
+
this.spec = spec;
|
48
|
+
}
|
49
|
+
|
50
|
+
public GroupElement getA() {
|
51
|
+
return A;
|
52
|
+
}
|
53
|
+
|
54
|
+
public GroupElement getNegativeA() {
|
55
|
+
return Aneg;
|
56
|
+
}
|
57
|
+
|
58
|
+
public EdDSAParameterSpec getParams() {
|
59
|
+
return spec;
|
60
|
+
}
|
61
|
+
}
|
@@ -0,0 +1,95 @@
|
|
1
|
+
package org.cryptosphere;
|
2
|
+
|
3
|
+
import java.security.MessageDigest;
|
4
|
+
import java.security.Signature;
|
5
|
+
import java.util.Arrays;
|
6
|
+
import net.i2p.crypto.eddsa.EdDSAEngine;
|
7
|
+
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
8
|
+
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
9
|
+
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
10
|
+
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
|
11
|
+
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
12
|
+
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
13
|
+
import org.jruby.Ruby;
|
14
|
+
import org.jruby.RubyModule;
|
15
|
+
import org.jruby.RubyString;
|
16
|
+
import org.jruby.anno.JRubyMethod;
|
17
|
+
import org.jruby.anno.JRubyModule;
|
18
|
+
import org.jruby.runtime.ThreadContext;
|
19
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
20
|
+
|
21
|
+
@JRubyModule(name="Ed25519::Provider::JRuby")
|
22
|
+
public class Ed25519Provider {
|
23
|
+
public static RubyModule createEd25519Module(Ruby runtime) {
|
24
|
+
RubyModule mEd25519 = runtime.defineModule("Ed25519");
|
25
|
+
RubyModule mEd25519Provider = mEd25519.defineModuleUnder("Provider");
|
26
|
+
RubyModule mEd25519ProviderJRuby = mEd25519Provider.defineOrGetModuleUnder("JRuby");
|
27
|
+
mEd25519ProviderJRuby.defineAnnotatedMethods(Ed25519Provider.class);
|
28
|
+
|
29
|
+
return mEd25519ProviderJRuby;
|
30
|
+
}
|
31
|
+
|
32
|
+
@JRubyMethod(name = "create_keypair", module = true)
|
33
|
+
public static IRubyObject create_keypair(ThreadContext context, IRubyObject self, IRubyObject seed) {
|
34
|
+
byte[] seedBytes = seed.convertToString().getByteList().bytes();
|
35
|
+
|
36
|
+
if (seedBytes.length != 32) {
|
37
|
+
throw context.runtime.newArgumentError("expected 32-byte seed value, got " + seedBytes.length);
|
38
|
+
}
|
39
|
+
|
40
|
+
EdDSAParameterSpec edParams = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
|
41
|
+
EdDSAPrivateKeySpec signingKey = new EdDSAPrivateKeySpec(seedBytes, edParams);
|
42
|
+
EdDSAPublicKeySpec verifyKey = new EdDSAPublicKeySpec(signingKey.getA(), edParams);
|
43
|
+
|
44
|
+
byte[] keypair = new byte[64];
|
45
|
+
|
46
|
+
System.arraycopy(seedBytes, 0, keypair, 0, 32);
|
47
|
+
System.arraycopy(verifyKey.getA().toByteArray(), 0, keypair, 32, 32);
|
48
|
+
|
49
|
+
return RubyString.newString(context.getRuntime(), keypair);
|
50
|
+
}
|
51
|
+
|
52
|
+
@JRubyMethod(name = "sign", module = true)
|
53
|
+
public static IRubyObject sign(ThreadContext context, IRubyObject self, IRubyObject keypair, IRubyObject msg) throws Exception {
|
54
|
+
byte[] keypairBytes = keypair.convertToString().getByteList().bytes();
|
55
|
+
|
56
|
+
if (keypairBytes.length != 64) {
|
57
|
+
throw context.runtime.newArgumentError("expected 64-byte keypair value, got " + keypairBytes.length);
|
58
|
+
}
|
59
|
+
|
60
|
+
EdDSAParameterSpec edParams = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
|
61
|
+
Signature signer = new EdDSAEngine(MessageDigest.getInstance(edParams.getHashAlgorithm()));
|
62
|
+
|
63
|
+
byte[] seedBytes = Arrays.copyOfRange(keypairBytes, 0, 32);
|
64
|
+
EdDSAPrivateKeySpec signingKey = new EdDSAPrivateKeySpec(seedBytes, edParams);
|
65
|
+
|
66
|
+
signer.initSign(new EdDSAPrivateKey(signingKey));
|
67
|
+
signer.update(msg.convertToString().getByteList().bytes());
|
68
|
+
|
69
|
+
return RubyString.newString(context.getRuntime(), signer.sign());
|
70
|
+
}
|
71
|
+
|
72
|
+
@JRubyMethod(name = "verify", module = true)
|
73
|
+
public static IRubyObject verify(ThreadContext context, IRubyObject self, IRubyObject verify_key, IRubyObject signature, IRubyObject msg) throws Exception {
|
74
|
+
byte[] verifyKeyBytes = verify_key.convertToString().getByteList().bytes();
|
75
|
+
byte[] signatureBytes = signature.convertToString().getByteList().bytes();
|
76
|
+
|
77
|
+
if (verifyKeyBytes.length != 32) {
|
78
|
+
throw context.runtime.newArgumentError("expected 32-byte verify key, got " + verifyKeyBytes.length);
|
79
|
+
}
|
80
|
+
|
81
|
+
if (signatureBytes.length != 64) {
|
82
|
+
throw context.runtime.newArgumentError("expected 64-byte signature, got " + signatureBytes.length);
|
83
|
+
}
|
84
|
+
|
85
|
+
EdDSAParameterSpec edParams = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
|
86
|
+
Signature signer = new EdDSAEngine(MessageDigest.getInstance(edParams.getHashAlgorithm()));
|
87
|
+
EdDSAPublicKeySpec verifyKey = new EdDSAPublicKeySpec(verifyKeyBytes, edParams);
|
88
|
+
|
89
|
+
signer.initVerify(new EdDSAPublicKey(verifyKey));
|
90
|
+
signer.update(msg.convertToString().getByteList().bytes());
|
91
|
+
|
92
|
+
boolean isValid = signer.verify(signatureBytes);
|
93
|
+
return context.runtime.newBoolean(isValid);
|
94
|
+
}
|
95
|
+
}
|