Files
angelc2/curve25519.d
2025-12-22 15:13:52 +00:00

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;
}