diff options
-rw-r--r-- | crypto/src/math/BigInteger.cs | 116 | ||||
-rw-r--r-- | crypto/src/util/BigIntegers.cs | 70 |
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(); } } } |