OK, you could try to use Linear Congruential Generator, which has some interesting properties - with good choice of constants it will cover whole range [0...2n) once without repetition before it hits its period. Thus, it is basically equivalent to sampling without replacement.
Code for n=64, if you need exactly 63, I could dig out set of constant, just ask.
Python 3.9.1, Win10 x64
import numpy as np
class LCG(object):
    UZERO: np.uint64 = np.uint64(0)
    UONE : np.uint64 = np.uint64(1)
    def __init__(self, seed: np.uint64, a: np.uint64, c: np.uint64) -> None:
        self._seed: np.uint64 = np.uint64(seed)
        self._a   : np.uint64 = np.uint64(a)
        self._c   : np.uint64 = np.uint64(c)
    def next(self) -> np.uint64:
        self._seed = self._a * self._seed + self._c
        return self._seed
    def seed(self) -> np.uint64:
        return self._seed
    def set_seed(self, seed: np.uint64) -> np.uint64:
        self._seed = seed
    def skip(self, ns: np.int64) -> None:
        """
        Signed argument - skip forward as well as backward
        The algorithm here to determine the parameters used to skip ahead is
        described in the paper F. Brown, "Random Number Generation with Arbitrary Stride,"
        Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in
        O(log2(N)) operations instead of O(N). It computes parameters
        A and C which can then be used to find x_N = A*x_0 + C mod 2^M.
        """
        nskip: np.uint64 = np.uint64(ns)
        a: np.uint64 = self._a
        c: np.uint64 = self._c
        a_next: np.uint64 = LCG.UONE
        c_next: np.uint64 = LCG.UZERO
        while nskip > LCG.UZERO:
            if (nskip & LCG.UONE) != LCG.UZERO:
                a_next = a_next * a
                c_next = c_next * a + c
            c = (a + LCG.UONE) * c
            a = a * a
            nskip = nskip >> LCG.UONE
        self._seed = a_next * self._seed + c_next
#%%
np.seterr(over='ignore')
seed = np.uint64(1)
rng64 = LCG(seed, np.uint64(6364136223846793005), np.uint64(1))
print(rng64.next())
print(rng64.next())
print(rng64.next())
#%%
rng64.skip(-3) # back by 3
print(rng64.next())
print(rng64.next())
print(rng64.next())
rng64.skip(-3) # back by 3
rng64.skip(2) # forward by 2
print(rng64.next())