X25519
using Org.BouncyCastle.Math.EC.Rfc8032;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Math.EC.Rfc7748
{
public static class X25519
{
public const int PointSize = 32;
public const int ScalarSize = 32;
private const int C_A = 486662;
private const int C_A24 = 121666;
public static bool CalculateAgreement(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff)
{
ScalarMult(k, kOff, u, uOff, r, rOff);
return !Arrays.AreAllZeroes(r, rOff, 32);
}
public static bool CalculateAgreement(ReadOnlySpan<byte> k, ReadOnlySpan<byte> u, Span<byte> r)
{
ScalarMult(k, u, r);
return !Arrays.AreAllZeroes(r.Slice(0, 32));
}
private static uint Decode32(ReadOnlySpan<byte> bs)
{
return (uint)(bs[0] | (bs[1] << 8) | (bs[2] << 16) | (bs[3] << 24));
}
private static void DecodeScalar(ReadOnlySpan<byte> k, Span<uint> n)
{
for (int i = 0; i < 8; i++) {
ref uint reference = ref n[i];
int num = i * 4;
reference = Decode32(k.Slice(num, k.Length - num));
}
n[0] &= 4294967288;
n[7] &= 2147483647;
n[7] |= 1073741824;
}
public static void GeneratePrivateKey(SecureRandom random, byte[] k)
{
if (k.Length != 32)
throw new ArgumentException("k");
random.NextBytes(k);
k[0] &= 248;
k[31] &= 127;
k[31] |= 64;
}
public static void GeneratePrivateKey(SecureRandom random, Span<byte> k)
{
if (k.Length != 32)
throw new ArgumentException("k");
random.NextBytes(k);
k[0] &= 248;
k[31] &= 127;
k[31] |= 64;
}
public static void GeneratePublicKey(byte[] k, int kOff, byte[] r, int rOff)
{
ScalarMultBase(k, kOff, r, rOff);
}
public static void GeneratePublicKey(ReadOnlySpan<byte> k, Span<byte> r)
{
ScalarMultBase(k, r);
}
private static void PointDouble(int[] x, int[] z)
{
int[] array = X25519Field.Create();
int[] array2 = X25519Field.Create();
X25519Field.Apm(x, z, array, array2);
X25519Field.Sqr(array, array);
X25519Field.Sqr(array2, array2);
X25519Field.Mul(array, array2, x);
X25519Field.Sub(array, array2, array);
X25519Field.Mul(array, 121666, z);
X25519Field.Add(z, array2, z);
X25519Field.Mul(z, array, z);
}
public static void Precompute()
{
Ed25519.Precompute();
}
public static void ScalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff)
{
ScalarMult(k.AsSpan(kOff), u.AsSpan(uOff), r.AsSpan(rOff));
}
public static void ScalarMult(ReadOnlySpan<byte> k, ReadOnlySpan<byte> u, Span<byte> r)
{
uint[] array = new uint[8];
DecodeScalar(k, array);
int[] array2 = X25519Field.Create();
X25519Field.Decode(u, array2);
int[] array3 = X25519Field.Create();
X25519Field.Copy(array2, 0, array3, 0);
int[] array4 = X25519Field.Create();
array4[0] = 1;
int[] array5 = X25519Field.Create();
array5[0] = 1;
int[] array6 = X25519Field.Create();
int[] array7 = X25519Field.Create();
int[] array8 = X25519Field.Create();
int num = 254;
int num2 = 1;
do {
X25519Field.Apm(array5, array6, array7, array5);
X25519Field.Apm(array3, array4, array6, array3);
X25519Field.Mul(array7, array3, array7);
X25519Field.Mul(array5, array6, array5);
X25519Field.Sqr(array6, array6);
X25519Field.Sqr(array3, array3);
X25519Field.Sub(array6, array3, array8);
X25519Field.Mul(array8, 121666, array4);
X25519Field.Add(array4, array3, array4);
X25519Field.Mul(array4, array8, array4);
X25519Field.Mul(array3, array6, array3);
X25519Field.Apm(array7, array5, array5, array6);
X25519Field.Sqr(array5, array5);
X25519Field.Sqr(array6, array6);
X25519Field.Mul(array6, array2, array6);
num--;
int num3 = num >> 5;
int num4 = num & 31;
int num5 = (int)((array[num3] >> num4) & 1);
num2 ^= num5;
X25519Field.CSwap(num2, array3, array5);
X25519Field.CSwap(num2, array4, array6);
num2 = num5;
} while (num >= 3);
for (int i = 0; i < 3; i++) {
PointDouble(array3, array4);
}
X25519Field.Inv(array4, array4);
X25519Field.Mul(array3, array4, array3);
X25519Field.Normalize(array3);
X25519Field.Encode(array3, r);
}
public static void ScalarMultBase(byte[] k, int kOff, byte[] r, int rOff)
{
ScalarMultBase(k.AsSpan(kOff), r.AsSpan(rOff));
}
public static void ScalarMultBase(ReadOnlySpan<byte> k, Span<byte> r)
{
int[] array = X25519Field.Create();
int[] array2 = X25519Field.Create();
Ed25519.ScalarMultBaseYZ(k, array, array2);
X25519Field.Apm(array2, array, array, array2);
X25519Field.Inv(array2, array2);
X25519Field.Mul(array, array2, array);
X25519Field.Normalize(array);
X25519Field.Encode(array, r);
}
}
}