1 module dcrypt.crypto.ecc.curve25519;
2 
3 import dcrypt.crypto.ecc.curved25519.fieldElement;
4 import dcrypt.util: wipe;
5 
6 /// Implementation of Curve25519.
7 ///
8 ///
9 
10 
11 /// Generate a public key from a secret. 
12 /// Test vectors from http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
13 unittest {
14 	alias ubyte[32] key_t;
15 	
16 	key_t secretKey = cast(key_t) x"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
17 	
18 	key_t publicKey = curve25519_scalarmult(secretKey);
19 	
20 	auto expectedPublic = x"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
21 	
22 	assert(publicKey == expectedPublic, "curve25519 public key generation failed!");
23 }
24 
25 /// Generate a public key from a secret. 
26 /// Test vectors from http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
27 unittest {
28 	alias ubyte[32] key_t;
29 	
30 	key_t secretKey = cast(key_t) x"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
31 	
32 	key_t publicKey = curve25519_scalarmult(secretKey);
33 	
34 	auto expectedPublic = x"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
35 	
36 	assert(publicKey == expectedPublic, "curve25519 public key generation failed!");
37 }
38 
39 /// DH key exchange
40 /// Test vectors from http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
41 unittest {
42 	alias ubyte[32] key_t;
43 	
44 	key_t priv1, priv2, pub1, pub2;
45 	priv1[] = cast(key_t) x"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
46 	priv2[] = cast(key_t) x"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
47 	
48 	pub1 = curve25519_scalarmult(priv1);
49 	pub2 = curve25519_scalarmult(priv2);
50 	
51 	key_t shared1, shared2;
52 	
53 	// Generate the shared keys. Both should be equal.
54 	shared1 = curve25519_scalarmult(priv1, pub2);
55 	shared2 = curve25519_scalarmult(priv2, pub1);
56 	
57 	auto expectedSharedSecret = x"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
58 	
59 	assert(shared1 == expectedSharedSecret, "curve25519 DH key agreement failed!");
60 	assert(shared1 == shared2, "curve25519 DH key agreement failed!");
61 }
62 
63 unittest {
64 	alias ubyte[32] key_t;
65 	key_t a = 1;
66 	key_t b = 2;
67 
68 	key_t A = curve25519_scalarmult(a);
69 	key_t B = curve25519_scalarmult(b);
70 
71 	key_t sa = curve25519_scalarmult(a, B);
72 	key_t sb = curve25519_scalarmult(b, A);
73 
74 	assert(sa == sb, "DH failed.");
75 }
76 
77 /// The default public base point.
78 public enum ubyte[32] publicBasePoint = cast(immutable (ubyte[32]) ) x"0900000000000000000000000000000000000000000000000000000000000000";
79 
80 @safe nothrow @nogc:
81 
82 /// 
83 /// 
84 /// Params:
85 /// secret = Your secret key, the 'exponent'.
86 /// p = Receivers public key. Default base point = 9.
87 /// 
88 /// Returns: p^secret.
89 /// 
90 /// Examples:
91 /// 
92 /// ubyte[32] publicKey = curve25519_scalarmult(secretKey);
93 /// 
94 /// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey);
95 /// 
96 ubyte[32] curve25519_scalarmult(in ubyte[] secret, in ubyte[] p = publicBasePoint) @safe nothrow @nogc
97 in {
98 	assert(secret.length == 32, "Secret key must be 32 bytes long.");
99 	assert(p.length == 32, "Public key must be 32 bytes long.");
100 } body {
101 	ubyte[32] sec = secret;
102 	scope(exit) {
103 		wipe(sec);
104 	}
105 
106 	ubyte[32] pub = p;
107 
108 	return curve25519_scalarmult(sec, pub);
109 }
110 
111 /// 
112 /// 
113 /// Params:
114 /// secret = Your secret key, the 'exponent'.
115 /// p = Receivers public key. Default base point = 9.
116 /// 
117 /// Returns: p^secret.
118 /// 
119 /// Examples:
120 /// 
121 /// ubyte[32] publicKey = curve25519_scalarmult(secretKey);
122 /// 
123 /// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey);
124 /// 
125 ubyte[32] curve25519_scalarmult(in ref ubyte[32] secret, in ref ubyte[32] p = publicBasePoint) @safe nothrow @nogc
126 {
127 	ubyte[32] e = secret;
128 	scope(exit) {
129 		wipe(e);
130 	}
131 	clamp(e);
132 
133 	fe x1, x2, x3, z2, z3, tmp0, tmp1;
134 	scope(exit) {
135 		wipe(x1);
136 		wipe(x2);
137 		wipe(x3);
138 		wipe(z2);
139 		wipe(z3);
140 		wipe(tmp0);
141 		wipe(tmp1);
142 	}
143 
144 	x1 = fe.fromBytes(p);
145 	x2 = fe.one;
146 	z2 = fe.zero;
147 	x3 = x1;
148 	z3 = fe.one;
149 
150 	uint swap = 0, b;
151 	for (int pos = 254; pos >= 0;--pos) {
152 		b = e[pos / 8] >> (pos & 7);
153 		b &= 1;
154 		swap ^= b;
155 		fe_cswap(x2,x3,swap);
156 		fe_cswap(z2,z3,swap);
157 		swap = b;
158 
159 		tmp0 = x3 - z3;
160 
161 		tmp1 = x2 - z2;
162 		x2 += z2;
163 		z2 = x3 + z3;
164 
165 		z3 = tmp0 * x2;
166 
167 		z2 *= tmp1;
168 		tmp0 = tmp1.sq;
169 		tmp1 = x2.sq;
170 		x3 = z2 + z3;
171 
172 		z2 = z3 - z2;
173 		x2 = tmp0 * tmp1;
174 
175 		tmp1 -= tmp0;
176 		
177 		z2 = z2.sq;
178 
179 		z3 = fe_mul121666(tmp1);
180 
181 		x3 = x3.sq;
182 
183 		tmp0 += z3;
184 		z3 = x1 * z2;
185 
186 		z2 = tmp0 * tmp1;
187 	}
188 	fe_cswap(x2,x3,swap);
189 	fe_cswap(z2,z3,swap);
190 
191 	x2 *= z2.inverse;
192 	return x2.toBytes;
193 }
194 
195 /// Transforms 32 random bytes into a valid secret key.
196 /// 
197 /// Params:
198 /// sk = 32 byte secret key.
199 package void clamp(ubyte[] sk) pure
200 in {
201 	assert(sk.length == 32);
202 } body {
203 	sk[0] &= 248;
204 	sk[31] &= 63;
205 	sk[31] |= 64;
206 }