A pure Zig implementation of Generalized XMSS hash-based signatures with 100% Rust compatibility. This library implements the complete GeneralizedXMSS signature scheme based on the framework from this paper, matching the hash-sig Rust implementation exactly.
- Complete GeneralizedXMSS Implementation: Full signature scheme matching Rust implementation exactly
- Identical API: Same function signatures and behavior as Rust version
- Cross-Implementation Interop: Signatures can be verified exactly between Rust and Zig
- Random Parameter Generation: Uses truly random PRF keys and parameters (matching Rust behavior)
- Top-Bottom Tree Architecture: Implements the complete Merkle tree construction with parallel processing
- Secret Key Management: Full support for activation intervals and key advancement
- Verified Compatibility: Comprehensive test suite ensures identical behavior with Rust implementation
- Proper Encapsulation: Private fields with controlled access methods, matching Rust's security model
- Poseidon2 Hash Function: KoalaBear field with Montgomery arithmetic (via zig-poseidon)
- ShakePRFtoF: SHAKE128-based PRF for key derivation with domain separation
- TargetSum Encoding: Incomparable binary encoding with randomness
- Merkle Tree Construction: Complete tree building with parallel processing support
- Hash Chain Computation: Full chain computation matching Rust implementation
- 128-bit Classical / 64-bit Quantum Security: Post-quantum security parameters
- Multiple Lifetimes: Support for 2^8, 2^18, and 2^32 signatures per keypair
- Memory Safe: Proper memory management with no leaks
- Pure Zig: Minimal dependencies, fully type-safe
- Comprehensive Testing: Full test suite with compatibility verification
- Built-in Benchmark Suite: Performance comparison and cross-compatibility testing with Rust implementation
- Installation
- Quick Start
- Architecture
- API Reference
- Testing
- Performance
- Built-in Benchmark Suite
- Contributing
- License
Add to your build.zig.zon:
.{
.name = "my_project",
.version = "0.1.0",
.dependencies = .{
.@"hash-zig" = .{
.url = "https://github.com/ch4r10t33r/hash-zig/archive/refs/tags/v2.0.0.tar.gz",
.hash = "1220...", // Will be generated by zig build
},
.@"zig-poseidon" = .{
.url = "https://github.com/blockblaz/zig-poseidon/archive/refs/heads/main.tar.gz",
.hash = "1220...", // Will be generated by zig build
},
},
}In your build.zig:
const hash_zig_dep = b.dependency("hash-zig", .{
.target = target,
.optimize = optimize,
});
const zig_poseidon_dep = b.dependency("zig_poseidon", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("hash-zig", hash_zig_dep.module("hash-zig"));
exe.root_module.addImport("poseidon", zig_poseidon_dep.module("poseidon"));git clone https://github.com/ch4r10t33r/hash-zig.git
cd hash-zig
zig build testconst std = @import("std");
const hash_zig = @import("hash-zig");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Initialize the GeneralizedXMSS signature scheme
var scheme = try hash_zig.GeneralizedXMSSSignatureScheme.init(allocator, .lifetime_2_8);
defer scheme.deinit();
// Generate a keypair with activation parameters
const keypair = try scheme.keyGen(0, 256); // activation_epoch=0, num_active_epochs=256
defer keypair.secret_key.deinit();
// Sign a message
const message = [_]u8{0x42} ** 32;
const signature = try scheme.sign(keypair.secret_key, 0, message);
defer signature.deinit();
// Verify the signature
const is_valid = try scheme.verify(&keypair.public_key, 0, message, signature);
std.debug.print("Signature valid: {}\n", .{is_valid});
}π‘ Performance Tip: For testing with larger lifetimes (2^18, 2^32), build with zig build -Doptimize=ReleaseFast for significantly better performance. Remember this is prototype software.
The main signature scheme implementation that provides:
keyGen(activation_epoch, num_active_epochs)- Generate keypairssign(secret_key, epoch, message)- Sign messagesverify(public_key, epoch, message, signature)- Verify signatures
- GeneralizedXMSSPublicKey: Contains root and parameters (private fields with controlled access)
- GeneralizedXMSSSecretKey: Contains PRF key, parameters, and tree state (private fields with controlled access)
- GeneralizedXMSSSignature: Contains Merkle path, randomness, and hashes (private fields with controlled access)
- ShakePRFtoF: SHAKE128-based PRF for key derivation
- Poseidon2: KoalaBear field hash function for tree construction
- TargetSum Encoding: Binary encoding with randomness
| Lifetime | Signatures | Use Case | Performance Note |
|---|---|---|---|
2^8 |
256 | Testing, short-term keys | Fast in both debug and optimized builds |
2^18 |
262,144 | Medium-term applications | Requires optimized build for reasonable performance |
2^32 |
4,294,967,296 | Long-term, high-volume | Requires optimized build for reasonable performance |
// Generate a keypair for lifetime 2^8
const keypair = try scheme.keyGen(0, 256);
// Access the public key (using controlled access methods)
const public_key = keypair.public_key;
const root = public_key.getRoot();
std.debug.print("Root: {}\n", .{root.value});
// Access the secret key (using controlled access methods)
const secret_key = keypair.secret_key;
const activation_interval = secret_key.getActivationInterval();
const prepared_interval = secret_key.getPreparedInterval(8);// Sign a message at epoch 0
const message = [_]u8{0x42} ** 32;
const signature = try scheme.sign(secret_key, 0, message);
// Verify the signature
const is_valid = try scheme.verify(&public_key, 0, message, signature);
// Access signature components (using controlled access methods)
const path = signature.getPath();
const rho = signature.getRho();
const hashes = signature.getHashes();// Check if key is active for a given epoch
const activation_interval = secret_key.getActivationInterval();
if (activation_interval.contains(epoch)) {
// Key is active for this epoch
}
// Check if key is prepared for a given epoch
const prepared_interval = secret_key.getPreparedInterval(log_lifetime);
if (prepared_interval.contains(epoch)) {
// Key is prepared for this epoch
}
// Advance key preparation (when needed)
try secret_key.advancePreparation(log_lifetime);# Run comprehensive test suite
zig build test
# Run only Rust compatibility tests
zig build test-rust-compat
# Run specific compatibility tests
zig build test-generalized-xmss-compat
zig build test-shake-prf-compat
zig build test-poseidon2-compat- β Unit Tests: Individual component testing
- β Integration Tests: Full signature scheme testing
- β Compatibility Tests: Rust implementation matching (100% verified)
- β Performance Tests: Benchmarking and timing
- β Memory Tests: Leak detection and management
- β Comprehensive Rust Compatibility: Full test suite covering all Rust hash-sig functionality
# Optimized build (for testing only - this is prototype software)
zig build -Doptimize=ReleaseFast
# Debug build (for development only)
zig build# Run performance benchmarks (prototype software - use at your own risk)
zig build benchmark -Doptimize=ReleaseFast
# Run key generation benchmarks
zig build benchmark-keygen -Doptimize=ReleaseFastThe standalone key-generation benchmark compares lifetime configurations while always generating 256 keys for each:
# Debug build (slower, good for development)
zig run scripts/benchmark_keygen.zig -- -i3
# Include lifetime 2^32 as well (can be slower due to larger trees)
zig run scripts/benchmark_keygen.zig -- --include-2-32 -i3
# Recommended for accurate results (prototype software)
zig run scripts/benchmark_keygen.zig -- -i5 -Doptimize=ReleaseFastWhat it measures:
- Lifetime 2^8, 2^18, and optionally 2^32
- Always generates 256 keys for apples-to-apples comparison
- Reports average/min/max time and derived keys/second
Example output (abbreviated):
hash-zig Key Generation Benchmark (Multiple Lifetimes)
=======================================================
Iterations per configuration: 3
Include 2^32 lifetime: true
Note: All tests generate 256 keys to compare lifetime performance
Benchmarking lifetime 2^8 (generating 256 keys)
... β
0.01s | ... β
0.02s | ... β
0.01s
π Results for lifetime 2^8 (256 keys):
Average time: 0.01 seconds
Generation rate: 17,000+ keys/second
Benchmarking lifetime 2^18 (generating 256 keys)
... β
0.05s | ... β
0.05s | ... β
0.05s
π Results for lifetime 2^18 (256 keys):
Average time: 0.05 seconds
Generation rate: ~5,000 keys/second
Benchmarking lifetime 2^32 (generating 256 keys)
... β
0.21s | ... β
0.21s | ... β
0.21s
π Results for lifetime 2^32 (256 keys):
Average time: 0.21 seconds
Generation rate: ~1,200 keys/second
Notes:
- 2^32 uses larger internal tree structures and is expected to be slower per key.
- Use
-Doptimize=ReleaseFastfor realistic throughput numbers.
- Key Generation (2^8): ~1.1 seconds (230 signatures/second) on M2 MacBook
- Key Generation (2^18): Use optimized build - significantly faster than debug
- Key Generation (2^32): Use optimized build - required for reasonable performance
- Signing: <1ms per signature (279,000 signatures/second)
- Verification: <1ms per signature (23,800,000 verifications/second)
- Memory Usage: Efficient with proper cleanup
Debug Build Performance (Prototype):
- Key Generation (2^8): ~14.8 seconds (17 signatures/second) - much slower
- Signing: <1ms per signature (25,900 signatures/second)
- Verification: <1ms per signature (5,900,000 verifications/second)
- Larger lifetimes: Not recommended for production use (this is prototype software)
- Always use
-Doptimize=ReleaseFastfor testing deployments - 2^8 lifetime: Suitable for testing and small-scale applications
- 2^18 lifetime: Use optimized builds, suitable for medium-term applications
- 2^32 lifetime: Use optimized builds, suitable for long-term, high-volume applications
# Build library and examples
zig build
# Build with documentation
zig build -Ddocs
# Run linting
zig build lint
# Run basic usage example (with timing)
zig build example
# Run basic usage example (optimized)
zig build example -Doptimize=ReleaseFastsrc/
βββ core/ # Core types and parameters
βββ hash/ # Hash function implementations
βββ prf/ # PRF implementations
βββ signature/ # Main signature scheme
βββ merkle/ # Merkle tree construction
βββ wots/ # Winternitz OTS
βββ utils/ # Utility functions
examples/
βββ basic_usage.zig # Basic usage example with timing
βββ test_generalized_xmss_compat.zig # Main compatibility test
βββ test_shake_prf_compatibility.zig # PRF compatibility test
βββ test_poseidon2_compatibility.zig # Hash function compatibility test
test/
βββ performance_test.zig # Performance benchmarks
βββ rust_compatibility_test.zig # Rust compatibility tests
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
zig build test - Submit a pull request
- Follow Zig naming conventions
- Add comprehensive tests for new features
- Ensure Rust compatibility is maintained
- Document public APIs
- Use proper memory management
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- hash-sig - Rust reference implementation (100% compatible)
- zig-poseidon - Poseidon2 implementation with KoalaBear field support
- Generalized XMSS Paper - Cryptographic framework
- Rust hash-sig compatibility investigation - Detailed compatibility analysis
The Zig implementation has been thoroughly tested and verified to match the Rust hash-sig implementation exactly:
- β Key Generation: Identical behavior with random parameter generation
- β Signing: Same signature generation process and output
- β Verification: Cross-compatible signature verification
- β Secret Key Management: Full support for activation intervals and advancement
- β Tree Construction: Complete Merkle tree building with parallel processing
- β Hash Chain Computation: Identical chain computation algorithm
- β PRF Implementation: ShakePRFtoF with proper domain separation
- β Poseidon2 Integration: KoalaBear field implementation via zig-poseidon
The implementation includes comprehensive tests that verify:
- Identical API behavior with Rust implementation
- Same random parameter generation patterns
- Cross-implementation signature verification
- Memory safety and proper resource management
See the compatibility investigation for detailed analysis and test results.
For questions, issues, or contributions:
- Open an issue on GitHub
- Check the analysis directory for detailed implementation notes
- Review the RUST_COMPATIBILITY.md for compatibility details
- See verification strategy for testing approach