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 }