def _unfold(x: np.ndarray, kernel_size: int, padding: int) -> np.ndarray:
        """
        Extract sliding local blocks from a batched input.

        :param x: A batched input of shape `batch x channel x width x height`.
        :param kernel_size: Kernel size for computing the cost matrix.
        :param padding: Controls the amount of implicit zero-paddings on both sides for padding number of points
            for each dimension before reshaping.
        :return: Sliding local blocks.
        """
        # Do padding
        shape = tuple(np.array(x.shape[2:]) + padding * 2)
        x_pad = np.zeros(x.shape[:2] + shape)
        x_pad[:, :, padding : (shape[0] - padding), padding : (shape[1] - padding)] = x

        # Do unfolding
        res_dim_0 = x.shape[0]
        res_dim_1 = x.shape[1] * kernel_size**2
        res_dim_2 = (shape[0] - kernel_size + 1) * (shape[1] - kernel_size + 1)
        result = np.zeros((res_dim_0, res_dim_1, res_dim_2))

        for i in range(shape[0] - kernel_size + 1):
            for j in range(shape[1] - kernel_size + 1):
                patch = x_pad[:, :, i : (i + kernel_size), j : (j + kernel_size)]
                patch = patch.reshape(x.shape[0], -1)
                result[:, :, i * (shape[1] - kernel_size + 1) + j] = patch

        return result

        Extract sliding local blocks from a batched input.

        :param x: A batched input of shape `batch x channel x width x height`.
        :param kernel_size: Kernel size for computing the cost matrix.
        :param padding: Controls the amount of implicit zero-paddings on both sides for padding number of points
            for each dimension before reshaping.
        :return: Sliding local blocks.
        
art/attacks/evasion/wasserstein.py