Written readme, improved documentation, added changelog and copyright

This commit is contained in:
Aitor Ruano 2020-01-13 11:42:59 +01:00
parent 90c7382c17
commit d6c7a6be9e
8 changed files with 172 additions and 61 deletions

9
CHANGELOG.md Normal file
View File

@ -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

12
COPYRIGHT Normal file
View File

@ -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.

View File

@ -2,7 +2,7 @@
name = "sharks"
version = "0.1.0"
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"
repository = "https://github.com/c0dearm/sharks"
readme = "README.md"

View File

@ -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.

View File

@ -1,4 +1,3 @@
use std::collections::HashMap;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
@ -8,7 +7,9 @@ fn secret_shares_generation(c: &mut Criterion) {
let shamir = SecretShares::new(1000, 128).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()));
}
@ -16,7 +17,9 @@ fn secret_from_shares(c: &mut Criterion) {
let shamir = SecretShares::new(10, 128).unwrap();
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);

View File

@ -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;
mod mersenne;
mod math;
mod mersenne;
/// Generate new [Shamir's secret shares](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing) or recover secrets from them.
pub struct SecretShares {
@ -10,7 +23,6 @@ pub struct SecretShares {
}
impl SecretShares {
/// 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).

View File

@ -1,16 +1,21 @@
// A module that contains necessary algorithms to compute Shamir's shares and recover secrets
use std::collections::HashMap;
use num_bigint::{BigInt, BigUint};
use num_traits::Zero;
use num_traits::cast::ToPrimitive;
use num_traits::Zero;
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 {
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 {
inv -= ((den / m) as i128) * x;
@ -20,27 +25,36 @@ fn div_diff_mod(num: &u128, b: &u128, p: u128) -> u128 {
}
let mut res = BigInt::from(inv);
if inv < 0 { res += p }
if inv < 0 {
res += p
}
(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 {
(points.iter().enumerate()
.map(|(j, (xj, yj))|
points.iter().enumerate().filter(|(m, _)| *m != j)
.map(|(_, (xm, _))|
div_diff_mod(xm, xj, p)
)
.product::<BigUint>()*yj % p
)
.sum::<BigUint>() % p)
.to_u128().unwrap()
(points
.iter()
.enumerate()
.map(|(j, (xj, yj))| {
points
.iter()
.enumerate()
.filter(|(m, _)| *m != j)
.map(|(_, (xm, _))| div_diff_mod(xm, xj, p))
.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)`.
/// Coefficient degrees go from higher to lower in the returned vector order.
// 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.
pub fn compute_coeffs(s: u128, k: usize, p: u128) -> (u128, Vec<u128>) {
let mut coeffs = Vec::with_capacity(k);
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)
}
/// 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`.
// 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`.
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)]
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]
fn div_diff_mod_works() {

View File

@ -1,16 +1,3 @@
/// 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
pub const EXPONENTS: [u32; 12] = [
2,
3,
5,
7,
13,
17,
19,
31,
61,
89,
107,
127
];
// 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
pub const EXPONENTS: [u32; 12] = [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127];