s-zip
███████╗ ███████╗██╗██████╗
██╔════╝ ╚══███╔╝██║██╔══██╗
███████╗█████╗ ███╔╝ ██║██████╔╝
╚════██║╚════╝ ███╔╝ ██║██╔═══╝
███████║ ███████╗██║██║
╚══════╝ ╚══════╝╚═╝╚═╝
High-performance streaming ZIP library for Rust backends. Process multi-gigabyte archives with constant ~5MB memory usage.
Features
- 🚀 Streaming I/O - Constant memory regardless of archive size
- 🔐 AES-256 Encryption - WinZip-compatible password protection (sync + async)
- ⚡ Async/Await - Full Tokio support with encryption
- 🌩️ Cloud Storage - Direct streaming to/from S3, GCS, MinIO
- 💪 Parallel Compression - 2-4x speedup on multi-core CPUs
- 📦 ZIP64 - Files >4GB supported
- 🗜️ Multiple Codecs - DEFLATE, Zstd (3x faster compression)
Quick Start
[]
= "0.11"
# With all features
= { = "0.11", = ["async", "encryption", "async-zstd", "cloud-all"] }
Basic Usage
use ;
// Write
let mut writer = new?;
writer.start_entry?;
writer.write_data?;
writer.finish?;
// Read
let mut reader = open?;
let data = reader.read_entry_by_name?;
Async with Encryption
use AsyncStreamingZipWriter;
async
Cloud Storage (S3/GCS)
use ;
use Client;
let config = load_from_env.await;
let s3_client = new;
let writer = builder
.client
.bucket
.key
.build
.await?;
let mut zip = from_writer;
zip.start_entry.await?;
zip.write_data.await?;
zip.finish.await?;
What's New in v0.11.1
🔒 Security patch — fixes two critical vulnerabilities in the encryption feature:
- AES-CTR keystream reuse fixed — writing large files in multiple chunks previously
reused the same keystream (IV=0 on every
encrypt()call), allowing an attacker to recoverp1 XOR p2from two ciphertexts. NowAesEncryptortracks a runningbyte_offsetso every chunk uses a distinct keystream segment.
Upgrade immediately if you use encryption feature with large files (>4MB per entry).
Breaking Changes: None.
Migration from v0.11.0:
= { = "0.11.1", = ["async", "encryption"] }
What's New in v0.11.2
🛡️ Correctness & reliability patch — 7 fixes across error handling, security, and data integrity:
IncorrectPassworderror variant —AesDecryptornow returns the correctSZipError::IncorrectPasswordvariant instead of a genericInvalidFormatstring, enabling reliable pattern matching in caller code.- No-panic RNG —
generate_salt()returnsResultinstead of calling.expect(), propagating OS RNG failures gracefully instead of crashing the process. - OOM protection —
read_entry()now rejects entries withcompressed_size > 2 GiBwith a clear error instead of attempting a fatal allocation. - Encrypted streaming guard —
read_entry_streaming()now returns an explicitEncryptionErrorfor encrypted entries instead of silently returning garbled data. Useread_entry()for encrypted entries. ParallelConfigno longer panics —with_max_concurrent()returnsResultinstead of callingassert!, so invalid input is catchable.- Zip-slip protection —
ZipEntry::safe_path()strips..and leading/from entry names. Always use this when extracting to disk. - ZIP64 in parallel writes —
write_entries_parallel()now writes correct ZIP64 local headers for entries larger than 4 GB.
Breaking change: ParallelConfig::with_max_concurrent() now returns Result<Self>
instead of Self. Add .unwrap() or ? at call sites.
Migration from v0.11.1:
= { = "0.11.2", = ["async", "encryption"] }
// Before (v0.11.1)
let config = default.with_max_concurrent;
// After (v0.11.2)
let config = default.with_max_concurrent?;
// or
let config = default.with_max_concurrent.unwrap;
What's New in v0.11.1
🔐 Async Encryption Support - AsyncStreamingZipWriter now supports AES-256 encryption!
- Full encryption/decryption roundtrip (fixes critical bug from v0.10.1)
- Password-protected async ZIP creation with Tokio
- WinZip AE-2 format compliance fixed
- Compatible with 7-Zip, WinZip, WinRAR
Breaking Changes: None - fully backward compatible!
Migration from v0.10.x:
= { = "0.11", = ["async", "encryption"] }
See CHANGELOG.md for full details.
Performance
Single-threaded (1MB file):
- DEFLATE: 610 MiB/s
- Zstd: 2.0 GiB/s (3.3x faster, 11x smaller)
Parallel compression (4 cores, 400MB total):
- Sequential: 618 MB/s
- 4 threads: 1491 MB/s (2.4x speedup)
Memory: ~2-5 MB constant, even processing 2GB archives.
See BENCHMARK_RESULTS.md for detailed benchmarks.
Optional Features
| Feature | Description |
|---|---|
encryption |
AES-256 encryption (sync + async) |
async |
Tokio async/await support |
async-zstd |
Async Zstd compression |
zstd-support |
Sync Zstd compression |
cloud-s3 |
AWS S3 / MinIO streaming |
cloud-gcs |
Google Cloud Storage streaming |
cloud-all |
All cloud providers |
Examples
Encryption:
// Sync
let mut writer = new?;
writer.set_password;
writer.start_entry?;
writer.write_data?;
writer.finish?;
// Async
let mut writer = new.await?;
writer.set_password;
writer.start_entry.await?;
writer.write_data.await?;
writer.finish.await?;
Zstd Compression:
let mut writer = with_zstd?;
writer.start_entry?;
writer.write_data?;
writer.finish?;
Parallel Compression:
use ;
let entries = vec!;
let config = balanced; // 4 threads
let mut writer = new.await?;
writer.write_entries_parallel.await?;
writer.finish.await?;
In-Memory ZIP:
let buffer = Vecnew;
let cursor = new;
let mut writer = from_writer?;
writer.start_entry?;
writer.write_data?;
let cursor = writer.finish?;
let zip_bytes = cursor.into_inner;
More examples in examples/ directory.
Use Cases
- Web APIs - Generate ZIPs on-demand (Axum, Actix, Rocket)
- Cloud Pipelines - Stream directly to S3/GCS without local disk
- Data Exports - Large dataset exports with encryption
- ETL Jobs - Batch processing with bounded memory
- Microservices - Streaming responses over HTTP
Documentation
- API Docs: https://docs.rs/s-zip
- Performance: BENCHMARK_RESULTS.md
- Examples: examples/
- Changelog: CHANGELOG.md
Non-Goals
- Not a CLI tool (use
zip/unzipfor that) - Not optimized for small files (<1KB)
- Not focused on desktop/GUI usage
License
MIT License - see LICENSE
Contributing
Contributions welcome! Please feel free to submit a Pull Request.
Author
Ton That Vu - @KSD-CO