summary refs log tree commit diff
path: root/crypto/src/math/ec/rfc7748/X25519.cs
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-10-01 19:46:15 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-10-01 19:46:15 +0700
commit2f4de05c64ba6653bec38941ba1b66c6e16f05b2 (patch)
treefc27b837ffdd6e0b399c604db4ed88a035a1d936 /crypto/src/math/ec/rfc7748/X25519.cs
parentPort Blake2xsDigest from bc-java (diff)
downloadBouncyCastle.NET-ed25519-2f4de05c64ba6653bec38941ba1b66c6e16f05b2.tar.xz
Span-based variant of IRawAgreement.CalculateAgreement
Diffstat (limited to 'crypto/src/math/ec/rfc7748/X25519.cs')
-rw-r--r--crypto/src/math/ec/rfc7748/X25519.cs98
1 files changed, 98 insertions, 0 deletions
diff --git a/crypto/src/math/ec/rfc7748/X25519.cs b/crypto/src/math/ec/rfc7748/X25519.cs
index 217ef8785..2a471ae26 100644
--- a/crypto/src/math/ec/rfc7748/X25519.cs
+++ b/crypto/src/math/ec/rfc7748/X25519.cs
@@ -26,6 +26,36 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
             return !Arrays.AreAllZeroes(r, rOff, PointSize);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static bool CalculateAgreement(ReadOnlySpan<byte> k, ReadOnlySpan<byte> u, Span<byte> r)
+        {
+            ScalarMult(k, u, r);
+            return !Arrays.AreAllZeroes(r[..PointSize]);
+        }
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private static uint Decode32(ReadOnlySpan<byte> bs)
+        {
+            uint n = bs[0];
+            n |= (uint)bs[1] << 8;
+            n |= (uint)bs[2] << 16;
+            n |= (uint)bs[3] << 24;
+            return n;
+        }
+
+        private static void DecodeScalar(ReadOnlySpan<byte> k, Span<uint> n)
+        {
+            for (int i = 0; i < 8; ++i)
+            {
+                n[i] = Decode32(k[(i * 4)..]);
+            }
+
+            n[0] &= 0xFFFFFFF8U;
+            n[7] &= 0x7FFFFFFFU;
+            n[7] |= 0x40000000U;
+        }
+#else
         private static uint Decode32(byte[] bs, int off)
         {
             uint n = bs[off];
@@ -46,6 +76,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
             n[7] &= 0x7FFFFFFFU;
             n[7] |= 0x40000000U;
         }
+#endif
 
         public static void GeneratePrivateKey(SecureRandom random, byte[] k)
         {
@@ -83,6 +114,9 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
 
         public static void ScalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            ScalarMult(k.AsSpan(kOff), u.AsSpan(uOff), r.AsSpan(rOff));
+#else
             uint[] n = new uint[8];     DecodeScalar(k, kOff, n);
 
             int[] x1 = F.Create();      F.Decode(u, uOff, x1);
@@ -140,7 +174,71 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748
 
             F.Normalize(x2);
             F.Encode(x2, r, rOff);
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void ScalarMult(ReadOnlySpan<byte> k, ReadOnlySpan<byte> u, Span<byte> r)
+        {
+            uint[] n = new uint[8];     DecodeScalar(k, n);
+
+            int[] x1 = F.Create();      F.Decode(u, x1);
+            int[] x2 = F.Create();      F.Copy(x1, 0, x2, 0);
+            int[] z2 = F.Create();      z2[0] = 1;
+            int[] x3 = F.Create();      x3[0] = 1;
+            int[] z3 = F.Create();
+
+            int[] t1 = F.Create();
+            int[] t2 = F.Create();
+
+            Debug.Assert(n[7] >> 30 == 1U);
+
+            int bit = 254, swap = 1;
+            do
+            {
+                F.Apm(x3, z3, t1, x3);
+                F.Apm(x2, z2, z3, x2);
+                F.Mul(t1, x2, t1);
+                F.Mul(x3, z3, x3);
+                F.Sqr(z3, z3);
+                F.Sqr(x2, x2);
+
+                F.Sub(z3, x2, t2);
+                F.Mul(t2, C_A24, z2);
+                F.Add(z2, x2, z2);
+                F.Mul(z2, t2, z2);
+                F.Mul(x2, z3, x2);
+
+                F.Apm(t1, x3, x3, z3);
+                F.Sqr(x3, x3);
+                F.Sqr(z3, z3);
+                F.Mul(z3, x1, z3);
+
+                --bit;
+
+                int word = bit >> 5, shift = bit & 0x1F;
+                int kt = (int)(n[word] >> shift) & 1;
+                swap ^= kt;
+                F.CSwap(swap, x2, x3);
+                F.CSwap(swap, z2, z3);
+                swap = kt;
+            }
+            while (bit >= 3);
+
+            Debug.Assert(swap == 0);
+
+            for (int i = 0; i < 3; ++i)
+            {
+                PointDouble(x2, z2);
+            }
+
+            F.Inv(z2, z2);
+            F.Mul(x2, z2, x2);
+
+            F.Normalize(x2);
+            F.Encode(x2, r);
         }
+#endif
 
         public static void ScalarMultBase(byte[] k, int kOff, byte[] r, int rOff)
         {