136 lines
2.6 KiB
D
136 lines
2.6 KiB
D
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;
|
|
} |