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 }