A production-grade Rust implementation of threshold encryption with silent (non-interactive) setup, built on Knowledge of Exponent (KZG) commitments.
You may also be interested in TrX: Encrypted Mempools in High Performance BFT Protocols.
Threshold encryption allows a message to be encrypted so it can only be decrypted when at least t out of n participants cooperate. TESS implements this using a silent setup, meaning the initial setup does not require interactive communication between participants.
- Non-interactive Setup: Silent setup eliminates the need for participant coordination during initialization
- KZG-based: Leverages Knowledge of Exponent commitments for efficient polynomial operations
- Multiple Backend Support: Choose between BLS12-381 (via blstrs or Arkworks) and BN254 (via Arkworks)
Add this to your Cargo.toml:
[dependencies]
tess = "0.1"TESS supports multiple cryptographic backends:
blst(default): blstrs backend for BLS12-381 - fastest and recommended for productionark_bls12381: Arkworks backend for BLS12-381ark_bn254: Arkworks backend for BN254
To use a different backend:
[dependencies]
tess = { version = "0.1", default-features = false, features = ["ark_bls12381"] }use rand::thread_rng;
use tess::{PairingEngine, SilentThresholdScheme, ThresholdEncryption};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
// Configuration
const PARTIES: usize = 100;
const THRESHOLD: usize = 67; // Need 67 out of 100 to decrypt
// Initialize the scheme
let scheme = SilentThresholdScheme::<PairingEngine>::new();
// 1. Generate parameters (one-time trusted setup)
let params = scheme.param_gen(&mut rng, PARTIES, THRESHOLD)?;
// 2. Generate keys for all participants
let key_material = scheme.keygen(&mut rng, PARTIES, ¶ms)?;
// 3. Encrypt a message
let message = b"Secret message that requires threshold decryption";
let ciphertext = scheme.encrypt(
&mut rng,
&key_material.aggregate_key,
¶ms,
THRESHOLD,
message,
)?;
// 4. Collect partial decryptions from THRESHOLD participants
let share_count = THRESHOLD;
let mut selector = vec![false; PARTIES];
let mut partials = Vec::new();
for i in 0..share_count {
selector[i] = true;
let partial = scheme.partial_decrypt(
&key_material.secret_keys[i],
&ciphertext,
)?;
partials.push(partial);
}
// 5. Aggregate and decrypt
let result = scheme.aggregate_decrypt(
&ciphertext,
&partials,
&selector,
&key_material.aggregate_key,
)?;
// Verify decryption
assert_eq!(result.plaintext.unwrap(), message);
Ok(())
}-
SRS Generation (
param_gen): Generate a Structured Reference String using a trusted setup. This produces KZG commitment parameters and precomputed Lagrange polynomial commitments. Internally it generates a toxic wastetauand Lagrange coefficients derived fromtau. It is critical that these parameters are not leaked. See the security considerations section. -
Key Generation (
keygen): Each participant generates a secret key share and corresponding public key with Lagrange commitment hints. Keys are generated independently without interaction. -
Key Aggregation: Public keys are combined to create an aggregate public key used for encryption.
-
Encryption (
encrypt): Messages are encrypted using the aggregate public key, producing a ciphertext with a KZG proof and a BLAKE3-encrypted payload. -
Partial Decryption (
partial_decrypt): Each participant creates a decryption share using their secret key. -
Aggregate Decryption (
aggregate_decrypt): Combine at leasttpartial decryptions to recover the plaintext using Lagrange interpolation.
┌─────────────────────────────────────────────────────────┐
│ Protocol Layer (tess/) │
│ ThresholdEncryption trait, Keys, Ciphertext, Params │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ Cryptographic Primitives (kzg/) │
│ KZG Commitments, Polynomial Operations │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ Backend Abstraction Layer (arith/) │
│ FieldElement, CurvePoint, PairingBackend traits │
└─────────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼──────┐ ┌────────▼────────┐ ┌─────▼─────┐
│ blst │ │ ark_bls12381 │ │ ark_bn254 │
│ (BLS12-381) │ │ (BLS12-381) │ │ (BN254) │
└──────────────┘ └─────────────────┘ └───────────┘
See examples/threshold_example.rs for a complete example with 2048 participants and a threshold of 1400.
Run with:
cargo run --example threshold_example --releaseuse tracing_subscriber::fmt;
// Initialize logging to see performance metrics
fmt()
.with_max_level(tracing::Level::INFO)
.with_span_events(fmt::format::FmtSpan::ENTER | fmt::format::FmtSpan::CLOSE)
.init();
// Operations will now log timing information
let params = scheme.param_gen(&mut rng, PARTIES, THRESHOLD)?;Run with:
cargo bench --bench threshold_benchThe SRS generation (param_gen) requires a trusted setup. The secret value tau used to generate the Structured Reference String must be securely discarded after generation. In production:
- Use a secure random number generator
- Ensure
tauis never stored or logged - Consider using a multi-party computation (MPC) ceremony for production deployments
- The
new_unsafe()method name indicates this responsibility
- The scheme is secure as long as fewer than
tparticipants are compromised - Choose
tbased on your threat model (typicallyt ≥ ⌈2n/3⌉for Byzantine fault tolerance) - Secret keys must be kept confidential and stored securely
- Partial decryptions should be transmitted over secure channels
- Uses BLAKE3 as a KDF to derive symmetric keys from the shared secret
- Domain separation ensures cryptographic independence
- XOR encryption with BLAKE3 in counter mode provides semantic security
TESS is secure under the following assumptions:
- The discrete logarithm problem is hard in the chosen pairing group
- The KZG assumption holds (knowledge of exponent)
- Fewer than
tparticipants collude - The trusted setup was performed honestly
- Random number generators are cryptographically secure
For detailed API documentation, run:
cargo doc --openOr visit docs.rs/tess (when published).
Run the test suite:
# Run all tests with default backend
cargo test
# Run tests with specific backend
cargo test --no-default-features --features ark_bls12381Contributions are welcome. Please submit a pull request. For major changes, open an issue first to discuss what you would like to change.
This implementation follows the research paper:
"Threshold Encryption with Silent Setup" by Sanjam Garg, Guru-Vamsi Policharla, and Mingyuan Wang ePrint Archive: https://eprint.iacr.org/2024/263
Original implementation by Guru-Vamsi Policharla: https://github.com/guruvamsi-policharla/silent-threshold-encryption
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
- ePrint Archive Paper: "Threshold Encryption with Silent Setup"
- KZG Commitments: Original KZG polynomial commitment scheme
- blstrs: High-performance BLS12-381 implementation
- Arkworks: Ecosystem of Rust libraries for zkSNARK programming
If you use TESS in your research, please cite the original paper:
@misc{garg2024threshold,
author = {Sanjam Garg and Guru-Vamsi Policharla and Mingyuan Wang},
title = {Threshold Encryption with Silent Setup},
howpublished = {Cryptology ePrint Archive, Paper 2024/263},
year = {2024},
url = {https://eprint.iacr.org/2024/263}
}