module angel.utils.cryptography.curve25519; import angel.utils.cryptography.fieldelem; import angel.utils.cryptography.utils; public enum ubyte[32] publicBasePoint = cast(immutable (ubyte[32]) ) x"0900000000000000000000000000000000000000000000000000000000000000"; @safe nothrow @nogc: /// /// /// Params: /// secret = Your secret key, the 'exponent'. /// p = Receivers public key. Default base point = 9. /// /// Returns: p^secret. /// /// Examples: /// /// ubyte[32] publicKey = curve25519_scalarmult(secretKey); /// /// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey); /// ubyte[32] curve25519_scalarmult( in ubyte[] secret, in ubyte[] p = cast(const ubyte[32]) publicBasePoint) @safe nothrow @nogc in { assert(secret.length == 32, "Secret key must be 32 bytes long."); assert(p.length == 32, "Public key must be 32 bytes long."); } body { ubyte[32] sec = secret; scope(exit) { wipe(sec); } ubyte[32] pub = p; return curve25519_scalarmult(sec, pub); } /// /// /// Params: /// secret = Your secret key, the 'exponent'. /// p = Receivers public key. Default base point = 9. /// /// Returns: p^secret. /// /// Examples: /// /// ubyte[32] publicKey = curve25519_scalarmult(secretKey); /// /// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey); /// ubyte[32] curve25519_scalarmult(in ref ubyte[32] secret, in ref ubyte[32] p = publicBasePoint) @safe nothrow @nogc { ubyte[32] e = secret; scope(exit) { wipe(e); } clamp(e); fe x1, x2, x3, z2, z3, tmp0, tmp1; scope(exit) { wipe(x1); wipe(x2); wipe(x3); wipe(z2); wipe(z3); wipe(tmp0); wipe(tmp1); } x1 = fe.fromBytes(p); x2 = fe.one; z2 = fe.zero; x3 = x1; z3 = fe.one; uint swap = 0, b; for (int pos = 254; pos >= 0;--pos) { b = e[pos / 8] >> (pos & 7); b &= 1; swap ^= b; fe_cswap(x2,x3,swap); fe_cswap(z2,z3,swap); swap = b; tmp0 = x3 - z3; tmp1 = x2 - z2; x2 += z2; z2 = x3 + z3; z3 = tmp0 * x2; z2 *= tmp1; tmp0 = tmp1.sq; tmp1 = x2.sq; x3 = z2 + z3; z2 = z3 - z2; x2 = tmp0 * tmp1; tmp1 -= tmp0; z2 = z2.sq; z3 = fe_mul121666(tmp1); x3 = x3.sq; tmp0 += z3; z3 = x1 * z2; z2 = tmp0 * tmp1; } fe_cswap(x2,x3,swap); fe_cswap(z2,z3,swap); x2 *= z2.inverse; return x2.toBytes; } /// Transforms 32 random bytes into a valid secret key. /// /// Params: /// sk = 32 byte secret key. package void clamp(ubyte[] sk) pure in { assert(sk.length == 32); } body { sk[0] &= 248; sk[31] &= 63; sk[31] |= 64; }