Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Base58Encoding/Base58.Decode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private static int DecodeGenericCore<TChar>(ReadOnlySpan<TChar> encoded, Span<by
{
TChar firstChar = TChar.CreateTruncating(TAlphabet.FirstCharacter);
int leadingOnes = Base58.CountLeadingCharacters(encoded, firstChar);
int scratchSize = encoded.Length * 733 / 1000 + 1;
int scratchSize = Base58.GetTypicalDecodedLength(encoded.Length);

if (scratchSize <= MaxStackallocByte)
{
Expand Down Expand Up @@ -167,7 +167,7 @@ private static byte[] DecodeGenericToArray<TChar>(ReadOnlySpan<TChar> encoded)
return new byte[leadingOnes];
}

int scratchSize = encoded.Length * 733 / 1000 + 1;
int scratchSize = Base58.GetTypicalDecodedLength(encoded.Length);

if (scratchSize <= MaxStackallocByte)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Base58Encoding/Base58.Encode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private static string EncodeGenericToString(ReadOnlySpan<byte> data)
}

ReadOnlySpan<byte> inputSpan = data[leadingZeros..];
int size = inputSpan.Length * 137 / 100 + 1;
int size = Base58.GetMaxEncodedLength(inputSpan.Length);

if (size <= MaxStackallocByte)
{
Expand Down Expand Up @@ -117,7 +117,7 @@ private static int EncodeGenericToBytes(ReadOnlySpan<byte> data, Span<byte> dest
}

ReadOnlySpan<byte> inputSpan = data[leadingZeros..];
int size = inputSpan.Length * 137 / 100 + 1;
int size = Base58.GetMaxEncodedLength(inputSpan.Length);

if (size <= MaxStackallocByte)
{
Expand Down
19 changes: 17 additions & 2 deletions src/Base58Encoding/Base58.Length.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ public static partial class Base58
/// </summary>
/// <param name="byteCount">Length of the input data in bytes.</param>
/// <returns>Maximum number of characters/bytes written by <c>Encode</c>.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if <paramref name="byteCount"/> is negative, or so large that the encoded
/// length would exceed <see cref="int.MaxValue"/>.
/// </exception>
/// <remarks>
/// 137 = ceil(100 * log(256)/log(58)); sufficient for every length because 58^137 &gt; 2^800,
/// and 136 is not. Do not shrink it or the <c>+ 1</c>, which covers the leading digit.
/// </remarks>
public static int GetMaxEncodedLength(int byteCount)
{
if (byteCount < 0)
Expand All @@ -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;
}

/// <summary>
Expand Down Expand Up @@ -53,6 +68,6 @@ public static int GetTypicalDecodedLength(int encodedLength)
return 0;
}

return encodedLength * 733 / 1000 + 1;
return (int)((long)encodedLength * 733 / 1000 + 1);
}
}
6 changes: 6 additions & 0 deletions src/Base58Encoding/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
}