Skip to content

Decoding big numbers fails when using custom alphabet. #32

@chrispaynter

Description

@chrispaynter

Hi,

I'm getting some invalid results with the library when decoding large numbers. I discovered this whilst I was adding some unit tests to stress test my implementation.

It occurs when I have a custom alphabet. I've not tried other alphabets.

For the purposes of setting the salt, I've used a guid and I've also set the min hash length to 15, and all tests use the same values.

I'm hoping it's just a range thing caused by this particular alphabet, but perhaps other custom alphabets can error like this.

Of course, doubt I'd ever see ids that big, but it did concern me a bit when the unit test on long.MaxValue failed, and spurred me on to find what the highest number I could decode correctly is ( it's 9549259626800016 , see below).

The hash for long.MaxValue in this case is 5jEpN7mlkn0BRvq

Passing Example

As a control on my salt and min hash length, here is a basic example where I do not customise the alphabet, and the test passes as expected:

[Fact]
public void DefaultAlphabet()
{
    var longToTest = long.MaxValue;

    string SALT = "0741cbe4-2140-4615-8b5b-93294aa52c9f";
    int MIN_HASH_LENGTH = 15;

    var hashids = new HashidsNet.Hashids(SALT, MIN_HASH_LENGTH);
    var hashed = hashids.EncodeLong(longToTest);
    var decoded = hashids.DecodeLong(hashed);

    if (decoded.Length == 0)
    {
        throw new Exception("No result returned");
    }

    Assert.Equal(longToTest, decoded[0]);
}

Failing Examples

Here is an example where I customise the alphabet, by removing all instances of i (lower and upper) as well as the number 1. In this case, no result is returned and the exception "No result returned" is thrown.

I found that the highest number I can get to pass is 9549259626800016. If I try to run the custom alphabet test with 9549259626800017, it fails with the same exception as long.MaxValue.

long.MaxValue fails 👎

[Fact]
public void HashIdsCustomSanityTest()
{
    var longToTest = long.MaxValue;

    string SALT = "0741cbe4-2140-4615-8b5b-93294aa52c9f";
    int MIN_HASH_LENGTH = 15;
    string ALPHABET = "abcdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ234567890";

    var hashids = new HashidsNet.Hashids(
        SALT, MIN_HASH_LENGTH, ALPHABET
        );
    var hashed = hashids.EncodeLong(longToTest);
    var decoded = hashids.DecodeLong(hashed);

    if (decoded.Length == 0)
    {
        throw new Exception("No result returned");
    }

    Assert.Equal(longToTest, decoded[0]);
}

9549259626800016 passes 👍

[Fact]
public void HashIdsCustomSanityTest()
{
    var longToTest = 9549259626800016;

    string SALT = "0741cbe4-2140-4615-8b5b-93294aa52c9f";
    int MIN_HASH_LENGTH = 15;
    string ALPHABET = "abcdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ234567890";

    var hashids = new HashidsNet.Hashids(
        SALT, MIN_HASH_LENGTH, ALPHABET
        );
    var hashed = hashids.EncodeLong(longToTest);
    var decoded = hashids.DecodeLong(hashed);

    if (decoded.Length == 0)
    {
        throw new Exception("No result returned");
    }

    Assert.Equal(longToTest, decoded[0]);
}

9549259626800017 fails 👎

Same exception thrown as above.

[Fact]
public void HashIdsCustomSanityTest()
{
    var longToTest = 9549259626800017;

    string SALT = "0741cbe4-2140-4615-8b5b-93294aa52c9f";
    int MIN_HASH_LENGTH = 15;
    string ALPHABET = "abcdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ234567890";

    var hashids = new HashidsNet.Hashids(
        SALT, MIN_HASH_LENGTH, ALPHABET
        );
    var hashed = hashids.EncodeLong(longToTest);
    var decoded = hashids.DecodeLong(hashed);

    if (decoded.Length == 0)
    {
        throw new Exception("No result returned");
    }

    Assert.Equal(longToTest, decoded[0]);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions