A high-performance, memory-safe implementation of BLS12-381 digital signatures in Zig, providing both native Zig APIs and C ABI bindings for maximum interoperability.
- BLS12-381 Digital Signatures - Complete implementation of pairing-based signatures
- Signature Aggregation - Efficient batch verification of multiple signatures
- Key Aggregation - Combine multiple public keys into a single aggregate key
- Min-PK and Min-Sig Variants - Support for both signature size and public key size optimizations
- Ethereum 2.0 Compatible - Fully compliant with Ethereum consensus specifications
- Memory Safe - Written in Zig with compile-time memory safety guarantees
- Zero-Copy Operations - Optimized for minimal memory allocations
- Thread-Safe - Built-in concurrency support with thread pooling
- Memory Pooling - Intelligent buffer reuse for high-throughput scenarios
- SIMD Optimizations - Leverages BLST's assembly optimizations (x86_64 ADX support)
- Native Zig API - Idiomatic Zig interfaces with error handling
- C ABI Bindings - Full C-compatible API for language interoperability
- Async Support - Non-blocking signature operations with callbacks
- Comprehensive Testing - Extensive test suite with benchmarks
- Cross-Platform - Supports Linux, macOS, and Windows
- Zig 0.15.1+ - Download here
- Git - For cloning the repository
# Clone the repository
git clone https://github.com/zk-evm/bls12-381.git
cd bls12-381
# Build the library (static and shared)
zig build
# Build with optimizations
zig build -Doptimize=ReleaseFast
# Build portable version (no CPU-specific optimizations)
zig build -Dportable=true
# Force ADX optimizations on x86_64
zig build -Dforce-adx=true
After building, you'll find:
- Static Library:
zig-out/lib/libbls12-381.a
- Shared Library:
zig-out/lib/libbls12-381-min-pk.so
(Linux) /.dylib
(macOS) /.dll
(Windows) - Executable:
zig-out/bin/bls12-381
const std = @import("std");
const bls = @import("bls12-381");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Initialize the library
try bls.init();
defer bls.deinit();
// Generate a secret key
var secret_key = bls.SecretKey.generate();
// Derive public key
var public_key = secret_key.getPublicKey();
// Sign a message
const message = "Hello, BLS12-381!";
var signature = secret_key.sign(message);
// Verify signature
const is_valid = public_key.verify(signature, message);
std.debug.print("Signature valid: {}\n", .{is_valid});
}
const signatures = [_]*bls.Signature{ &sig1, &sig2, &sig3 };
const public_keys = [_]*bls.PublicKey{ &pk1, &pk2, &pk3 };
const messages = [_][]const u8{ "msg1", "msg2", "msg3" };
// Aggregate signatures
var agg_sig = bls.AggregateSignature.aggregate(&signatures);
// Batch verify
const is_valid = agg_sig.fastAggregateVerify(&public_keys, &messages);
#include "bls12-381.h"
int main() {
// Initialize library
if (init() != 0) {
return 1;
}
// Create signature set
SignatureSet set = {
.message = "Hello World",
.message_len = 11,
.public_key = pk_bytes,
.signature = sig_bytes
};
// Verify signature
uint32_t result = verify_signature(&set, 1, true, true);
deinit();
return result == 0 ? 0 : 1;
}
Type | Description | Size |
---|---|---|
SecretKey |
Private key for signing | 32 bytes |
PublicKey |
Public key for verification | 48 bytes (min-pk) / 96 bytes (min-sig) |
Signature |
Digital signature | 96 bytes (min-pk) / 48 bytes (min-sig) |
AggregatePublicKey |
Aggregated public keys | 48/96 bytes |
AggregateSignature |
Aggregated signatures | 96/48 bytes |
// Single signature
const signature = secret_key.sign(message);
// Sign with domain separation
const sig_with_dst = secret_key.signWithDst(message, dst);
// Single verification
const valid = public_key.verify(signature, message);
// Batch verification (faster for multiple sigs)
const valid = bls.fastAggregateVerify(public_keys, signatures, messages);
// Key generation from seed
var secret_key = SecretKey.fromSeed(seed_bytes);
// Key derivation
var child_key = secret_key.derive(derivation_path);
// Key serialization
var pk_bytes = public_key.toBytes();
var sk_bytes = secret_key.toBytes();
Operation | Throughput | Latency | Notes |
---|---|---|---|
Key Generation | 1,265,227 ops/sec | 0.8 μs | Secret key creation from random material |
Public Key Derivation | 8,072 ops/sec | 123.9 μs | SK→PK conversion |
Signing | 2,261 ops/sec | 442.3 μs | Message signing with BLS12-381 |
Verification | 660 ops/sec | 1,516.1 μs | Single signature verification |
Signature Aggregation | 68,836 ops/sec | 14.5 μs | Combining 10 signatures |
Aggregate Verification | 660 agg/sec | 1.51 ms | Batch verify 100 signatures |
Effective Batch Throughput | 66,030 sigs/sec | - | Individual sigs in batch mode |
Operation | Throughput | Latency |
---|---|---|
Public Key Compression | 13,057,728 ops/sec | 0.1 μs |
Signature Compression | 6,603,057 ops/sec | 0.2 μs |
Public Key Decompression | 55,413 ops/sec | 18.0 μs |
Benchmarks run on x86_64 Linux with Zig 0.15.1 ReleaseFast optimization and ADX support
🔑 Key Insights:
- Signature Aggregation is 100x faster than individual operations - use batch verification for high throughput
- Key generation is extremely fast due to efficient random number generation
- Verification is the bottleneck - consider caching verified signatures when possible
- Serialization is negligible cost - network/storage will be the limiting factor
- Signature Context: ~3KB
- Memory Pool Buffer: Configurable (default: 64KB)
- Thread Pool: ~8 threads (configurable)
# Run all tests
zig build test
# Run with coverage
zig build test --summary all
# Run specific test suite
zig build test --test-filter "signature_tests"
# Performance benchmarks
zig build bench # Debug benchmarks
zig build bench -Doptimize=ReleaseFast # Production benchmarks
# Individual benchmark categories
zig build bench --test-filter "benchmark_key_generation"
zig build bench --test-filter "benchmark_signing"
zig build bench --test-filter "benchmark_verification"
zig build bench --test-filter "benchmark_aggregation"
zig build bench --test-filter "benchmark_serialization"
- ✅ Core cryptographic operations
- ✅ Edge cases and error conditions
- ✅ Cross-platform compatibility
- ✅ Thread safety and concurrency
- ✅ Memory leak detection
- ✅ Performance regression tests
This library implements signatures over the BLS12-381 elliptic curve pairing, which provides:
- 128-bit security level - Equivalent to 3072-bit RSA
- Pairing-friendly - Enables signature aggregation
- Ethereum 2.0 standard - Used in Ethereum's proof-of-stake consensus
- Deterministic signatures (RFC 6979)
- Side-channel resistance - Constant-time operations where applicable
- Memory safety - Zig's compile-time guarantees prevent buffer overflows
- Input validation - All inputs are validated before processing
# Performance optimizations
zig build -Doptimize=ReleaseFast # Maximum speed
zig build -Doptimize=ReleaseSmall # Minimum size
zig build -Doptimize=ReleaseSafe # Optimized + safety checks
# Platform options
zig build -Dportable=true # Disable CPU-specific optimizations
zig build -Dforce-adx=true # Force ADX instructions (x86_64)
# Threading
zig build -Dthread-pool-size=16 # Custom thread pool size
zig build -Dsingle-threaded=true # Disable threading
// Memory pool settings
const config = bls.Config{
.memory_pool_size = 128 * 1024, // 128KB pool
.max_threads = 8, // Thread limit
.enable_batch_verify = true, // Batch verification
};
try bls.initWithConfig(config);
Platform | Status | Notes |
---|---|---|
Linux x86_64 | ✅ Full | Includes ADX optimizations |
Linux ARM64 | ✅ Full | NEON optimizations |
macOS x86_64 | ✅ Full | Intel Mac support |
macOS ARM64 | ✅ Full | Apple Silicon (M1/M2) |
Windows x86_64 | ✅ Full | MSVC and MinGW |
FreeBSD | 🧪 Beta | Community maintained |
We welcome contributions! Please see our Contributing Guidelines for details.
# Install development dependencies
zig build install-dev
# Run pre-commit hooks
zig build lint
zig build format
zig build test
# Generate documentation
zig build docs
- Follow Zig Style Guide
- Use
zig fmt
for formatting - Add tests for new features
- Update documentation as needed
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright (c) 2025 zk-evm
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
- BLST Library - High-performance BLS12-381 implementation
- Zig Programming Language - Memory-safe systems programming
- Ethereum Foundation - BLS12-381 standardization efforts
- IETF CFRG - Cryptographic standards development
- BLS Signatures Explained - Vitalik Buterin's introduction
- Zig Documentation - Official Zig language reference
- Ethereum 2.0 BLS - BLS in Ethereum 2.0 context
- Pairing-Based Cryptography - Mathematical foundations
Website • Documentation • Issues • Discussions
Made with ❤️ by zk-evm