summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-10-05 15:39:23 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-10-05 15:39:23 +0700
commit57a13b4f15c5a5b8f495b83b5ea825716a199935 (patch)
tree0f454ba2b3a4f542534ab96db358251f4ca85bae
parentVarious span usage in TLS code (diff)
downloadBouncyCastle.NET-ed25519-57a13b4f15c5a5b8f495b83b5ea825716a199935.tar.xz
BigInteger in-place conversions
-rw-r--r--crypto/src/math/BigInteger.cs116
-rw-r--r--crypto/src/util/BigIntegers.cs70
2 files changed, 145 insertions, 41 deletions
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs
index fc4e15486..4cb220d00 100644
--- a/crypto/src/math/BigInteger.cs
+++ b/crypto/src/math/BigInteger.cs
@@ -14,7 +14,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math
 {
     [Serializable]
-    public class BigInteger
+    public sealed class BigInteger
     {
         // The first few odd primes
         /*
@@ -237,8 +237,7 @@ namespace Org.BouncyCastle.Math
             this.mQuote = 0;
         }
 
-        private static int GetByteLength(
-            int nBits)
+        private static int GetByteLength(int nBits)
         {
             return (nBits + BitsPerByte - 1) / BitsPerByte;
         }
@@ -3169,18 +3168,41 @@ namespace Org.BouncyCastle.Math
             return Subtract(0, res, 0, lilMag);
         }
 
+        public int GetLengthofByteArray()
+        {
+            return GetByteLength(BitLength + 1);
+        }
+
+        public int GetLengthofByteArrayUnsigned()
+        {
+            return GetByteLength(sign < 0 ? BitLength + 1 : BitLength);
+        }
+
         public byte[] ToByteArray()
         {
             return ToByteArray(false);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ToByteArray(Span<byte> output)
+        {
+            ToByteArray(false, output);
+        }
+#endif
+
         public byte[] ToByteArrayUnsigned()
         {
             return ToByteArray(true);
         }
 
-        private byte[] ToByteArray(
-            bool unsigned)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ToByteArrayUnsigned(Span<byte> output)
+        {
+            ToByteArray(true, output);
+        }
+#endif
+
+        private byte[] ToByteArray(bool unsigned)
         {
             if (sign == 0)
                 return unsigned ? ZeroEncoding : new byte[1];
@@ -3259,6 +3281,90 @@ namespace Org.BouncyCastle.Math
             return bytes;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private void ToByteArray(bool unsigned, Span<byte> output)
+        {
+            if (sign == 0)
+            {
+                if (!unsigned)
+                {
+                    output[0] = 0;
+                }
+                return;
+            }
+
+            int nBits = (unsigned && sign > 0) ? BitLength : BitLength + 1;
+
+            int nBytes = GetByteLength(nBits);
+            if (nBytes > output.Length)
+                throw new ArgumentException("insufficient space", nameof(output));
+
+            int magIndex = magnitude.Length;
+            int bytesIndex = nBytes;
+
+            if (sign > 0)
+            {
+                while (magIndex > 1)
+                {
+                    uint mag = (uint) magnitude[--magIndex];
+                    output[--bytesIndex] = (byte) mag;
+                    output[--bytesIndex] = (byte)(mag >> 8);
+                    output[--bytesIndex] = (byte)(mag >> 16);
+                    output[--bytesIndex] = (byte)(mag >> 24);
+                }
+
+                uint lastMag = (uint)magnitude[0];
+                while (lastMag > byte.MaxValue)
+                {
+                    output[--bytesIndex] = (byte)lastMag;
+                    lastMag >>= 8;
+                }
+
+                output[--bytesIndex] = (byte)lastMag;
+            }
+            else // sign < 0
+            {
+                bool carry = true;
+
+                while (magIndex > 1)
+                {
+                    uint mag = ~((uint)magnitude[--magIndex]);
+
+                    if (carry)
+                    {
+                        carry = (++mag == uint.MinValue);
+                    }
+
+                    output[--bytesIndex] = (byte) mag;
+                    output[--bytesIndex] = (byte)(mag >> 8);
+                    output[--bytesIndex] = (byte)(mag >> 16);
+                    output[--bytesIndex] = (byte)(mag >> 24);
+                }
+
+                uint lastMag = (uint)magnitude[0];
+
+                if (carry)
+                {
+                    // Never wraps because magnitude[0] != 0
+                    --lastMag;
+                }
+
+                while (lastMag > byte.MaxValue)
+                {
+                    output[--bytesIndex] = (byte)~lastMag;
+                    lastMag >>= 8;
+                }
+
+                output[--bytesIndex] = (byte)~lastMag;
+
+                if (bytesIndex > 0)
+                {
+                    output[--bytesIndex] = byte.MaxValue;
+                }
+            }
+        }
+#endif
+
         public override string ToString()
         {
             return ToString(10);
diff --git a/crypto/src/util/BigIntegers.cs b/crypto/src/util/BigIntegers.cs
index 1d706beb4..44c9e32a7 100644
--- a/crypto/src/util/BigIntegers.cs
+++ b/crypto/src/util/BigIntegers.cs
@@ -22,8 +22,7 @@ namespace Org.BouncyCastle.Utilities
         * @param value the value to be converted.
         * @return a byte array without a leading zero byte if present in the signed encoding.
         */
-        public static byte[] AsUnsignedByteArray(
-            BigInteger n)
+        public static byte[] AsUnsignedByteArray(BigInteger n)
         {
             return n.ToByteArrayUnsigned();
         }
@@ -37,6 +36,16 @@ namespace Org.BouncyCastle.Utilities
          */
         public static byte[] AsUnsignedByteArray(int length, BigInteger n)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            int bytesLength = n.GetLengthofByteArrayUnsigned();
+
+            if (bytesLength > length)
+                throw new ArgumentException("standard length exceeded", nameof(n));
+
+            byte[] bytes = new byte[length];
+            n.ToByteArrayUnsigned(bytes.AsSpan(length - bytesLength));
+            return bytes;
+#else
             byte[] bytes = n.ToByteArrayUnsigned();
             int bytesLength = bytes.Length;
 
@@ -44,18 +53,19 @@ namespace Org.BouncyCastle.Utilities
                 return bytes;
 
             if (bytesLength > length)
-                throw new ArgumentException("standard length exceeded", "n");
+                throw new ArgumentException("standard length exceeded", nameof(n));
 
             byte[] tmp = new byte[length];
             Array.Copy(bytes, 0, tmp, length - bytesLength, bytesLength);
             return tmp;
+#endif
         }
 
         /**
          * Write the passed in value as unsigned bytes to the specified buffer range, padded with
          * leading zeros as necessary.
          *
-         * @param value
+         * @param n
          *            the value to be converted.
          * @param buf
          *            the buffer to which the value is written.
@@ -64,50 +74,33 @@ namespace Org.BouncyCastle.Utilities
          * @param len
          *            the fixed length of data written (possibly padded with leading zeros).
          */
-        public static void AsUnsignedByteArray(BigInteger value, byte[] buf, int off, int len)
+        public static void AsUnsignedByteArray(BigInteger n, byte[] buf, int off, int len)
         {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            AsUnsignedByteArray(value, buf.AsSpan(off, len));
+            AsUnsignedByteArray(n, buf.AsSpan(off, len));
 #else
-            byte[] bytes = value.ToByteArrayUnsigned();
-            if (bytes.Length == len)
-            {
-                Array.Copy(bytes, 0, buf, off, len);
-                return;
-            }
-
-            int start = bytes[0] == 0 ? 1 : 0;
-            int count = bytes.Length - start;
+            byte[] bytes = n.ToByteArrayUnsigned();
+            int bytesLength = bytes.Length;
 
-            if (count > len)
-                throw new ArgumentException("standard length exceeded for value");
+            if (bytesLength > len)
+                throw new ArgumentException("standard length exceeded", nameof(n));
 
-            int padLen = len - count;
+            int padLen = len - bytesLength;
             Arrays.Fill(buf, off, off + padLen, 0);
-            Array.Copy(bytes, start, buf, off + padLen, count);
+            Array.Copy(bytes, 0, buf, off + padLen, bytesLength);
 #endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public static void AsUnsignedByteArray(BigInteger value, Span<byte> buf)
+        public static void AsUnsignedByteArray(BigInteger n, Span<byte> buf)
         {
-            int len = buf.Length;
-            byte[] bytes = value.ToByteArrayUnsigned();
-            if (bytes.Length == len)
-            {
-                bytes.CopyTo(buf);
-                return;
-            }
+            int bytesLength = n.GetLengthofByteArrayUnsigned();
 
-            int start = bytes[0] == 0 ? 1 : 0;
-            int count = bytes.Length - start;
+            if (bytesLength > buf.Length)
+                throw new ArgumentException("standard length exceeded", nameof(n));
 
-            if (count > len)
-                throw new ArgumentException("standard length exceeded for value");
-
-            int padLen = len - count;
-            buf[..padLen].Fill(0x00);
-            bytes.AsSpan(start, count).CopyTo(buf[padLen..]);
+            buf[..^bytesLength].Fill(0x00);
+            n.ToByteArrayUnsigned(buf[^bytesLength..]);
         }
 #endif
 
@@ -209,9 +202,14 @@ namespace Org.BouncyCastle.Utilities
             return Nat.ToBigInteger(len, z);
         }
 
+        public static int GetByteLength(BigInteger n)
+        {
+            return n.GetLengthofByteArray();
+        }
+
         public static int GetUnsignedByteLength(BigInteger n)
         {
-            return (n.BitLength + 7) / 8;
+            return n.GetLengthofByteArrayUnsigned();
         }
     }
 }