shamir-vault is a Rust crate that provides an implementation of Shamir's Secret Sharing algorithm, enabling secure splitting and reconstruction of secrets. This crate allows you to divide a secret into multiple shares and reconstruct it with a minimum threshold of shares, ensuring data security and redundancy.
- Split secrets into
nshares with a thresholdtrequired for reconstruction. - Robust error handling for input validation.
- Implementation using Galois Field arithmetic for security and efficiency.
- Easy-to-use API with comprehensive test coverage.
no_stdcompatible - works in embedded and WASM environments- Explicit RNG control - you provide the randomness source for better security
Add shamir-vault to your Cargo.toml dependencies:
[dependencies]
shamir-vault = "1.3.0"For no_std environments, both dependencies will automatically work without their default features.
This crate works with both rand 0.8 and 0.9. The way you instantiate the RNG differs between versions:
For rand 0.8.x:
use rand::thread_rng;
let secret = b"My Super Secret Data";
let shares = split(secret, 5, 3, &mut thread_rng()).unwrap();For rand 0.9.x:
use rand::rng;
let secret = b"My Super Secret Data";
let shares = split(secret, 5, 3, &mut rng()).unwrap();Alternatively with rand 0.9, you can also use:
use rand::thread_rng::thread_rng;
let secret = b"My Super Secret Data";
let shares = split(secret, 5, 3, &mut thread_rng()).unwrap();The split function accepts any &mut dyn RngCore, so it's compatible with any version - just use the appropriate import for your rand version.
You can split a secret into multiple shares, requiring a specified threshold for reconstruction. You must provide your own RNG instance.
use shamir_vault::{split, combine};
fn main() {
let secret = b"My Super Secret Data";
// Use rand::thread_rng() for rand 0.8, or rand::rng() for rand 0.9
let mut rng = rand::thread_rng(); // or rand::rng() for 0.9+
let shares = split(secret, 5, 3, &mut rng).expect("Failed to split secret");
println!("Generated Shares:");
for (i, share) in shares.iter().enumerate() {
println!("Share {}: {:?}", i + 1, share);
}
}Parameters:
secret: A byte array representing the secret.shares: The total number of shares to generate.threshold: The minimum number of shares required to reconstruct the secret.rng: A mutable reference to any RNG implementingRngCore.
Errors:
InvalidShareCount: If shares are not between 2 and 255.InvalidThreshold: If the threshold is not between 2 and 255.SharesLessThanThreshold: If the number of shares is less than the threshold.EmptySecret: If the secret is empty.
To recover the original secret, provide at least the threshold number of shares.
use shamir_vault::{split, combine};
fn main() {
let secret = b"My Super Secret Data";
// Use rand::thread_rng() for rand 0.8, or rand::rng() for rand 0.9
let mut rng = rand::thread_rng(); // or rand::rng() for 0.9+
let shares = split(secret, 5, 3, &mut rng).expect("Failed to split secret");
let recovered_secret = combine(&shares[0..3]).expect("Failed to reconstruct secret");
assert_eq!(secret, recovered_secret.as_slice());
println!("Recovered Secret: {:?}", String::from_utf8_lossy(&recovered_secret));
}Parameters:
shares: A slice of shares used for reconstruction.
Errors:
InconsistentShareLength: If shares have varying lengths.DuplicateShares: If there are duplicate shares.ShareCountMismatch: If the provided shares count does not match the required count.
This crate provides robust error handling with the ShamirError enum.
use shamir_vault::{split, ShamirError};
fn main() {
// Use rand::thread_rng() for rand 0.8, or rand::rng() for rand 0.9
let mut rng = rand::thread_rng(); // or rand::rng() for 0.9+
match split(b"", 5, 3, &mut rng) {
Ok(_) => println!("Secret successfully split"),
Err(ShamirError::EmptySecret) => println!("Secret cannot be empty"),
Err(e) => println!("Error: {}", e),
}
}For embedded systems or WASM, you can use any RNG that implements RngCore:
#![no_std]
extern crate alloc;
use shamir_vault::{split, combine};
use alloc::vec::Vec;
use rand_core::RngCore;
// Example with a custom RNG or hardware RNG
fn split_secret_embedded(mut rng: impl RngCore) {
let secret = b"My Super Secret Data";
let shares = split(secret, 5, 3, &mut rng).expect("Failed to split secret");
// ... use shares
}split(secret: &[u8], shares: usize, threshold: usize, rng: &mut (dyn RngCore + '_)) -> Result<Vec<Vec<u8>>, ShamirError>
Splits the given secret into a specified number of shares with a threshold for reconstruction.
Combines the provided shares to reconstruct the original secret.
InvalidShareCountInvalidThresholdSharesLessThanThresholdEmptySecretDuplicateSharesInconsistentShareLengthShareCountMismatch
- Ensure that secret shares are distributed securely to prevent unauthorized reconstruction.
- Use a sufficiently high threshold to prevent loss due to missing shares.
- Keep the number of generated shares within a reasonable limit (max 255).
- Use a cryptographically secure RNG -
rand::thread_rng()is recommended for most applications. - Control your randomness source - the explicit RNG parameter gives you full control over entropy.
The crate is optimized for performance using precomputed Galois Field tables for fast arithmetic operations. The no_std design makes it suitable for resource-constrained environments.
Unit tests are included to ensure the correctness of the implementation.
Run tests with:
cargo test- RNG Parameter Required: The
splitfunction now requires an explicit RNG parameter no_stdCompatible: Now works inno_stdenvironments- Dependency Changes:
randandthiserrornow usedefault-features = false
This project is licensed under the MIT License. See the LICENSE file for more details.
Feel free to submit issues, suggestions, or pull requests on GitHub: shamir-vault
Developed by Sabir Khan