1 module dcrypt.ecc.curve25519;
2 
3 import dcrypt.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(
97 	in ubyte[] secret, 
98 	in ubyte[] p = cast(const ubyte[32]) publicBasePoint) @safe nothrow @nogc
99 in {
100 	assert(secret.length == 32, "Secret key must be 32 bytes long.");
101 	assert(p.length == 32, "Public key must be 32 bytes long.");
102 } body {
103 	ubyte[32] sec = secret;
104 	scope(exit) {
105 		wipe(sec);
106 	}
107 
108 	ubyte[32] pub = p;
109 
110 	return curve25519_scalarmult(sec, pub);
111 }
112 
113 /// 
114 /// 
115 /// Params:
116 /// secret = Your secret key, the 'exponent'.
117 /// p = Receivers public key. Default base point = 9.
118 /// 
119 /// Returns: p^secret.
120 /// 
121 /// Examples:
122 /// 
123 /// ubyte[32] publicKey = curve25519_scalarmult(secretKey);
124 /// 
125 /// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey);
126 /// 
127 ubyte[32] curve25519_scalarmult(in ref ubyte[32] secret, in ref ubyte[32] p = publicBasePoint) @safe nothrow @nogc
128 {
129 	ubyte[32] e = secret;
130 	scope(exit) {
131 		wipe(e);
132 	}
133 	clamp(e);
134 
135 	fe x1, x2, x3, z2, z3, tmp0, tmp1;
136 	scope(exit) {
137 		wipe(x1);
138 		wipe(x2);
139 		wipe(x3);
140 		wipe(z2);
141 		wipe(z3);
142 		wipe(tmp0);
143 		wipe(tmp1);
144 	}
145 
146 	x1 = fe.fromBytes(p);
147 	x2 = fe.one;
148 	z2 = fe.zero;
149 	x3 = x1;
150 	z3 = fe.one;
151 
152 	uint swap = 0, b;
153 	for (int pos = 254; pos >= 0;--pos) {
154 		b = e[pos / 8] >> (pos & 7);
155 		b &= 1;
156 		swap ^= b;
157 		fe_cswap(x2,x3,swap);
158 		fe_cswap(z2,z3,swap);
159 		swap = b;
160 
161 		tmp0 = x3 - z3;
162 
163 		tmp1 = x2 - z2;
164 		x2 += z2;
165 		z2 = x3 + z3;
166 
167 		z3 = tmp0 * x2;
168 
169 		z2 *= tmp1;
170 		tmp0 = tmp1.sq;
171 		tmp1 = x2.sq;
172 		x3 = z2 + z3;
173 
174 		z2 = z3 - z2;
175 		x2 = tmp0 * tmp1;
176 
177 		tmp1 -= tmp0;
178 		
179 		z2 = z2.sq;
180 
181 		z3 = fe_mul121666(tmp1);
182 
183 		x3 = x3.sq;
184 
185 		tmp0 += z3;
186 		z3 = x1 * z2;
187 
188 		z2 = tmp0 * tmp1;
189 	}
190 	fe_cswap(x2,x3,swap);
191 	fe_cswap(z2,z3,swap);
192 
193 	x2 *= z2.inverse;
194 	return x2.toBytes;
195 }
196 
197 /// Transforms 32 random bytes into a valid secret key.
198 /// 
199 /// Params:
200 /// sk = 32 byte secret key.
201 package void clamp(ubyte[] sk) pure
202 in {
203 	assert(sk.length == 32);
204 } body {
205 	sk[0] &= 248;
206 	sk[31] &= 63;
207 	sk[31] |= 64;
208 }