summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-04-20 15:32:18 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-04-20 15:32:18 +0700
commitcaa2a7dfcc4038b83d7ff19d90c491912827f448 (patch)
tree9ee395339edd6b0a8a51f14a1a25813ccb980080
parentRefactoring in BigInteger (diff)
downloadBouncyCastle.NET-ed25519-caa2a7dfcc4038b83d7ff19d90c491912827f448.tar.xz
BigInteger construction from little-endian
-rw-r--r--crypto/src/crypto/signers/ECGOST3410Signer.cs6
-rw-r--r--crypto/src/crypto/signers/GOST3410Signer.cs14
-rw-r--r--crypto/src/crypto/util/Pack.cs40
-rw-r--r--crypto/src/math/BigInteger.cs189
-rw-r--r--crypto/src/math/raw/Nat.cs11
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs15
-rw-r--r--crypto/src/security/PublicKeyFactory.cs4
7 files changed, 232 insertions, 47 deletions
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index fd5fa4818..ba6969e39 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -68,8 +68,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (!forSigning)
                 throw new InvalidOperationException("not initialized for signing");
 
-            byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
-            BigInteger e = new BigInteger(1, mRev);
+            BigInteger e = new BigInteger(1, message, bigEndian: false);
 
             ECDomainParameters ec = key.Parameters;
             BigInteger n = ec.N;
@@ -113,8 +112,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (forSigning)
                 throw new InvalidOperationException("not initialized for verification");
 
-            byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
-            BigInteger e = new BigInteger(1, mRev);
+            BigInteger e = new BigInteger(1, message, bigEndian: false);
             BigInteger n = key.Parameters.N;
 
             // r in the range [1,n-1]
diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs
index 03aab0b04..0d80737d0 100644
--- a/crypto/src/crypto/signers/GOST3410Signer.cs
+++ b/crypto/src/crypto/signers/GOST3410Signer.cs
@@ -61,11 +61,9 @@ namespace Org.BouncyCastle.Crypto.Signers
 		 *
 		 * @param message the message that will be verified later.
 		 */
-        public virtual BigInteger[] GenerateSignature(
-			byte[] message)
+        public virtual BigInteger[] GenerateSignature(byte[] message)
 		{
-            byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
-			BigInteger m = new BigInteger(1, mRev);
+			BigInteger m = new BigInteger(1, message, bigEndian: false);
 			Gost3410Parameters parameters = key.Parameters;
 			BigInteger k;
 
@@ -89,13 +87,9 @@ namespace Org.BouncyCastle.Crypto.Signers
 		 * the passed in message for standard Gost3410 the message should be a
 		 * Gost3411 hash of the real message to be verified.
 		 */
-        public virtual bool VerifySignature(
-			byte[]		message,
-			BigInteger	r,
-			BigInteger	s)
+        public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
 		{
-            byte[] mRev = Arrays.Reverse(message); // conversion is little-endian
-            BigInteger m = new BigInteger(1, mRev);
+            BigInteger m = new BigInteger(1, message, bigEndian: false);
 			Gost3410Parameters parameters = key.Parameters;
 
 			if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0)
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 99c15484c..a4f8a834f 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -578,6 +578,25 @@ namespace Org.BouncyCastle.Crypto.Utilities
 #endif
         }
 
+        internal static uint LE_To_UInt32_High(byte[] bs, int off, int len)
+        {
+            return LE_To_UInt32_Low(bs, off, len) << ((4 - len) << 3);
+        }
+
+        internal static uint LE_To_UInt32_Low(byte[] bs, int off, int len)
+        {
+            Debug.Assert(1 <= len && len <= 4);
+
+            uint result = bs[off];
+            int pos = 0;
+            for (int i = 1; i < len; ++i)
+            {
+                pos += 8;
+                result |= (uint)bs[off + i] << pos;
+            }
+            return result;
+        }
+
         internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
         {
             for (int i = 0; i < ns.Length; ++i)
@@ -826,6 +845,27 @@ namespace Org.BouncyCastle.Crypto.Utilities
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static uint LE_To_UInt32_High(ReadOnlySpan<byte> bs)
+        {
+            return LE_To_UInt32_Low(bs) << ((4 - bs.Length) << 3);
+        }
+
+        internal static uint LE_To_UInt32_Low(ReadOnlySpan<byte> bs)
+        {
+            int len = bs.Length;
+            Debug.Assert(1 <= len && len <= 4);
+
+            uint result = bs[0];
+            int pos = 0;
+            for (int i = 1; i < len; ++i)
+            {
+                pos += 8;
+                result |= (uint)bs[i] << pos;
+            }
+            return result;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal static ulong LE_To_UInt64(ReadOnlySpan<byte> bs)
         {
             return BinaryPrimitives.ReadUInt64LittleEndian(bs);
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs
index a98955779..7da886c4f 100644
--- a/crypto/src/math/BigInteger.cs
+++ b/crypto/src/math/BigInteger.cs
@@ -475,8 +475,15 @@ namespace Org.BouncyCastle.Math
         }
 
         public BigInteger(byte[] bytes)
-            : this(bytes, 0, bytes.Length)
         {
+            this.magnitude = InitBE(bytes, 0, bytes.Length, out this.sign);
+        }
+
+        public BigInteger(byte[] bytes, bool bigEndian)
+        {
+            this.magnitude = bigEndian
+                ? InitBE(bytes, 0, bytes.Length, out this.sign)
+                : InitLE(bytes, 0, bytes.Length, out this.sign);
         }
 
         public BigInteger(byte[] bytes, int offset, int length)
@@ -484,16 +491,30 @@ namespace Org.BouncyCastle.Math
             if (length == 0)
                 throw new FormatException("Zero length BigInteger");
 
-            // TODO Move this processing into MakeMagnitude (provide sign argument)
+            this.magnitude = InitBE(bytes, offset, length, out this.sign);
+        }
+
+        public BigInteger(byte[] bytes, int offset, int length, bool bigEndian)
+        {
+            if (length <= 0)
+                throw new FormatException("Zero length BigInteger");
+
+            this.magnitude = bigEndian
+                ? InitBE(bytes, offset, length, out this.sign)
+                : InitLE(bytes, offset, length, out this.sign);
+        }
+
+        private static uint[] InitBE(byte[] bytes, int offset, int length, out int sign)
+        {
+            // TODO Move this processing into MakeMagnitudeBE (provide sign argument)
             if ((sbyte)bytes[offset] >= 0)
             {
-                // strip leading zero bytes and return magnitude bytes
-                this.magnitude = MakeMagnitudeBE(bytes, offset, length);
-                this.sign = this.magnitude.Length > 0 ? 1 : 0;
-                return;
+                uint[] magnitude = MakeMagnitudeBE(bytes, offset, length);
+                sign = magnitude.Length > 0 ? 1 : 0;
+                return magnitude;
             }
 
-            this.sign = -1;
+            sign = -1;
 
             int end = offset + length;
 
@@ -504,10 +525,7 @@ namespace Org.BouncyCastle.Math
             }
 
             if (iBval >= end)
-            {
-                this.magnitude = One.magnitude;
-                return;
-            }
+                return One.magnitude;
 
             int numBytes = end - iBval;
 
@@ -534,7 +552,56 @@ namespace Org.BouncyCastle.Math
 
             inverse[index]++;
 
-            this.magnitude = MakeMagnitudeBE(inverse);
+            return MakeMagnitudeBE(inverse);
+        }
+
+        private static uint[] InitLE(byte[] bytes, int offset, int length, out int sign)
+        {
+            int end = offset + length;
+
+            // TODO Move this processing into MakeMagnitudeLE (provide sign argument)
+            if ((sbyte)bytes[end - 1] >= 0)
+            {
+                uint[] magnitude = MakeMagnitudeLE(bytes, offset, length);
+                sign = magnitude.Length > 0 ? 1 : 0;
+                return magnitude;
+            }
+
+            sign = -1;
+
+            // strip leading sign bytes
+            int last = length;
+            while (--last >= 0 && bytes[offset + last] == byte.MaxValue)
+            {
+            }
+
+            if (last < 0)
+                return One.magnitude;
+
+            int numBytes = last + 1;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> inverse = numBytes <= 512
+                ? stackalloc byte[numBytes]
+                : new byte[numBytes];
+#else
+            byte[] inverse = new byte[numBytes];
+#endif
+
+            for (int i = 0; i < numBytes; ++i)
+            {
+                inverse[i] = (byte)~bytes[offset + i];
+            }
+
+            int index = 0;
+            while (inverse[index] == byte.MaxValue)
+            {
+                inverse[index++] = byte.MinValue;
+            }
+
+            inverse[index]++;
+
+            return MakeMagnitudeLE(inverse);
         }
 
         private static uint[] MakeMagnitudeBE(byte[] bytes)
@@ -600,12 +667,95 @@ namespace Org.BouncyCastle.Math
         }
 #endif
 
+        private static uint[] MakeMagnitudeLE(byte[] bytes)
+        {
+            return MakeMagnitudeLE(bytes, 0, bytes.Length);
+        }
+
+        private static uint[] MakeMagnitudeLE(byte[] bytes, int offset, int length)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return MakeMagnitudeLE(bytes.AsSpan(offset, length));
+#else
+            // strip leading zeros
+            int last = length;
+            while (--last >= 0 && bytes[offset + last] == 0)
+            {
+            }
+
+            if (last < 0)
+                return ZeroMagnitude;
+
+            int nInts = (last + BytesPerInt) / BytesPerInt;
+            Debug.Assert(nInts > 0);
+
+            uint[] magnitude = new uint[nInts];
+
+            int partial = last % BytesPerInt;
+            int first = partial + 1;
+            int pos = offset + last - partial;
+
+            magnitude[0] = Pack.LE_To_UInt32_Low(bytes, pos, first);
+            for (int i = 1; i < nInts; ++i)
+            {
+                pos -= BytesPerInt;
+                magnitude[i] = Pack.LE_To_UInt32(bytes, pos);
+            }
+            Debug.Assert(pos == offset);
+
+            return magnitude;
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private static uint[] MakeMagnitudeLE(ReadOnlySpan<byte> bytes)
+        {
+            // strip leading zeros
+            int last = bytes.Length;
+            while (--last >= 0 && bytes[last] == 0)
+            {
+            }
+
+            if (last < 0)
+                return ZeroMagnitude;
+
+            int nInts = (last + BytesPerInt) / BytesPerInt;
+            Debug.Assert(nInts > 0);
+
+            uint[] magnitude = new uint[nInts];
+
+            int partial = last % BytesPerInt;
+            int first = partial + 1;
+            int pos = last - partial;
+
+            magnitude[0] = Pack.LE_To_UInt32_Low(bytes.Slice(pos, first));
+            for (int i = 1; i < nInts; ++i)
+            {
+                pos -= BytesPerInt;
+                magnitude[i] = Pack.LE_To_UInt32(bytes, pos);
+            }
+            Debug.Assert(pos == 0);
+
+            return magnitude;
+        }
+#endif
+
         public BigInteger(int sign, byte[] bytes)
-            : this(sign, bytes, 0, bytes.Length)
+            : this(sign, bytes, 0, bytes.Length, true)
+        {
+        }
+
+        public BigInteger(int sign, byte[] bytes, bool bigEndian)
+            : this(sign, bytes, 0, bytes.Length, bigEndian)
         {
         }
 
         public BigInteger(int sign, byte[] bytes, int offset, int length)
+            : this(sign, bytes, offset, length, true)
+        {
+        }
+
+        public BigInteger(int sign, byte[] bytes, int offset, int length, bool bigEndian)
         {
             if (sign < -1 || sign > 1)
                 throw new FormatException("Invalid sign value");
@@ -618,13 +768,20 @@ namespace Org.BouncyCastle.Math
             else
             {
                 // copy bytes
-                this.magnitude = MakeMagnitudeBE(bytes, offset, length);
+                this.magnitude = bigEndian
+                    ? MakeMagnitudeBE(bytes, offset, length)
+                    : MakeMagnitudeLE(bytes, offset, length);
                 this.sign = this.magnitude.Length < 1 ? 0 : sign;
             }
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public BigInteger(int sign, ReadOnlySpan<byte> bytes)
+            : this(sign, bytes, true)
+        {
+        }
+
+        public BigInteger(int sign, ReadOnlySpan<byte> bytes, bool bigEndian)
         {
             if (sign < -1 || sign > 1)
                 throw new FormatException("Invalid sign value");
@@ -637,7 +794,9 @@ namespace Org.BouncyCastle.Math
             else
             {
                 // copy bytes
-                this.magnitude = MakeMagnitudeBE(bytes);
+                this.magnitude = bigEndian
+                    ? MakeMagnitudeBE(bytes)
+                    : MakeMagnitudeLE(bytes);
                 this.sign = this.magnitude.Length < 1 ? 0 : sign;
             }
         }
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index 61d060b4e..f4d91b180 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -2747,14 +2747,9 @@ namespace Org.BouncyCastle.Math.Raw
                 ? stackalloc byte[bsLen]
                 : new byte[bsLen];
 
-            int xPos = len;
-            Span<byte> t = bs;
-            while (--xPos >= 0)
-            {
-                Pack.UInt32_To_BE(x[xPos], t);
-                t = t[4..];
-            }
-            return new BigInteger(1, bs);
+            Pack.UInt32_To_LE(x, bs);
+
+            return new BigInteger(1, bs, bigEndian: false);
         }
 #endif
 
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index 38e571cd6..d6fa87943 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -151,7 +151,7 @@ namespace Org.BouncyCastle.Security
                     Asn1OctetString privEnc = keyInfo.PrivateKeyData;
                     if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64)
                     {
-                        d = new BigInteger(1, Arrays.Reverse(privEnc.GetOctets()));
+                        d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false);
                     }
                     else
                     {
@@ -162,8 +162,8 @@ namespace Org.BouncyCastle.Security
                         }
                         else
                         {
-                            byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets());
-                            d = new BigInteger(1, dVal);
+                            byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets();
+                            d = new BigInteger(1, dVal, bigEndian: false);
                         }
                     }
                 }
@@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Security
                 }
                 else
                 {
-                    x = new BigInteger(1, Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()));
+                    x = new BigInteger(1, Asn1OctetString.GetInstance(privKey).GetOctets(), bigEndian: false);
                 }
 
                 return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
@@ -280,8 +280,7 @@ namespace Org.BouncyCastle.Security
                     Asn1OctetString privEnc = keyInfo.PrivateKeyData;
                     if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64)
                     {
-                        byte[] dVal = Arrays.Reverse(privEnc.GetOctets());
-                        d = new BigInteger(1, dVal);
+                        d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false);
                     }
                     else
                     {
@@ -292,8 +291,8 @@ namespace Org.BouncyCastle.Security
                         }
                         else
                         {
-                            byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets());
-                            d = new BigInteger(1, dVal);
+                            byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets();
+                            d = new BigInteger(1, dVal, bigEndian: false);
                         }
                     }
                 }
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index 03cabbb13..d3ecef5c7 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -203,9 +203,9 @@ namespace Org.BouncyCastle.Security
                     throw new ArgumentException("error recovering GOST3410_94 public key", e);
                 }
 
-                byte[] keyBytes = Arrays.Reverse(key.GetOctets()); // was little endian
+                byte[] keyBytes = key.GetOctets();
 
-                BigInteger y = new BigInteger(1, keyBytes);
+                BigInteger y = new BigInteger(1, keyBytes, bigEndian: false);
 
                 return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
             }