diff --git a/src/Base58Encoding/Base58.Decode.cs b/src/Base58Encoding/Base58.Decode.cs index 549e663..b71121f 100644 --- a/src/Base58Encoding/Base58.Decode.cs +++ b/src/Base58Encoding/Base58.Decode.cs @@ -112,7 +112,7 @@ private static int DecodeGenericCore(ReadOnlySpan encoded, Span(ReadOnlySpan encoded) return new byte[leadingOnes]; } - int scratchSize = encoded.Length * 733 / 1000 + 1; + int scratchSize = Base58.GetTypicalDecodedLength(encoded.Length); if (scratchSize <= MaxStackallocByte) { diff --git a/src/Base58Encoding/Base58.Encode.cs b/src/Base58Encoding/Base58.Encode.cs index 02e9fe8..285ba4a 100644 --- a/src/Base58Encoding/Base58.Encode.cs +++ b/src/Base58Encoding/Base58.Encode.cs @@ -72,7 +72,7 @@ private static string EncodeGenericToString(ReadOnlySpan data) } ReadOnlySpan inputSpan = data[leadingZeros..]; - int size = inputSpan.Length * 137 / 100 + 1; + int size = Base58.GetMaxEncodedLength(inputSpan.Length); if (size <= MaxStackallocByte) { @@ -117,7 +117,7 @@ private static int EncodeGenericToBytes(ReadOnlySpan data, Span dest } ReadOnlySpan inputSpan = data[leadingZeros..]; - int size = inputSpan.Length * 137 / 100 + 1; + int size = Base58.GetMaxEncodedLength(inputSpan.Length); if (size <= MaxStackallocByte) { diff --git a/src/Base58Encoding/Base58.Length.cs b/src/Base58Encoding/Base58.Length.cs index 666af08..d65cecf 100644 --- a/src/Base58Encoding/Base58.Length.cs +++ b/src/Base58Encoding/Base58.Length.cs @@ -8,6 +8,14 @@ public static partial class Base58 /// /// Length of the input data in bytes. /// Maximum number of characters/bytes written by Encode. + /// + /// Thrown if is negative, or so large that the encoded + /// length would exceed . + /// + /// + /// 137 = ceil(100 * log(256)/log(58)); sufficient for every length because 58^137 > 2^800, + /// and 136 is not. Do not shrink it or the + 1, which covers the leading digit. + /// public static int GetMaxEncodedLength(int byteCount) { if (byteCount < 0) @@ -20,7 +28,14 @@ public static int GetMaxEncodedLength(int byteCount) return 0; } - return byteCount * 138 / 100 + 1; + long maxLength = (long)byteCount * 137 / 100 + 1; + + if (maxLength > int.MaxValue) + { + ThrowHelper.ThrowInputTooLarge(nameof(byteCount)); + } + + return (int)maxLength; } /// @@ -53,6 +68,6 @@ public static int GetTypicalDecodedLength(int encodedLength) return 0; } - return encodedLength * 733 / 1000 + 1; + return (int)((long)encodedLength * 733 / 1000 + 1); } } diff --git a/src/Base58Encoding/ThrowHelper.cs b/src/Base58Encoding/ThrowHelper.cs index 3d4fb5d..d4c24e9 100644 --- a/src/Base58Encoding/ThrowHelper.cs +++ b/src/Base58Encoding/ThrowHelper.cs @@ -21,4 +21,10 @@ public static void ThrowNegativeLength(string paramName) { throw new ArgumentOutOfRangeException(paramName, "Length must be non-negative."); } + + [DoesNotReturn] + public static void ThrowInputTooLarge(string paramName) + { + throw new ArgumentOutOfRangeException(paramName, "Input is too large: the encoded length would exceed Int32.MaxValue."); + } }