red25519 1.1.0-jruby
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +4 -0
- data/.travis.yml +14 -0
- data/CHANGES.md +3 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +140 -0
- data/Rakefile +9 -0
- data/ed25519.png +0 -0
- data/ext/red25519/api.h +4 -0
- data/ext/red25519/crypto_int32.h +6 -0
- data/ext/red25519/crypto_sign.h +13 -0
- data/ext/red25519/crypto_uint32.h +6 -0
- data/ext/red25519/crypto_verify_32.h +7 -0
- data/ext/red25519/ed25519.c +136 -0
- data/ext/red25519/extconf.rb +4 -0
- data/ext/red25519/fe25519.c +326 -0
- data/ext/red25519/fe25519.h +63 -0
- data/ext/red25519/ge25519.c +311 -0
- data/ext/red25519/ge25519.h +35 -0
- data/ext/red25519/ge25519_base.data +850 -0
- data/ext/red25519/org/red25519/ed25519.java +228 -0
- data/ext/red25519/red25519_engine.c +82 -0
- data/ext/red25519/sc25519.c +298 -0
- data/ext/red25519/sc25519.h +73 -0
- data/ext/red25519/sha512-blocks.c +239 -0
- data/ext/red25519/sha512-hash.c +72 -0
- data/ext/red25519/sha512.h +4 -0
- data/ext/red25519/verify.c +40 -0
- data/lib/red25519/jruby_engine.rb +27 -0
- data/lib/red25519/keys.rb +73 -0
- data/lib/red25519/version.rb +3 -0
- data/lib/red25519.rb +41 -0
- data/lib/red25519_engine.jar +0 -0
- data/red25519.gemspec +31 -0
- data/spec/red25519/engine_spec.rb +33 -0
- data/spec/red25519/keys_spec.rb +65 -0
- data/spec/spec_helper.rb +3 -0
- data/tasks/extension.rake +12 -0
- data/tasks/rspec.rake +7 -0
- metadata +134 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
package org.red25519;
|
2
|
+
|
3
|
+
import java.math.BigInteger;
|
4
|
+
import java.nio.ByteBuffer;
|
5
|
+
import java.security.MessageDigest;
|
6
|
+
import java.security.NoSuchAlgorithmException;
|
7
|
+
import java.util.Arrays;
|
8
|
+
|
9
|
+
/* Written by k3d3
|
10
|
+
* Released to the public domain
|
11
|
+
*/
|
12
|
+
|
13
|
+
public class ed25519 {
|
14
|
+
static final int b = 256;
|
15
|
+
static final BigInteger q = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819949");
|
16
|
+
static final BigInteger qm2 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819947");
|
17
|
+
static final BigInteger qp3 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819952");
|
18
|
+
static final BigInteger l = new BigInteger("7237005577332262213973186563042994240857116359379907606001950938285454250989");
|
19
|
+
static final BigInteger d = new BigInteger("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740");
|
20
|
+
static final BigInteger I = new BigInteger("19681161376707505956807079304988542015446066515923890162744021073123829784752");
|
21
|
+
static final BigInteger By = new BigInteger("46316835694926478169428394003475163141307993866256225615783033603165251855960");
|
22
|
+
static final BigInteger Bx = new BigInteger("15112221349535400772501151409588531511454012693041857206046113283949847762202");
|
23
|
+
static final BigInteger[] B = {Bx.mod(q),By.mod(q)};
|
24
|
+
static final BigInteger un = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819967");
|
25
|
+
|
26
|
+
static byte[] H(byte[] m) {
|
27
|
+
MessageDigest md;
|
28
|
+
try {
|
29
|
+
md = MessageDigest.getInstance("SHA-512");
|
30
|
+
md.reset();
|
31
|
+
return md.digest(m);
|
32
|
+
} catch (NoSuchAlgorithmException e) {
|
33
|
+
e.printStackTrace();
|
34
|
+
System.exit(1);
|
35
|
+
}
|
36
|
+
return null;
|
37
|
+
}
|
38
|
+
|
39
|
+
static BigInteger expmod(BigInteger b, BigInteger e, BigInteger m) {
|
40
|
+
//System.out.println("expmod open with b=" + b + " e=" + e + " m=" + m);
|
41
|
+
if (e.equals(BigInteger.ZERO)) {
|
42
|
+
//System.out.println("expmod close with 1z");
|
43
|
+
return BigInteger.ONE;
|
44
|
+
}
|
45
|
+
BigInteger t = expmod(b, e.divide(BigInteger.valueOf(2)), m).pow(2).mod(m);
|
46
|
+
//System.out.println("expmod 1/2 t="+t+" e="+e+" testbit="+(e.testBit(0)?1:0));
|
47
|
+
if (e.testBit(0)) {
|
48
|
+
t = t.multiply(b).mod(m);
|
49
|
+
}
|
50
|
+
//System.out.println("expmod close with " + t);
|
51
|
+
return t;
|
52
|
+
}
|
53
|
+
|
54
|
+
static BigInteger inv(BigInteger x) {
|
55
|
+
//System.out.println("inv open with " + x);
|
56
|
+
//System.out.println("inv close with " + expmod(x, qm2, q));
|
57
|
+
return expmod(x, qm2, q);
|
58
|
+
}
|
59
|
+
|
60
|
+
static BigInteger xrecover(BigInteger y) {
|
61
|
+
BigInteger y2 = y.multiply(y);
|
62
|
+
BigInteger xx = (y2.subtract(BigInteger.ONE)).multiply(inv(d.multiply(y2).add(BigInteger.ONE)));
|
63
|
+
BigInteger x = expmod(xx, qp3.divide(BigInteger.valueOf(8)), q);
|
64
|
+
if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO)) x = (x.multiply(I).mod(q));
|
65
|
+
if (!x.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) x = q.subtract(x);
|
66
|
+
return x;
|
67
|
+
}
|
68
|
+
|
69
|
+
static BigInteger[] edwards(BigInteger[] P, BigInteger[] Q) {
|
70
|
+
BigInteger x1 = P[0];
|
71
|
+
BigInteger y1 = P[1];
|
72
|
+
BigInteger x2 = Q[0];
|
73
|
+
BigInteger y2 = Q[1];
|
74
|
+
BigInteger dtemp = d.multiply(x1).multiply(x2).multiply(y1).multiply(y2);
|
75
|
+
//System.out.println("edwards open with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
|
76
|
+
BigInteger x3 = ((x1.multiply(y2)).add((x2.multiply(y1)))).multiply(inv(BigInteger.ONE.add(dtemp)));
|
77
|
+
//System.out.println("edwards 1/2 with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
|
78
|
+
BigInteger y3 = ((y1.multiply(y2)).add((x1.multiply(x2)))).multiply(inv(BigInteger.ONE.subtract(dtemp)));
|
79
|
+
//System.out.println("edwards 2/2 with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
|
80
|
+
//System.out.println("edwards close with "+x3.mod(q)+","+y3.mod(q));
|
81
|
+
return new BigInteger[]{x3.mod(q), y3.mod(q)};
|
82
|
+
}
|
83
|
+
|
84
|
+
static BigInteger[] scalarmult(BigInteger[] P, BigInteger e) {
|
85
|
+
//System.out.println("scalarmult open with e = " + e);
|
86
|
+
if (e.equals(BigInteger.ZERO)) {
|
87
|
+
//System.out.println("scalarmult close with Q = 0,1");
|
88
|
+
return new BigInteger[]{BigInteger.ZERO, BigInteger.ONE};
|
89
|
+
}
|
90
|
+
BigInteger[] Q = scalarmult(P, e.divide(BigInteger.valueOf(2)));
|
91
|
+
//System.out.println("scalarmult asQ = " + Q[0] + "," + Q[1]);
|
92
|
+
Q = edwards(Q, Q);
|
93
|
+
//System.out.println("scalarmult aeQ = " + Q[0] + "," + Q[1] + " e="+e+" testbit="+(e.testBit(0)?1:0));
|
94
|
+
if (e.testBit(0)) Q = edwards(Q, P);
|
95
|
+
//System.out.println("scalarmult close with Q = " + Q[0] + "," + Q[1]);
|
96
|
+
return Q;
|
97
|
+
}
|
98
|
+
|
99
|
+
static byte[] encodeint(BigInteger y) {
|
100
|
+
byte[] in = y.toByteArray();
|
101
|
+
byte[] out = new byte[in.length];
|
102
|
+
for (int i=0;i<in.length;i++) {
|
103
|
+
out[i] = in[in.length-1-i];
|
104
|
+
}
|
105
|
+
return out;
|
106
|
+
}
|
107
|
+
|
108
|
+
static byte[] encodepoint(BigInteger[] P) {
|
109
|
+
BigInteger x = P[0];
|
110
|
+
BigInteger y = P[1];
|
111
|
+
byte[] out = encodeint(y);
|
112
|
+
//System.out.println("encodepoint x="+x+" testbit="+(x.testBit(0) ? 1 : 0));
|
113
|
+
out[out.length-1] |= (x.testBit(0) ? 0x80 : 0);
|
114
|
+
return out;
|
115
|
+
}
|
116
|
+
|
117
|
+
static int bit(byte[] h, int i) {
|
118
|
+
//System.out.println("bit open with i="+i);
|
119
|
+
//System.out.println("bit close with "+(h[i/8] >> (i%8) & 1));
|
120
|
+
return h[i/8] >> (i%8) & 1;
|
121
|
+
}
|
122
|
+
|
123
|
+
static byte[] publickey(byte[] sk) {
|
124
|
+
byte[] h = H(sk);
|
125
|
+
//System.out.println("publickey open with h=" + test.getHex(h));
|
126
|
+
BigInteger a = BigInteger.valueOf(2).pow(b-2);
|
127
|
+
for (int i=3;i<(b-2);i++) {
|
128
|
+
BigInteger apart = BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i)));
|
129
|
+
//System.out.println("publickey apart="+apart);
|
130
|
+
a = a.add(apart);
|
131
|
+
}
|
132
|
+
BigInteger[] A = scalarmult(B,a);
|
133
|
+
//System.out.println("publickey close with A="+A[0]+","+A[1]+" out="+test.getHex(encodepoint(A)));
|
134
|
+
return encodepoint(A);
|
135
|
+
}
|
136
|
+
|
137
|
+
static BigInteger Hint(byte[] m) {
|
138
|
+
byte[] h = H(m);
|
139
|
+
BigInteger hsum = BigInteger.ZERO;
|
140
|
+
for (int i=0;i<2*b;i++) {
|
141
|
+
hsum = hsum.add(BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i))));
|
142
|
+
}
|
143
|
+
return hsum;
|
144
|
+
}
|
145
|
+
|
146
|
+
static byte[] signature(byte[] m, byte[] sk, byte[] pk) {
|
147
|
+
byte[] h = H(sk);
|
148
|
+
//System.out.println("signature open with m="+test.getHex(m)+" h="+test.getHex(h)+" pk="+test.getHex(pk));
|
149
|
+
BigInteger a = BigInteger.valueOf(2).pow(b-2);
|
150
|
+
for (int i=3;i<(b-2);i++) {
|
151
|
+
a = a.add(BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i))));
|
152
|
+
}
|
153
|
+
//System.out.println("signature a="+a);
|
154
|
+
ByteBuffer rsub = ByteBuffer.allocate((b/8)+m.length);
|
155
|
+
rsub.put(h, b/8, b/4-b/8).put(m);
|
156
|
+
//System.out.println("signature rsub="+test.getHex(rsub.array()));
|
157
|
+
BigInteger r = Hint(rsub.array());
|
158
|
+
//System.out.println("signature r="+r);
|
159
|
+
BigInteger[] R = scalarmult(B,r);
|
160
|
+
ByteBuffer Stemp = ByteBuffer.allocate(32+pk.length+m.length);
|
161
|
+
Stemp.put(encodepoint(R)).put(pk).put(m);
|
162
|
+
BigInteger S = r.add(Hint(Stemp.array()).multiply(a)).mod(l);
|
163
|
+
ByteBuffer out = ByteBuffer.allocate(64);
|
164
|
+
out.put(encodepoint(R)).put(encodeint(S));
|
165
|
+
return out.array();
|
166
|
+
}
|
167
|
+
|
168
|
+
static boolean isoncurve(BigInteger[] P) {
|
169
|
+
BigInteger x = P[0];
|
170
|
+
BigInteger y = P[1];
|
171
|
+
//System.out.println("isoncurve open with P="+x+","+y);
|
172
|
+
BigInteger xx = x.multiply(x);
|
173
|
+
BigInteger yy = y.multiply(y);
|
174
|
+
BigInteger dxxyy = d.multiply(yy).multiply(xx);
|
175
|
+
//System.out.println("isoncurve close with "+xx.negate().add(yy).subtract(BigInteger.ONE).subtract(dxxyy).mod(q));
|
176
|
+
return xx.negate().add(yy).subtract(BigInteger.ONE).subtract(dxxyy).mod(q).equals(BigInteger.ZERO);
|
177
|
+
}
|
178
|
+
|
179
|
+
static BigInteger decodeint(byte[] s) {
|
180
|
+
byte[] out = new byte[s.length];
|
181
|
+
for (int i=0;i<s.length;i++) {
|
182
|
+
out[i] = s[s.length-1-i];
|
183
|
+
}
|
184
|
+
return new BigInteger(out).and(un);
|
185
|
+
}
|
186
|
+
|
187
|
+
static BigInteger[] decodepoint(byte[] s) throws Exception {
|
188
|
+
byte[] ybyte = new byte[s.length];
|
189
|
+
for (int i=0;i<s.length;i++) {
|
190
|
+
ybyte[i] = s[s.length-1-i];
|
191
|
+
}
|
192
|
+
//System.out.println("decodepoint open with s="+test.getHex(s)+" ybyte="+test.getHex(ybyte));
|
193
|
+
BigInteger y = new BigInteger(ybyte).and(un);
|
194
|
+
//System.out.println("decodepoint y="+y);
|
195
|
+
BigInteger x = xrecover(y);
|
196
|
+
//System.out.println("decodepoint x="+x+" testbit="+(x.testBit(0)?1:0)+" bit="+bit(s, b-1));
|
197
|
+
if ((x.testBit(0)?1:0) != bit(s, b-1)) {
|
198
|
+
x = q.subtract(x);
|
199
|
+
}
|
200
|
+
BigInteger[] P = {x,y};
|
201
|
+
if (!isoncurve(P)) throw new Exception("decoding point that is not on curve");
|
202
|
+
return P;
|
203
|
+
}
|
204
|
+
|
205
|
+
static boolean checkvalid(byte[] s, byte[] m, byte[] pk) throws Exception {
|
206
|
+
if (s.length != b/4) throw new Exception("signature length is wrong");
|
207
|
+
if (pk.length != b/8) throw new Exception("public-key length is wrong");
|
208
|
+
//System.out.println("checkvalid open with s="+test.getHex(s)+" m="+test.getHex(m)+" pk="+test.getHex(pk));
|
209
|
+
byte[] Rbyte = Arrays.copyOfRange(s, 0, b/8);
|
210
|
+
//System.out.println("checkvalid Rbyte="+test.getHex(Rbyte));
|
211
|
+
BigInteger[] R = decodepoint(Rbyte);
|
212
|
+
BigInteger[] A = decodepoint(pk);
|
213
|
+
//System.out.println("checkvalid R="+R[0]+","+R[1]+" A="+A[0]+","+A[1]);
|
214
|
+
byte[] Sbyte = Arrays.copyOfRange(s, b/8, b/4);
|
215
|
+
//System.out.println("checkvalid Sbyte="+test.getHex(Sbyte));
|
216
|
+
BigInteger S = decodeint(Sbyte);
|
217
|
+
//System.out.println("checkvalid S="+S);
|
218
|
+
ByteBuffer Stemp = ByteBuffer.allocate(32+pk.length+m.length);
|
219
|
+
Stemp.put(encodepoint(R)).put(pk).put(m);
|
220
|
+
BigInteger h = Hint(Stemp.array());
|
221
|
+
BigInteger[] ra = scalarmult(B,S);
|
222
|
+
BigInteger[] rb = edwards(R,scalarmult(A,h));
|
223
|
+
//System.out.println("checkvalid ra="+ra[0]+","+ra[1]+" rb="+rb[0]+","+rb[1]);
|
224
|
+
if (!ra[0].equals(rb[0]) || !ra[1].equals(rb[1])) // Constant time comparison
|
225
|
+
return false;
|
226
|
+
return true;
|
227
|
+
}
|
228
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "crypto_sign.h"
|
3
|
+
|
4
|
+
static VALUE mEd25519 = Qnil;
|
5
|
+
static VALUE mEd25519_Engine = Qnil;
|
6
|
+
|
7
|
+
static VALUE Ed25519_Engine_create_keypair(VALUE self, VALUE seed);
|
8
|
+
static VALUE Ed25519_Engine_sign(VALUE self, VALUE signing_key, VALUE msg);
|
9
|
+
static VALUE Ed25519_Engine_verify(VALUE self, VALUE verify_key, VALUE signature, VALUE msg);
|
10
|
+
|
11
|
+
void Init_red25519_engine()
|
12
|
+
{
|
13
|
+
mEd25519 = rb_define_module("Ed25519");
|
14
|
+
mEd25519_Engine = rb_define_module_under(mEd25519, "Engine");
|
15
|
+
|
16
|
+
rb_define_singleton_method(mEd25519_Engine, "create_keypair", Ed25519_Engine_create_keypair, 1);
|
17
|
+
rb_define_singleton_method(mEd25519_Engine, "sign", Ed25519_Engine_sign, 2);
|
18
|
+
rb_define_singleton_method(mEd25519_Engine, "verify", Ed25519_Engine_verify, 3);
|
19
|
+
}
|
20
|
+
|
21
|
+
static VALUE Ed25519_Engine_create_keypair(VALUE self, VALUE seed)
|
22
|
+
{
|
23
|
+
unsigned char verify_key[PUBLICKEYBYTES], signing_key[SECRETKEYBYTES];
|
24
|
+
|
25
|
+
seed = rb_convert_type(seed, T_STRING, "String", "to_str");
|
26
|
+
|
27
|
+
if(RSTRING_LEN(seed) != SECRETKEYBYTES / 2)
|
28
|
+
rb_raise(rb_eArgError, "seed must be exactly %d bytes", SECRETKEYBYTES / 2);
|
29
|
+
|
30
|
+
crypto_sign_publickey(verify_key, signing_key, RSTRING_PTR(seed));
|
31
|
+
|
32
|
+
rb_ary_new3(2,
|
33
|
+
rb_str_new(verify_key, PUBLICKEYBYTES),
|
34
|
+
rb_str_new(signing_key, SECRETKEYBYTES)
|
35
|
+
);
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE Ed25519_Engine_sign(VALUE self, VALUE signing_key, VALUE msg)
|
39
|
+
{
|
40
|
+
unsigned char *sig_and_msg;
|
41
|
+
unsigned long long sig_and_msg_len;
|
42
|
+
VALUE result;
|
43
|
+
|
44
|
+
if(RSTRING_LEN(signing_key) != SECRETKEYBYTES)
|
45
|
+
rb_raise(rb_eArgError, "private signing keys must be %d bytes", SECRETKEYBYTES);
|
46
|
+
|
47
|
+
sig_and_msg = (unsigned char *)xmalloc(SIGNATUREBYTES + RSTRING_LEN(msg));
|
48
|
+
crypto_sign(sig_and_msg, &sig_and_msg_len, RSTRING_PTR(msg), RSTRING_LEN(msg), RSTRING_PTR(signing_key));
|
49
|
+
result = rb_str_new(sig_and_msg, SIGNATUREBYTES);
|
50
|
+
free(sig_and_msg);
|
51
|
+
|
52
|
+
return result;
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE Ed25519_Engine_verify(VALUE self, VALUE verify_key, VALUE signature, VALUE msg)
|
56
|
+
{
|
57
|
+
unsigned char *sig_and_msg, *buffer;
|
58
|
+
unsigned long long sig_and_msg_len, buffer_len;
|
59
|
+
int result;
|
60
|
+
|
61
|
+
if(RSTRING_LEN(verify_key) != PUBLICKEYBYTES)
|
62
|
+
rb_raise(rb_eArgError, "public verify keys must be %d bytes", PUBLICKEYBYTES);
|
63
|
+
|
64
|
+
if(RSTRING_LEN(signature) != SIGNATUREBYTES)
|
65
|
+
rb_raise(rb_eArgError, "public verify keys must be %d bytes", PUBLICKEYBYTES);
|
66
|
+
|
67
|
+
sig_and_msg_len = SIGNATUREBYTES + RSTRING_LEN(msg);
|
68
|
+
sig_and_msg = (unsigned char *)xmalloc(sig_and_msg_len);
|
69
|
+
buffer = (unsigned char *)xmalloc(sig_and_msg_len);
|
70
|
+
memcpy(sig_and_msg, RSTRING_PTR(signature), SIGNATUREBYTES);
|
71
|
+
memcpy(sig_and_msg + SIGNATUREBYTES, RSTRING_PTR(msg), RSTRING_LEN(msg));
|
72
|
+
|
73
|
+
result = crypto_sign_open(
|
74
|
+
buffer, &buffer_len,
|
75
|
+
sig_and_msg, sig_and_msg_len,
|
76
|
+
RSTRING_PTR(verify_key));
|
77
|
+
|
78
|
+
free(sig_and_msg);
|
79
|
+
free(buffer);
|
80
|
+
|
81
|
+
return result == 0 ? Qtrue : Qfalse;
|
82
|
+
}
|
@@ -0,0 +1,298 @@
|
|
1
|
+
#include "sc25519.h"
|
2
|
+
|
3
|
+
/*Arithmetic modulo the group order m = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 */
|
4
|
+
|
5
|
+
static const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
|
6
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
|
7
|
+
|
8
|
+
static const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21,
|
9
|
+
0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
|
10
|
+
|
11
|
+
static crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
|
12
|
+
{
|
13
|
+
unsigned int x = a;
|
14
|
+
x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */
|
15
|
+
x >>= 31; /* 0: no; 1: yes */
|
16
|
+
return x;
|
17
|
+
}
|
18
|
+
|
19
|
+
/* Reduce coefficients of r before calling reduce_add_sub */
|
20
|
+
static void reduce_add_sub(sc25519 *r)
|
21
|
+
{
|
22
|
+
crypto_uint32 pb = 0;
|
23
|
+
crypto_uint32 b;
|
24
|
+
crypto_uint32 mask;
|
25
|
+
int i;
|
26
|
+
unsigned char t[32];
|
27
|
+
|
28
|
+
for(i=0;i<32;i++)
|
29
|
+
{
|
30
|
+
pb += m[i];
|
31
|
+
b = lt(r->v[i],pb);
|
32
|
+
t[i] = r->v[i]-pb+(b<<8);
|
33
|
+
pb = b;
|
34
|
+
}
|
35
|
+
mask = b - 1;
|
36
|
+
for(i=0;i<32;i++)
|
37
|
+
r->v[i] ^= mask & (r->v[i] ^ t[i]);
|
38
|
+
}
|
39
|
+
|
40
|
+
/* Reduce coefficients of x before calling barrett_reduce */
|
41
|
+
static void barrett_reduce(sc25519 *r, const crypto_uint32 x[64])
|
42
|
+
{
|
43
|
+
/* See HAC, Alg. 14.42 */
|
44
|
+
int i,j;
|
45
|
+
crypto_uint32 q2[66];
|
46
|
+
crypto_uint32 *q3 = q2 + 33;
|
47
|
+
crypto_uint32 r1[33];
|
48
|
+
crypto_uint32 r2[33];
|
49
|
+
crypto_uint32 carry;
|
50
|
+
crypto_uint32 pb = 0;
|
51
|
+
crypto_uint32 b;
|
52
|
+
|
53
|
+
for (i = 0;i < 66;++i) q2[i] = 0;
|
54
|
+
for (i = 0;i < 33;++i) r2[i] = 0;
|
55
|
+
|
56
|
+
for(i=0;i<33;i++)
|
57
|
+
for(j=0;j<33;j++)
|
58
|
+
if(i+j >= 31) q2[i+j] += mu[i]*x[j+31];
|
59
|
+
carry = q2[31] >> 8;
|
60
|
+
q2[32] += carry;
|
61
|
+
carry = q2[32] >> 8;
|
62
|
+
q2[33] += carry;
|
63
|
+
|
64
|
+
for(i=0;i<33;i++)r1[i] = x[i];
|
65
|
+
for(i=0;i<32;i++)
|
66
|
+
for(j=0;j<33;j++)
|
67
|
+
if(i+j < 33) r2[i+j] += m[i]*q3[j];
|
68
|
+
|
69
|
+
for(i=0;i<32;i++)
|
70
|
+
{
|
71
|
+
carry = r2[i] >> 8;
|
72
|
+
r2[i+1] += carry;
|
73
|
+
r2[i] &= 0xff;
|
74
|
+
}
|
75
|
+
|
76
|
+
for(i=0;i<32;i++)
|
77
|
+
{
|
78
|
+
pb += r2[i];
|
79
|
+
b = lt(r1[i],pb);
|
80
|
+
r->v[i] = r1[i]-pb+(b<<8);
|
81
|
+
pb = b;
|
82
|
+
}
|
83
|
+
|
84
|
+
/* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3
|
85
|
+
* If so: Handle it here!
|
86
|
+
*/
|
87
|
+
|
88
|
+
reduce_add_sub(r);
|
89
|
+
reduce_add_sub(r);
|
90
|
+
}
|
91
|
+
|
92
|
+
void sc25519_from32bytes(sc25519 *r, const unsigned char x[32])
|
93
|
+
{
|
94
|
+
int i;
|
95
|
+
crypto_uint32 t[64];
|
96
|
+
for(i=0;i<32;i++) t[i] = x[i];
|
97
|
+
for(i=32;i<64;++i) t[i] = 0;
|
98
|
+
barrett_reduce(r, t);
|
99
|
+
}
|
100
|
+
|
101
|
+
void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16])
|
102
|
+
{
|
103
|
+
int i;
|
104
|
+
for(i=0;i<16;i++) r->v[i] = x[i];
|
105
|
+
}
|
106
|
+
|
107
|
+
void sc25519_from64bytes(sc25519 *r, const unsigned char x[64])
|
108
|
+
{
|
109
|
+
int i;
|
110
|
+
crypto_uint32 t[64];
|
111
|
+
for(i=0;i<64;i++) t[i] = x[i];
|
112
|
+
barrett_reduce(r, t);
|
113
|
+
}
|
114
|
+
|
115
|
+
void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x)
|
116
|
+
{
|
117
|
+
int i;
|
118
|
+
for(i=0;i<16;i++)
|
119
|
+
r->v[i] = x->v[i];
|
120
|
+
for(i=0;i<16;i++)
|
121
|
+
r->v[16+i] = 0;
|
122
|
+
}
|
123
|
+
|
124
|
+
void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
|
125
|
+
{
|
126
|
+
int i;
|
127
|
+
for(i=0;i<32;i++) r[i] = x->v[i];
|
128
|
+
}
|
129
|
+
|
130
|
+
int sc25519_iszero_vartime(const sc25519 *x)
|
131
|
+
{
|
132
|
+
int i;
|
133
|
+
for(i=0;i<32;i++)
|
134
|
+
if(x->v[i] != 0) return 0;
|
135
|
+
return 1;
|
136
|
+
}
|
137
|
+
|
138
|
+
int sc25519_isshort_vartime(const sc25519 *x)
|
139
|
+
{
|
140
|
+
int i;
|
141
|
+
for(i=31;i>15;i--)
|
142
|
+
if(x->v[i] != 0) return 0;
|
143
|
+
return 1;
|
144
|
+
}
|
145
|
+
|
146
|
+
int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y)
|
147
|
+
{
|
148
|
+
int i;
|
149
|
+
for(i=31;i>=0;i--)
|
150
|
+
{
|
151
|
+
if(x->v[i] < y->v[i]) return 1;
|
152
|
+
if(x->v[i] > y->v[i]) return 0;
|
153
|
+
}
|
154
|
+
return 0;
|
155
|
+
}
|
156
|
+
|
157
|
+
void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
158
|
+
{
|
159
|
+
int i, carry;
|
160
|
+
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
|
161
|
+
for(i=0;i<31;i++)
|
162
|
+
{
|
163
|
+
carry = r->v[i] >> 8;
|
164
|
+
r->v[i+1] += carry;
|
165
|
+
r->v[i] &= 0xff;
|
166
|
+
}
|
167
|
+
reduce_add_sub(r);
|
168
|
+
}
|
169
|
+
|
170
|
+
void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
171
|
+
{
|
172
|
+
crypto_uint32 b = 0;
|
173
|
+
crypto_uint32 t;
|
174
|
+
int i;
|
175
|
+
for(i=0;i<32;i++)
|
176
|
+
{
|
177
|
+
t = x->v[i] - y->v[i] - b;
|
178
|
+
r->v[i] = t & 255;
|
179
|
+
b = (t >> 8) & 1;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
184
|
+
{
|
185
|
+
int i,j,carry;
|
186
|
+
crypto_uint32 t[64];
|
187
|
+
for(i=0;i<64;i++)t[i] = 0;
|
188
|
+
|
189
|
+
for(i=0;i<32;i++)
|
190
|
+
for(j=0;j<32;j++)
|
191
|
+
t[i+j] += x->v[i] * y->v[j];
|
192
|
+
|
193
|
+
/* Reduce coefficients */
|
194
|
+
for(i=0;i<63;i++)
|
195
|
+
{
|
196
|
+
carry = t[i] >> 8;
|
197
|
+
t[i+1] += carry;
|
198
|
+
t[i] &= 0xff;
|
199
|
+
}
|
200
|
+
|
201
|
+
barrett_reduce(r, t);
|
202
|
+
}
|
203
|
+
|
204
|
+
void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y)
|
205
|
+
{
|
206
|
+
sc25519 t;
|
207
|
+
sc25519_from_shortsc(&t, y);
|
208
|
+
sc25519_mul(r, x, &t);
|
209
|
+
}
|
210
|
+
|
211
|
+
void sc25519_window3(signed char r[85], const sc25519 *s)
|
212
|
+
{
|
213
|
+
char carry;
|
214
|
+
int i;
|
215
|
+
for(i=0;i<10;i++)
|
216
|
+
{
|
217
|
+
r[8*i+0] = s->v[3*i+0] & 7;
|
218
|
+
r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
|
219
|
+
r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
|
220
|
+
r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
|
221
|
+
r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
|
222
|
+
r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
|
223
|
+
r[8*i+5] = (s->v[3*i+1] >> 7) & 7;
|
224
|
+
r[8*i+5] ^= (s->v[3*i+2] << 1) & 7;
|
225
|
+
r[8*i+6] = (s->v[3*i+2] >> 2) & 7;
|
226
|
+
r[8*i+7] = (s->v[3*i+2] >> 5) & 7;
|
227
|
+
}
|
228
|
+
r[8*i+0] = s->v[3*i+0] & 7;
|
229
|
+
r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
|
230
|
+
r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
|
231
|
+
r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
|
232
|
+
r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
|
233
|
+
r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
|
234
|
+
|
235
|
+
/* Making it signed */
|
236
|
+
carry = 0;
|
237
|
+
for(i=0;i<84;i++)
|
238
|
+
{
|
239
|
+
r[i] += carry;
|
240
|
+
r[i+1] += r[i] >> 3;
|
241
|
+
r[i] &= 7;
|
242
|
+
carry = r[i] >> 2;
|
243
|
+
r[i] -= carry<<3;
|
244
|
+
}
|
245
|
+
r[84] += carry;
|
246
|
+
}
|
247
|
+
|
248
|
+
void sc25519_window5(signed char r[51], const sc25519 *s)
|
249
|
+
{
|
250
|
+
char carry;
|
251
|
+
int i;
|
252
|
+
for(i=0;i<6;i++)
|
253
|
+
{
|
254
|
+
r[8*i+0] = s->v[5*i+0] & 31;
|
255
|
+
r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
|
256
|
+
r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
|
257
|
+
r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
|
258
|
+
r[8*i+3] = (s->v[5*i+1] >> 7) & 31;
|
259
|
+
r[8*i+3] ^= (s->v[5*i+2] << 1) & 31;
|
260
|
+
r[8*i+4] = (s->v[5*i+2] >> 4) & 31;
|
261
|
+
r[8*i+4] ^= (s->v[5*i+3] << 4) & 31;
|
262
|
+
r[8*i+5] = (s->v[5*i+3] >> 1) & 31;
|
263
|
+
r[8*i+6] = (s->v[5*i+3] >> 6) & 31;
|
264
|
+
r[8*i+6] ^= (s->v[5*i+4] << 2) & 31;
|
265
|
+
r[8*i+7] = (s->v[5*i+4] >> 3) & 31;
|
266
|
+
}
|
267
|
+
r[8*i+0] = s->v[5*i+0] & 31;
|
268
|
+
r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
|
269
|
+
r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
|
270
|
+
r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
|
271
|
+
|
272
|
+
/* Making it signed */
|
273
|
+
carry = 0;
|
274
|
+
for(i=0;i<50;i++)
|
275
|
+
{
|
276
|
+
r[i] += carry;
|
277
|
+
r[i+1] += r[i] >> 5;
|
278
|
+
r[i] &= 31;
|
279
|
+
carry = r[i] >> 4;
|
280
|
+
r[i] -= carry<<5;
|
281
|
+
}
|
282
|
+
r[50] += carry;
|
283
|
+
}
|
284
|
+
|
285
|
+
void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
|
286
|
+
{
|
287
|
+
int i;
|
288
|
+
for(i=0;i<31;i++)
|
289
|
+
{
|
290
|
+
r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2);
|
291
|
+
r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2);
|
292
|
+
r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2);
|
293
|
+
r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2);
|
294
|
+
}
|
295
|
+
r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2);
|
296
|
+
r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2);
|
297
|
+
r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2);
|
298
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#ifndef SC25519_H
|
2
|
+
#define SC25519_H
|
3
|
+
|
4
|
+
#include "crypto_int32.h"
|
5
|
+
#include "crypto_uint32.h"
|
6
|
+
|
7
|
+
#define sc25519 crypto_sign_ed25519_ref_sc25519
|
8
|
+
#define shortsc25519 crypto_sign_ed25519_ref_shortsc25519
|
9
|
+
#define sc25519_from32bytes crypto_sign_ed25519_ref_sc25519_from32bytes
|
10
|
+
#define shortsc25519_from16bytes crypto_sign_ed25519_ref_shortsc25519_from16bytes
|
11
|
+
#define sc25519_from64bytes crypto_sign_ed25519_ref_sc25519_from64bytes
|
12
|
+
#define sc25519_from_shortsc crypto_sign_ed25519_ref_sc25519_from_shortsc
|
13
|
+
#define sc25519_to32bytes crypto_sign_ed25519_ref_sc25519_to32bytes
|
14
|
+
#define sc25519_iszero_vartime crypto_sign_ed25519_ref_sc25519_iszero_vartime
|
15
|
+
#define sc25519_isshort_vartime crypto_sign_ed25519_ref_sc25519_isshort_vartime
|
16
|
+
#define sc25519_lt_vartime crypto_sign_ed25519_ref_sc25519_lt_vartime
|
17
|
+
#define sc25519_add crypto_sign_ed25519_ref_sc25519_add
|
18
|
+
#define sc25519_sub_nored crypto_sign_ed25519_ref_sc25519_sub_nored
|
19
|
+
#define sc25519_mul crypto_sign_ed25519_ref_sc25519_mul
|
20
|
+
#define sc25519_mul_shortsc crypto_sign_ed25519_ref_sc25519_mul_shortsc
|
21
|
+
#define sc25519_window3 crypto_sign_ed25519_ref_sc25519_window3
|
22
|
+
#define sc25519_window5 crypto_sign_ed25519_ref_sc25519_window5
|
23
|
+
#define sc25519_2interleave2 crypto_sign_ed25519_ref_sc25519_2interleave2
|
24
|
+
|
25
|
+
typedef struct
|
26
|
+
{
|
27
|
+
crypto_uint32 v[32];
|
28
|
+
}
|
29
|
+
sc25519;
|
30
|
+
|
31
|
+
typedef struct
|
32
|
+
{
|
33
|
+
crypto_uint32 v[16];
|
34
|
+
}
|
35
|
+
shortsc25519;
|
36
|
+
|
37
|
+
void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]);
|
38
|
+
|
39
|
+
void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16]);
|
40
|
+
|
41
|
+
void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]);
|
42
|
+
|
43
|
+
void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x);
|
44
|
+
|
45
|
+
void sc25519_to32bytes(unsigned char r[32], const sc25519 *x);
|
46
|
+
|
47
|
+
int sc25519_iszero_vartime(const sc25519 *x);
|
48
|
+
|
49
|
+
int sc25519_isshort_vartime(const sc25519 *x);
|
50
|
+
|
51
|
+
int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y);
|
52
|
+
|
53
|
+
void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
54
|
+
|
55
|
+
void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
56
|
+
|
57
|
+
void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
58
|
+
|
59
|
+
void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y);
|
60
|
+
|
61
|
+
/* Convert s into a representation of the form \sum_{i=0}^{84}r[i]2^3
|
62
|
+
* with r[i] in {-4,...,3}
|
63
|
+
*/
|
64
|
+
void sc25519_window3(signed char r[85], const sc25519 *s);
|
65
|
+
|
66
|
+
/* Convert s into a representation of the form \sum_{i=0}^{50}r[i]2^5
|
67
|
+
* with r[i] in {-16,...,15}
|
68
|
+
*/
|
69
|
+
void sc25519_window5(signed char r[51], const sc25519 *s);
|
70
|
+
|
71
|
+
void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2);
|
72
|
+
|
73
|
+
#endif
|