Overview | Features | Disclaimer | Security | Acknowledgments | Tests | Installation | Usage | Examples | License
ShamiRS (shamir-rs) utilizes Sharmir's Secret Sharing, a cryptographic method for dividing a secret into multiple shares. In this context, the secret is represented as a polynomial in Galois Field GF(2^8)
where each share corresponds to a point on this polynomial.
- Share Generation: Each byte of the secret is assigned as the constant term of a distinct, newly created polynomial, while it's remaining coefficients are being randomly generated. Shares are then produced by evaluating these polynomials at random
x
points with each shares=(y1, y2, .., yn, x)
consisting of anx
point and its correspondingy1..yn
points being the result of every evaluation. - Secret Reconstruction: When the minimum number of shares (
threshold
) are gathered, the polynomial can be then reconstructed using Lagrange interpolation. The constant terms of these resulting polynomials would be each byte of the original secret.
A key aspect of this method is that possession of less shares than the required threshold
amount reveals no information about the secret, which substantially reduces the risk of a single point of failure.
- Proactive Refresh: Allows shares to be updated while preserving the original secret, countering perpetual leakage by preventing the accumulation of exposed shares over time. Can be enabled with the
refresh
feature flag. Highly experimental.
The library has not been subjected to a formal security audit. It should be used at your own discretion and risk. Furthermore, backward compatibility is not guaranteed and the package is intentionally not published on crates.io until and if there's a stable
release in the future.
Contributions are welcome. Users are encouraged to submit pull requests, fork, or alter the code in accordance with the terms outlined in the LICENSE.
ShamiRS places strong emphasis on security.
- CSPRNG: To maximize unpredictability in scenarios requiring randomness, the library utilizes only generators from the
rand
crate that are classified as cryptograpically secure. - Constant-Time Operations: To mitigate side-channel (timing) attacks, constant-time operations are implemented where necessary.
- No LOG/EXP Tables: Arithmetic operations in
GF(2^8)
are handled through bitwise and constant-time operations, avoiding the security risks associated with precomputedLOG/EXP
tables. (CVE-2023-25000).
The original library mentioned in the CVE report 2023-25000
has already mitigated the vulnerability, although it's crucial to exercise caution when using other libraries to verify that they do not utilize precomputed LOG/EXP
tables, which in this case are susceptible to security vulnerabilities.
The current implementation is based on the Golang library developed by Hashicorp. This version is not meant to mirror the original implementation and there's no affiliation with Hashicorp or Vault. There might be changes and added features. You can find the repository here.
Every module has it's own tests located at the end of the file, to execute them run the following command at the root of the repository:
cargo test
[dependencies]
shamirs = { git = "https://github.com/wavefnx/shamirs" }
use shamirs::{combine, split};
// The total number of shares the secret will be split into.
const PARTS: usize = 5;
// The minimum number of shares required to reconstruct the secret.
const THRESHOLD: usize = 3;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Set the bytes of the secret.
let secret: &[u8] = b"example_secret";
// 65 78 61 6d 70 6c 65 5f 73 65 63 72 65 74
// Split the secret into shares.
let shares: Vec<Vec<u8>> = split(secret, PARTS, THRESHOLD)?;
// This will generate `PARTS` amount of shares, with their corresponding coordinates.
// y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 x
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
// s1 = 67 | 7c | cf | fd | 45 | 77 | 67 | fe | db | a2 | d9 | 62 | 0b | c2 | 82
// s2 = 46 | 50 | 1f | 7b | 38 | cc | 46 | eb | 90 | dc | a1 | 5e | 37 | 48 | 45
// ...
// Combine a subset of `THRESHOLD` amount of shares to recover the secret.
let reconstructed = combine(&shares[..THRESHOLD])?;
// Verify that the recovered secret matches the original secret.
assert_eq!(secret, reconstructed);
Ok(())
}
To execute the basic example, run the following command at the root of the repository:
cargo run --example basic -q
// cargo run: Invokes the Rust package manager to run the code.
// --example basic: Specifies that you want to run the 'basic' example.
// -q: Optional flag for quiet mode, which reduces unnecessary output.
For the refresh example, run the following command:
// Note: The refresh feature must be enabled.
cargo run --example refresh --features refresh -q
This library is released under the terms of the Mozilla Public License version 2.0. See LICENSE.