def hash_(self, keys: Index, salt: int = 0) -> pd.Series:
        """Hashes the given index into an integer index in the range [0, self.stride]

        Parameters
        ----------
        keys :
            The new index to hash.
        salt :
            An integer used to perturb the hash in a deterministic way.  Useful
            in dealing with collisions.

        Returns
        -------
        pd.Series
            A pandas series indexed by the given keys and whose values take on integers in
            the range [0, self.stride].  Duplicates may appear and should be dealt with
            by the calling code.
        """
        key_frame = keys.to_frame()
        new_map = pd.Series(0, index=keys)
        salt = self.convert_to_ten_digit_int(pd.Series(salt, index=keys))

        for i, column_name in enumerate(key_frame.columns):
            column = self.convert_to_ten_digit_int(key_frame[column_name])

            primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 27]
            out = pd.Series(1, index=column.index)
            for idx, p in enumerate(primes):
                # numpy will almost always overflow here, but it is equivalent to modding
                # out by 2**64.  Since it's much much larger than our map size
                # the amount of additional periodicity this introduces is pretty trivial.
                out *= np.power(p, self.digit(column, idx))
            new_map += out + salt

        return new_map % self.map_size