Skip to content

Encoded hash is not being decoded (rounding bug) #23

@MarkOtter

Description

@MarkOtter

I have a reproducable bug in which certain input does create a valid hashid, but the Decode fails!

Repro code where the result is empty, instead of equal to the source:

var hashId = new Hashids(salt: "0Q6wKupsoahWD5le", alphabet: "abcdefghijklmnopqrstuvwxyz1234567890!", seps: "cfhistu");

var source = new long[] { 35887507618889472L, 30720L, Int64.MaxValue };

var encoded = hashId.EncodeLong(source);

var result = hashId.DecodeLong(encoded);

// ASSERT result == source FAILS

(Both the first (35887507618889472L) and the last (Int64.MaxValue) long values fail here)

After some investigation of my own, it turns out the root cause is the use of the Math.Pow function in the Unhash function. Due to its double nature, it is subject to rounding errors.

Proposed solution: update the Unhash function with the following code:

private long Unhash(string input, string alphabet)
{
    long number = 0;
    var alphabetLength = new System.Numerics.BigInteger(alphabet.Length);

    for (var i = 0; i < input.Length; i++)
    {
        var pos = (long)alphabet.IndexOf(input[i]);
        number += (pos * (long)System.Numerics.BigInteger.Pow(alphabetLength, input.Length - i - 1));
    }

    return number;
}

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