class obsidiansbox:
    def __init__(self, seed=None):
        self._forward = list(range(256))
        self._inverse = list(range(256))
        self._generate_sbox(seed)
    
    def _generate_sbox(self, seed):
        if seed is None:
            seed = 0x5a3c9f7e2d1b4a8c
        
        state = seed
        for i in range(255, 0, -1):
            state = self._prng_next(state)
            j = state % (i + 1)
            self._forward[i], self._forward[j] = self._forward[j], self._forward[i]
        
        for i in range(256):
            self._inverse[self._forward[i]] = i
    
    def _prng_next(self, state):
        state ^= (state << 13) & 0xffffffffffffffff
        state ^= (state >> 7) & 0xffffffffffffffff
        state ^= (state << 17) & 0xffffffffffffffff
        state = (state * 0x5851f42d4c957f2d + 1) & 0xffffffffffffffff
        return state
    
    def substitute(self, data):
        if isinstance(data, (bytes, bytearray)):
            return bytes([self._forward[b] for b in data])
        return self._forward[data & 0xff]
    
    def inverse_substitute(self, data):
        if isinstance(data, (bytes, bytearray)):
            return bytes([self._inverse[b] for b in data])
        return self._inverse[data & 0xff]
    
    def get_forward_table(self):
        return self._forward.copy()
    
    def get_inverse_table(self):
        return self._inverse.copy()
