Written readme, improved documentation, added changelog and copyright
This commit is contained in:
parent
90c7382c17
commit
d6c7a6be9e
|
@ -0,0 +1,9 @@
|
||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.1.0] - 2020-01-13
|
||||||
|
### Added
|
||||||
|
- Initial version
|
|
@ -0,0 +1,12 @@
|
||||||
|
Copyrights in the Sharks project are retained by their contributors. No
|
||||||
|
copyright assignment is required to contribute to the Sharks project.
|
||||||
|
|
||||||
|
For full authorship information, see the version control history.
|
||||||
|
|
||||||
|
Except as otherwise noted (below and/or in individual files), Sharks is
|
||||||
|
licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
|
||||||
|
<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
|
||||||
|
|
||||||
|
The Sharks project includes code from the Rust project
|
||||||
|
published under these same licenses.
|
|
@ -2,7 +2,7 @@
|
||||||
name = "sharks"
|
name = "sharks"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Aitor Ruano <codearm@pm.me>"]
|
authors = ["Aitor Ruano <codearm@pm.me>"]
|
||||||
description = "Fast, secure and minimal Shamir's Secret Sharing library crate"
|
description = "Fast, smanll and secure Shamir's Secret Sharing library crate"
|
||||||
homepage = "https://github.com/c0dearm/sharks"
|
homepage = "https://github.com/c0dearm/sharks"
|
||||||
repository = "https://github.com/c0dearm/sharks"
|
repository = "https://github.com/c0dearm/sharks"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
65
README.md
65
README.md
|
@ -0,0 +1,65 @@
|
||||||
|
# Sharks
|
||||||
|
|
||||||
|
Fast, small and secure [Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing) library crate
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
- [API reference (docs.rs)](https://docs.rs/sharks)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add this to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
sharks = "0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
To get started using Sharks, see the [Rust docs](https://docs.rs/sharks)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Developer friendly
|
||||||
|
The API is simple and to the point, with minimal configuration.
|
||||||
|
|
||||||
|
### Fast and small
|
||||||
|
The code is as idiomatic and clean as possible, with minimum external dependencies.
|
||||||
|
|
||||||
|
### Secure by design
|
||||||
|
The implementation forbids the user to choose parameters that would result in an insecure application,
|
||||||
|
like generating more shares than what's allowed by the finite field length.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
Currently only finite fields with modulus up to 128 bits (12th Mersenne prime) are supported. This means:
|
||||||
|
- Only up to `2^128` shares can be generated.
|
||||||
|
- Maximum secret length is 128 bits.
|
||||||
|
|
||||||
|
This is imposed by the Rust maximum unsigned integer length, which is `u128`.
|
||||||
|
Going around this limitation would mean using crates like `num-bigint` in most of the computations, reducing performance drastically.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
This crate contains both unit and benchmark tests (as well as the examples included in the docs).
|
||||||
|
You can run them with `cargo test` and `cargo bench`.
|
||||||
|
|
||||||
|
### Benchmark results [min mean max]
|
||||||
|
|
||||||
|
| CPU | obtain_shares_iterator | step_shares_iterator | recover_secret |
|
||||||
|
| ----------------------------------------- | ------------------------------- | ------------------------------- | ------------------------------- |
|
||||||
|
| Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz | [14.023 us 14.087 us 14.146 us] | [413.19 us 414.90 us 416.60 us] | [24.978 ms 25.094 ms 25.226 ms] |
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
If you find a vulnerability, bug or would like a new feature, [open a new issue](https://github.com/c0dearm/sharks/issues/new).
|
||||||
|
|
||||||
|
To introduce your changes into the codebase, submit a Pull Request.
|
||||||
|
|
||||||
|
Many thanks!
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
Sharks is distributed under the terms of both the MIT license and the
|
||||||
|
Apache License (Version 2.0).
|
||||||
|
|
||||||
|
See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
|
||||||
|
[COPYRIGHT](COPYRIGHT) for details.
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
@ -8,15 +7,19 @@ fn secret_shares_generation(c: &mut Criterion) {
|
||||||
let shamir = SecretShares::new(1000, 128).unwrap();
|
let shamir = SecretShares::new(1000, 128).unwrap();
|
||||||
let mut iter = shamir.iter_shares(12345).unwrap();
|
let mut iter = shamir.iter_shares(12345).unwrap();
|
||||||
|
|
||||||
c.bench_function("obtain_shares_iterator", |b| b.iter(|| shamir.iter_shares(black_box(12345))));
|
c.bench_function("obtain_shares_iterator", |b| {
|
||||||
|
b.iter(|| shamir.iter_shares(black_box(12345)))
|
||||||
|
});
|
||||||
c.bench_function("step_shares_iterator", |b| b.iter(|| iter.next()));
|
c.bench_function("step_shares_iterator", |b| b.iter(|| iter.next()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secret_from_shares(c: &mut Criterion) {
|
fn secret_from_shares(c: &mut Criterion) {
|
||||||
let shamir = SecretShares::new(10, 128).unwrap();
|
let shamir = SecretShares::new(10, 128).unwrap();
|
||||||
let shares: HashMap<u128,u128> = shamir.iter_shares(12345).unwrap().take(100).collect();
|
let shares: HashMap<u128, u128> = shamir.iter_shares(12345).unwrap().take(100).collect();
|
||||||
|
|
||||||
c.bench_function("recover_secret", |b| b.iter(|| shamir.secret_from(black_box(&shares))));
|
c.bench_function("recover_secret", |b| {
|
||||||
|
b.iter(|| shamir.secret_from(black_box(&shares)))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, secret_shares_generation, secret_from_shares);
|
criterion_group!(benches, secret_shares_generation, secret_from_shares);
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -1,7 +1,20 @@
|
||||||
|
//! Fast, small and secure [Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing) library crate
|
||||||
|
//!
|
||||||
|
//! # Usage example
|
||||||
|
//! ```
|
||||||
|
//! // Configure algorithm with minimum 3 shares to recover secret and security level 12
|
||||||
|
//! let shamir = sharks::SecretShares::new(3, 12).unwrap();
|
||||||
|
//! // Generate 3 shares for the 12345 secret
|
||||||
|
//! let shares = shamir.iter_shares(12345).unwrap().take(3).collect();
|
||||||
|
//! // Recover the secret from the shares
|
||||||
|
//! let secret = shamir.secret_from(&shares).unwrap();
|
||||||
|
//! assert_eq!(secret, 12345);
|
||||||
|
//! ```
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
mod mersenne;
|
|
||||||
mod math;
|
mod math;
|
||||||
|
mod mersenne;
|
||||||
|
|
||||||
/// Generate new [Shamir's secret shares](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing) or recover secrets from them.
|
/// Generate new [Shamir's secret shares](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing) or recover secrets from them.
|
||||||
pub struct SecretShares {
|
pub struct SecretShares {
|
||||||
|
@ -10,7 +23,6 @@ pub struct SecretShares {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SecretShares {
|
impl SecretShares {
|
||||||
|
|
||||||
/// Returns a result containing a`SecretShares` instance if parameters are reasonable.
|
/// Returns a result containing a`SecretShares` instance if parameters are reasonable.
|
||||||
///
|
///
|
||||||
/// `security_level` is the index of the [Mersenne prime](https://en.wikipedia.org/wiki/Mersenne_prime) to use as the finite field prime modulo (the higher the more secure, but slower).
|
/// `security_level` is the index of the [Mersenne prime](https://en.wikipedia.org/wiki/Mersenne_prime) to use as the finite field prime modulo (the higher the more secure, but slower).
|
||||||
|
|
83
src/math.rs
83
src/math.rs
|
@ -1,46 +1,60 @@
|
||||||
|
// A module that contains necessary algorithms to compute Shamir's shares and recover secrets
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use num_bigint::{BigInt, BigUint};
|
use num_bigint::{BigInt, BigUint};
|
||||||
use num_traits::Zero;
|
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
use num_traits::Zero;
|
||||||
use rand::distributions::{Distribution, Uniform};
|
use rand::distributions::{Distribution, Uniform};
|
||||||
|
|
||||||
/// A module that contains necessary algorithms to compute Shamir's shares and recover secrets
|
// Computes `num/(num - b) mod p`, a necessary step to compute the [root of the Lagrange polynomial](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing#Computationally_efficient_approach).
|
||||||
|
// To find the modulo multiplicative inverse of `num - b` the [Extended Euclidean Algorithm](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Computation) is used.
|
||||||
/// Computes `num/(num - b) mod p`, a necessary step to compute the [root of the Lagrange polynomial](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing#Computationally_efficient_approach).
|
|
||||||
/// To find the modulo multiplicative inverse of `num - b` the [Extended Euclidean Algorithm](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Computation) is used.
|
|
||||||
fn div_diff_mod(num: &u128, b: &u128, p: u128) -> u128 {
|
fn div_diff_mod(num: &u128, b: &u128, p: u128) -> u128 {
|
||||||
let (mut m, mut x, mut inv, mut den) = (p, 0i128, 1i128, if num < b { p - (b - num) } else { num - b });
|
let (mut m, mut x, mut inv, mut den) = (
|
||||||
|
p,
|
||||||
|
0i128,
|
||||||
|
1i128,
|
||||||
|
if num < b { p - (b - num) } else { num - b },
|
||||||
|
);
|
||||||
|
|
||||||
while den > 1 {
|
while den > 1 {
|
||||||
inv -= ((den/m) as i128)*x;
|
inv -= ((den / m) as i128) * x;
|
||||||
den %= m;
|
den %= m;
|
||||||
std::mem::swap(&mut den, &mut m);
|
std::mem::swap(&mut den, &mut m);
|
||||||
std::mem::swap(&mut x, &mut inv);
|
std::mem::swap(&mut x, &mut inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = BigInt::from(inv);
|
let mut res = BigInt::from(inv);
|
||||||
if inv < 0 { res += p }
|
if inv < 0 {
|
||||||
|
res += p
|
||||||
|
}
|
||||||
|
|
||||||
(num*res % p).to_u128().unwrap()
|
(num * res % p).to_u128().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the [root of the Lagrange polynomial](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing#Computationally_efficient_approach).
|
// Finds the [root of the Lagrange polynomial](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing#Computationally_efficient_approach).
|
||||||
pub fn lagrange_root(points: &HashMap<u128, u128>, p: u128) -> u128 {
|
pub fn lagrange_root(points: &HashMap<u128, u128>, p: u128) -> u128 {
|
||||||
(points.iter().enumerate()
|
(points
|
||||||
.map(|(j, (xj, yj))|
|
.iter()
|
||||||
points.iter().enumerate().filter(|(m, _)| *m != j)
|
.enumerate()
|
||||||
.map(|(_, (xm, _))|
|
.map(|(j, (xj, yj))| {
|
||||||
div_diff_mod(xm, xj, p)
|
points
|
||||||
)
|
.iter()
|
||||||
.product::<BigUint>()*yj % p
|
.enumerate()
|
||||||
)
|
.filter(|(m, _)| *m != j)
|
||||||
.sum::<BigUint>() % p)
|
.map(|(_, (xm, _))| div_diff_mod(xm, xj, p))
|
||||||
.to_u128().unwrap()
|
.product::<BigUint>()
|
||||||
|
* yj
|
||||||
|
% p
|
||||||
|
})
|
||||||
|
.sum::<BigUint>()
|
||||||
|
% p)
|
||||||
|
.to_u128()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates `k` polynomial coefficients, being the last one `s` and the others randomly generated between `[1, p)`.
|
// Generates `k` polynomial coefficients, being the last one `s` and the others randomly generated between `[1, p)`.
|
||||||
/// Coefficient degrees go from higher to lower in the returned vector order.
|
// Coefficient degrees go from higher to lower in the returned vector order.
|
||||||
pub fn compute_coeffs(s: u128, k: usize, p: u128) -> (u128, Vec<u128>) {
|
pub fn compute_coeffs(s: u128, k: usize, p: u128) -> (u128, Vec<u128>) {
|
||||||
let mut coeffs = Vec::with_capacity(k);
|
let mut coeffs = Vec::with_capacity(k);
|
||||||
let between = Uniform::new(1, p);
|
let between = Uniform::new(1, p);
|
||||||
|
@ -54,15 +68,24 @@ pub fn compute_coeffs(s: u128, k: usize, p: u128) -> (u128, Vec<u128>) {
|
||||||
(p, coeffs)
|
(p, coeffs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a set of polynomial coefficients `coeffs` and a modulus `p`, returns an iterator that computes a `(x, f(x) mod p)` point
|
// Given a set of polynomial coefficients `coeffs` and a modulus `p`, returns an iterator that computes a `(x, f(x) mod p)` point
|
||||||
/// on each iteration. The iterator starts for `x = 1` and ends at `x = p-1`.
|
// on each iteration. The iterator starts for `x = 1` and ends at `x = p-1`.
|
||||||
pub fn get_evaluator(coeffs: Vec<u128>, p: u128) -> impl Iterator<Item = (u128, u128)> {
|
pub fn get_evaluator(coeffs: Vec<u128>, p: u128) -> impl Iterator<Item = (u128, u128)> {
|
||||||
(1..p).map(move |x| (x, coeffs.iter().fold(BigUint::zero(), |acc, c| (acc*x + c) % p).to_u128().unwrap()))
|
(1..p).map(move |x| {
|
||||||
|
(
|
||||||
|
x,
|
||||||
|
coeffs
|
||||||
|
.iter()
|
||||||
|
.fold(BigUint::zero(), |acc, c| (acc * x + c) % p)
|
||||||
|
.to_u128()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{div_diff_mod, lagrange_root, compute_coeffs, get_evaluator};
|
use super::{compute_coeffs, div_diff_mod, get_evaluator, lagrange_root};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn div_diff_mod_works() {
|
fn div_diff_mod_works() {
|
||||||
|
@ -75,12 +98,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lagrange_root_works() {
|
fn lagrange_root_works() {
|
||||||
let iter = get_evaluator(vec![3,2,1], 7);
|
let iter = get_evaluator(vec![3, 2, 1], 7);
|
||||||
let values = iter.take(3).collect();
|
let values = iter.take(3).collect();
|
||||||
let root = lagrange_root(&values, 7);
|
let root = lagrange_root(&values, 7);
|
||||||
assert_eq!(root, 1);
|
assert_eq!(root, 1);
|
||||||
|
|
||||||
let iter = get_evaluator(vec![3,2,5], 7);
|
let iter = get_evaluator(vec![3, 2, 5], 7);
|
||||||
let values = iter.take(3).collect();
|
let values = iter.take(3).collect();
|
||||||
let root = lagrange_root(&values, 7);
|
let root = lagrange_root(&values, 7);
|
||||||
assert_eq!(root, 5);
|
assert_eq!(root, 5);
|
||||||
|
@ -96,8 +119,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluator_works() {
|
fn evaluator_works() {
|
||||||
let iter = get_evaluator(vec![3,2,5], 7);
|
let iter = get_evaluator(vec![3, 2, 5], 7);
|
||||||
let values: Vec<_> = iter.take(2).collect();
|
let values: Vec<_> = iter.take(2).collect();
|
||||||
assert_eq!(values, vec![(1,3), (2,0)]);
|
assert_eq!(values, vec![(1, 3), (2, 0)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,3 @@
|
||||||
/// A table containing the exponents of found [Mersenne primes](https://en.wikipedia.org/wiki/Mersenne_prime)
|
// A table containing the exponents of found [Mersenne primes](https://en.wikipedia.org/wiki/Mersenne_prime)
|
||||||
/// To be used as finite field modulo for shares and secret recovery computation
|
// To be used as finite field modulo for shares and secret recovery computation
|
||||||
pub const EXPONENTS: [u32; 12] = [
|
pub const EXPONENTS: [u32; 12] = [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127];
|
||||||
2,
|
|
||||||
3,
|
|
||||||
5,
|
|
||||||
7,
|
|
||||||
13,
|
|
||||||
17,
|
|
||||||
19,
|
|
||||||
31,
|
|
||||||
61,
|
|
||||||
89,
|
|
||||||
107,
|
|
||||||
127
|
|
||||||
];
|
|
||||||
|
|
Loading…
Reference in New Issue