As mentioned in https://github.com/elastic/elasticsearch/pull/96216, `LuceneVerifyingIndexOutput` always copies the last chunk byte-by-byte. This might be a pretty big chunk. We should be able to copy all the bytes up to the start of the checksum in bulk (and then I guess bulk-copy the checksum too not that this matters so much).

In the same area, `LuceneVerifyingIndexOutput` is the only subclass of `VerifyingIndexOutput` and there's no need for it to be an inner class of `Store`. `VerifyingIndexInput` also doesn't need to be an inner class.
server/src/main/java/org/elasticsearch/index/store/Store.java
};
            boolean segmentsIdentical = true;
            for (Tuple<List<StoreFileMetadata>, List<StoreFileMetadata>> segmentFiles : perSegmentSourceFiles.values()) {
                final List<StoreFileMetadata> nonGenerationalFiles = segmentFiles.v1();
                final List<StoreFileMetadata> generationalFiles = segmentFiles.v2();
                if (groupComparer.test(nonGenerationalFiles)) {
                    
                    segmentsIdentical = groupComparer.test(generationalFiles) && segmentsIdentical;
                } else {
                    
                    segmentsIdentical = false;
                    allDifferent.accept(generationalFiles);
                }
            }
            if (segmentsIdentical) {
                
                groupComparer.test(perCommitSourceFiles);
            } else {
                
                allDifferent.accept(perCommitSourceFiles);
            }
            final RecoveryDiff recoveryDiff = new RecoveryDiff(
                Collections.unmodifiableList(identical),
                Collections.unmodifiableList(different),
                Collections.unmodifiableList(missing)
            );
            assert recoveryDiff.size() == fileMetadataMap.size()
                : "some files are missing: recoveryDiff is ["
                    + recoveryDiff
                    + "] comparing: ["