Summary
Every object warp uploads during a benchmark is byte-for-byte identical to every other object of the same size. The root cause is a one-character typo in github.com/minio/pkg/v3/rng (the upstream library warp uses for data generation): sub-keys are derived from a zero-filled local variable instead of the struct field that was just populated with random bytes. Because ResetSize resets the stream offset to 0 and (incorrectly) reuses the same zero sub-keys, every reset produces the exact same byte stream.
Warp calls ResetSize once per object via randomSrc.Object() in pkg/generator/random.go.
Warp's own code is correct. The bug is entirely in the upstream minio/pkg/v3/rng library. This report is filed here because minio/pkg has no public issue tracker.
Root Cause (in minio/pkg/v3/rng/reader.go)
func (r *Reader) init() error {
_, err := io.ReadFull(r.o.rng, r.buf[:]) // ✅ base buffer seeded correctly
...
}
// Always reset subkeys.
var tmp [32]byte // ❌ local variable, zero-initialized
_, err := io.ReadFull(r.o.rng, r.tmp[:]) // ✅ fills r.tmp (struct field) correctly
...
r.subxor[1] = binary.LittleEndian.Uint64(tmp[8:16]) // ❌ always 0
r.subxor[2] = binary.LittleEndian.Uint64(tmp[16:24]) // ❌ always 0
r.subxor[3] = binary.LittleEndian.Uint64(tmp[24:32]) // ❌ always 0
r.offset = 0
return nil
}
Random bytes are correctly read into r.tmp (struct field), but r.subxor is derived from a separate uninitialized local tmp — always zeros.
The fix is four characters: change tmp[ → r.tmp[ on lines 87–90.
r.subxor[0] = binary.LittleEndian.Uint64(r.tmp[:8])
r.subxor[1] = binary.LittleEndian.Uint64(r.tmp[8:16])
r.subxor[2] = binary.LittleEndian.Uint64(r.tmp[16:24])
r.subxor[3] = binary.LittleEndian.Uint64(r.tmp[24:32])
Reproduction
A minimal test that demonstrates the bug in minio/pkg v3.6.1:
func TestResetSizeProducesUniqueOutput(t *testing.T) {
const size = 64 << 20 // 64 MiB
r, _ := rng.NewReader(rng.WithSize(size))
out1 := make([]byte, size)
io.ReadFull(r, out1)
r.ResetSize(size)
out2 := make([]byte, size)
io.ReadFull(r, out2)
if bytes.Equal(out1, out2) {
t.Fatal("ResetSize produced identical output: subxor keys are not being randomized")
}
}
This test fails — out1 and out2 are byte-for-byte identical.
Impact Measurement
Generated two 10 GB files using the warp generator (one per run), then analyzed them:
Compression (zstd -3 and -5) — both files:
Data is correctly incompressible — the XOR scrambling looks uniform to any compressor.
| Input |
Compressed |
Ratio |
| 10,737,418,240 B |
10,737,664,018 B |
1.000023× (0% compression) |
Block-level deduplication at 4 KB granularity:
| Metric |
Result |
| Total 4 KB blocks |
2,621,440 |
| Unique blocks |
16,384 (= exactly one 64 MiB write chunk) |
| Duplicate blocks |
2,605,056 |
| Dedup savings |
99.375% |
Chunk-level (64 MiB = one warp object):
Every chunk across 10 GB has the same MD5 hash — 160 objects, 1 unique content.
Practical consequence
Any storage system with block-level deduplication reduces a warp-generated 10 GB dataset to 64 MB on disk. Benchmarks run against such systems will report:
- Artificially high write throughput (dedup hit on every block after the first object)
- Artificially low storage consumption
- Zero meaningful data for evaluating random-data performance
Environment
github.com/minio/pkg v3.6.1
github.com/minio/warp (current master, Apr 2026)
- Go 1.26.1, linux/amd64
- Intel Xeon Platinum 8280L @ 2.70GHz
Summary
Every object warp uploads during a benchmark is byte-for-byte identical to every other object of the same size. The root cause is a one-character typo in
github.com/minio/pkg/v3/rng(the upstream library warp uses for data generation): sub-keys are derived from a zero-filled local variable instead of the struct field that was just populated with random bytes. BecauseResetSizeresets the stream offset to 0 and (incorrectly) reuses the same zero sub-keys, every reset produces the exact same byte stream.Warp calls
ResetSizeonce per object viarandomSrc.Object()inpkg/generator/random.go.Warp's own code is correct. The bug is entirely in the upstream
minio/pkg/v3/rnglibrary. This report is filed here becauseminio/pkghas no public issue tracker.Root Cause (in minio/pkg/v3/rng/reader.go)
Random bytes are correctly read into
r.tmp(struct field), butr.subxoris derived from a separate uninitialized localtmp— always zeros.The fix is four characters: change
tmp[→r.tmp[on lines 87–90.Reproduction
A minimal test that demonstrates the bug in minio/pkg v3.6.1:
This test fails —
out1andout2are byte-for-byte identical.Impact Measurement
Generated two 10 GB files using the warp generator (one per run), then analyzed them:
Compression (zstd -3 and -5) — both files:
Data is correctly incompressible — the XOR scrambling looks uniform to any compressor.
Block-level deduplication at 4 KB granularity:
Chunk-level (64 MiB = one warp object):
Every chunk across 10 GB has the same MD5 hash — 160 objects, 1 unique content.
Practical consequence
Any storage system with block-level deduplication reduces a warp-generated 10 GB dataset to 64 MB on disk. Benchmarks run against such systems will report:
Environment
github.com/minio/pkg v3.6.1github.com/minio/warp(current master, Apr 2026)