summary refs log tree commit diff
path: root/crypto/src/math/BigInteger.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/math/BigInteger.cs')
-rw-r--r--crypto/src/math/BigInteger.cs273
1 files changed, 193 insertions, 80 deletions
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs

index d84680de5..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 = MakeMagnitude(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,124 +552,210 @@ namespace Org.BouncyCastle.Math inverse[index]++; - this.magnitude = MakeMagnitude(inverse); - } - - private static uint[] MakeMagnitude(byte[] bytes) - { - return MakeMagnitude(bytes, 0, bytes.Length); + return MakeMagnitudeBE(inverse); } - private static uint[] MakeMagnitude(byte[] bytes, int offset, int length) + private static uint[] InitLE(byte[] bytes, int offset, int length, out int sign) { -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - return MakeMagnitude(bytes.AsSpan(offset, length)); -#else int end = offset + length; - // strip leading zeros - int firstSignificant; - for (firstSignificant = offset; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++) + // 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; } - if (firstSignificant >= end) - return ZeroMagnitude; + sign = -1; - int nInts = (end - firstSignificant + 3) / BytesPerInt; - int bCount = (end - firstSignificant) % BytesPerInt; - if (bCount == 0) + // strip leading sign bytes + int last = length; + while (--last >= 0 && bytes[offset + last] == byte.MaxValue) { - bCount = BytesPerInt; } - if (nInts < 1) - return ZeroMagnitude; + if (last < 0) + return One.magnitude; - uint[] mag = new uint[nInts]; + int numBytes = last + 1; - uint v = 0U; - int magnitudeIndex = 0; - for (int i = firstSignificant; i < end; ++i) +#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) { - v <<= 8; - v |= bytes[i]; - bCount--; - if (bCount <= 0) - { - mag[magnitudeIndex] = v; - magnitudeIndex++; - bCount = BytesPerInt; - v = 0U; - } + inverse[i] = (byte)~bytes[offset + i]; + } + + int index = 0; + while (inverse[index] == byte.MaxValue) + { + inverse[index++] = byte.MinValue; } - if (magnitudeIndex < mag.Length) + inverse[index]++; + + return MakeMagnitudeLE(inverse); + } + + private static uint[] MakeMagnitudeBE(byte[] bytes) + { + return MakeMagnitudeBE(bytes, 0, bytes.Length); + } + + private static uint[] MakeMagnitudeBE(byte[] bytes, int offset, int length) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return MakeMagnitudeBE(bytes.AsSpan(offset, length)); +#else + int end = offset + length; + + // strip leading zeros + int start; + for (start = offset; start < end && bytes[start] == 0; start++) { - mag[magnitudeIndex] = v; } - return mag; + int nBytes = end - start; + if (nBytes <= 0) + return ZeroMagnitude; + + int nInts = (nBytes + BytesPerInt - 1) / BytesPerInt; + Debug.Assert(nInts > 0); + + uint[] magnitude = new uint[nInts]; + + int first = ((nBytes - 1) % BytesPerInt) + 1; + magnitude[0] = Pack.BE_To_UInt32_Low(bytes, start, first); + Pack.BE_To_UInt32(bytes, start + first, magnitude, 1, nInts - 1); + + return magnitude; #endif } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - private static uint[] MakeMagnitude(ReadOnlySpan<byte> bytes) + private static uint[] MakeMagnitudeBE(ReadOnlySpan<byte> bytes) { int end = bytes.Length; // strip leading zeros - int firstSignificant; - for (firstSignificant = 0; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++) + int start; + for (start = 0; start < end && bytes[start] == 0; start++) { } - if (firstSignificant >= end) + int nBytes = end - start; + if (nBytes <= 0) return ZeroMagnitude; - int nInts = (end - firstSignificant + 3) / BytesPerInt; - int bCount = (end - firstSignificant) % BytesPerInt; - if (bCount == 0) + int nInts = (nBytes + BytesPerInt - 1) / BytesPerInt; + Debug.Assert(nInts > 0); + + uint[] magnitude = new uint[nInts]; + + int first = ((nBytes - 1) % BytesPerInt) + 1; + magnitude[0] = Pack.BE_To_UInt32_Low(bytes.Slice(start, first)); + Pack.BE_To_UInt32(bytes.Slice(start + first), magnitude.AsSpan(1)); + + return magnitude; + } +#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) { - bCount = BytesPerInt; } - if (nInts < 1) + if (last < 0) return ZeroMagnitude; - uint[] mag = new uint[nInts]; + int nInts = (last + BytesPerInt) / BytesPerInt; + Debug.Assert(nInts > 0); - uint v = 0; - int magnitudeIndex = 0; - for (int i = firstSignificant; i < end; ++i) + 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) { - v <<= 8; - v |= bytes[i]; - bCount--; - if (bCount <= 0) - { - mag[magnitudeIndex] = v; - magnitudeIndex++; - bCount = BytesPerInt; - v = 0U; - } } - if (magnitudeIndex < mag.Length) + 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) { - mag[magnitudeIndex] = v; + pos -= BytesPerInt; + magnitude[i] = Pack.LE_To_UInt32(bytes, pos); } + Debug.Assert(pos == 0); - return mag; + 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"); @@ -664,13 +768,20 @@ namespace Org.BouncyCastle.Math else { // copy bytes - this.magnitude = MakeMagnitude(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"); @@ -683,7 +794,9 @@ namespace Org.BouncyCastle.Math else { // copy bytes - this.magnitude = MakeMagnitude(bytes); + this.magnitude = bigEndian + ? MakeMagnitudeBE(bytes) + : MakeMagnitudeLE(bytes); this.sign = this.magnitude.Length < 1 ? 0 : sign; } } @@ -719,7 +832,7 @@ namespace Org.BouncyCastle.Math int xBits = BitsPerByte * nBytes - sizeInBits; b[0] &= (byte)(255U >> xBits); - this.magnitude = MakeMagnitude(b); + this.magnitude = MakeMagnitudeBE(b); this.sign = this.magnitude.Length < 1 ? 0 : 1; } @@ -766,7 +879,7 @@ namespace Org.BouncyCastle.Math // ensure the trailing bit is 1 (i.e. must be odd) b[nBytes - 1] |= 1; - this.magnitude = MakeMagnitude(b); + this.magnitude = MakeMagnitudeBE(b); this.nBits = -1; if (certainty < 1)