├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── benches ├── resources │ └── 1KB.txt ├── shared.rs ├── ss1.rs ├── sss.rs ├── thss.rs └── wrapped_secrets.rs ├── build.rs ├── fuzz ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── fuzz_targets │ ├── ss1_1.rs │ ├── sss_1.rs │ ├── thss_1.rs │ └── wrapped_secrets_1.rs ├── protobuf ├── .gitignore ├── Makefile ├── dss │ ├── metadata.proto │ ├── secret.proto │ └── share.proto ├── version.proto └── wrapped │ ├── secret.proto │ └── share.proto ├── rust-toolchain ├── src ├── dss │ ├── format.rs │ ├── metadata.rs │ ├── mod.rs │ ├── random.rs │ ├── ss1 │ │ ├── mod.rs │ │ ├── scheme.rs │ │ ├── serialize.rs │ │ └── share.rs │ ├── thss │ │ ├── encode.rs │ │ ├── mod.rs │ │ ├── scheme.rs │ │ ├── serialize.rs │ │ └── share.rs │ └── utils.rs ├── errors.rs ├── gf256.rs ├── lagrange.rs ├── lib.rs ├── poly.rs ├── proto │ ├── dss │ │ ├── metadata.rs │ │ ├── mod.rs │ │ ├── secret.rs │ │ └── share.rs │ ├── mod.rs │ ├── version.rs │ └── wrapped │ │ ├── mod.rs │ │ ├── secret.rs │ │ └── share.rs ├── share │ ├── mod.rs │ └── validation.rs ├── sss │ ├── encode.rs │ ├── format.rs │ ├── mod.rs │ ├── scheme.rs │ └── share.rs ├── vol_hash.rs └── wrapped_secrets │ ├── mod.rs │ └── scheme.rs └── tests ├── fixtures └── gf256 │ ├── .gitignore │ ├── Makefile │ ├── common.sage │ ├── gf256_add.sage │ ├── gf256_add.txt.gz │ ├── gf256_div.sage │ ├── gf256_div.txt.gz │ ├── gf256_mul.sage │ ├── gf256_mul.txt.gz │ ├── gf256_pow.sage │ ├── gf256_pow.txt.gz │ ├── gf256_sub.sage │ └── gf256_sub.txt.gz ├── generation_errors.rs ├── randomized_tests.rs ├── recovery_errors.rs ├── ss1_recovery_errors.rs ├── test_vectors.rs ├── thss_generation_errors.rs └── thss_recovery_errors.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # Will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | # Swap files 9 | *~ 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo # https://docs.travis-ci.com/user/caching/#Rust-Cargo-cache 3 | 4 | rust: 5 | - stable 6 | - beta 7 | 8 | matrix: 9 | # Since this item is allowed to fail, don't wait for it's result to mark the 10 | # build complete. 11 | fast_finish: true 12 | allow_failures: 13 | - env: NAME='nightly' 14 | - env: NAME='kcov' 15 | include: 16 | - env: NAME='nightly' 17 | rust: nightly 18 | - env: NAME='rustfmt' 19 | rust: nightly 20 | before_script: 21 | - rustup component add rustfmt-preview 22 | script: 23 | - cargo fmt --all -- --write-mode=diff 24 | - env: NAME='kcov' 25 | sudo: required # travis-ci/travis-ci#9061 26 | before_script: 27 | - cargo install cargo-update || echo "cargo-update already installed" 28 | - cargo install cargo-kcov || echo "cargo-kcov already installed" 29 | - cargo install-update -a 30 | script: 31 | - cargo kcov --print-install-kcov-sh | sh 32 | - cargo update # Creates `Cargo.lock` needed by next command 33 | - cargo kcov --verbose --features dss --coveralls -- --verify --exclude-pattern=/.cargo,/usr/lib,src/proto 34 | addons: 35 | apt: 36 | packages: 37 | - libcurl4-openssl-dev 38 | - libdw-dev 39 | - binutils-dev 40 | - libiberty-dev 41 | - zlib1g-dev 42 | 43 | env: 44 | global: 45 | - RUSTFLAGS="-C link-dead-code" 46 | 47 | script: 48 | - cargo build --verbose --all-features 49 | - cargo test --verbose --all-features 50 | - cargo doc --verbose --all-features 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | ## [Unreleased](https://github.com/SpinResearch/RustySecrets/compare/v0.2.2...master) 5 | 6 | * Add EditorConfig configuration file ([17a9c14](https://github.com/SpinResearch/RustySecrets/commit/17a9c14)) 7 | * Add ErrorKind::ShareParsingInvalidShareThreshold ([55b7c78](https://github.com/SpinResearch/RustySecrets/commit/55b7c78)) 8 | * Add rust-toolchain file ([2ed5bfb](https://github.com/SpinResearch/RustySecrets/commit/2ed5bfb)) 9 | * Add support for custom RNGs in SSS and WrappedSecrets (#64) ([f83ef1b](https://github.com/SpinResearch/RustySecrets/commit/f83ef1b)), closes [#64](https://github.com/SpinResearch/RustySecrets/issues/64) 10 | * Change signatures of share validation fns ([840f5cc](https://github.com/SpinResearch/RustySecrets/commit/840f5cc)) 11 | * Ensure there is at least one point in QuickCheck tests ([b477d3d](https://github.com/SpinResearch/RustySecrets/commit/b477d3d)) 12 | * Fix arg order missing shares validation ([fd74534](https://github.com/SpinResearch/RustySecrets/commit/fd74534)) 13 | * Fix wrong validation of threshold ([06033f1](https://github.com/SpinResearch/RustySecrets/commit/06033f1)) 14 | * Initial barycentric Langrange interpolation ([e767f28](https://github.com/SpinResearch/RustySecrets/commit/e767f28)) 15 | * Minor improvement to validation ([71064a6](https://github.com/SpinResearch/RustySecrets/commit/71064a6)) 16 | * MissingShares should take `u8` for `required` arg ([cb13a9b](https://github.com/SpinResearch/RustySecrets/commit/cb13a9b)) 17 | * More specific validation error when share thresholds mismatch ([df091b0](https://github.com/SpinResearch/RustySecrets/commit/df091b0)) 18 | * Remove `DuplicateShareData` error and validation ([cdcf012](https://github.com/SpinResearch/RustySecrets/commit/cdcf012)) 19 | * Remove `ShareIdentifierTooBig` error and validation ([ed867ba](https://github.com/SpinResearch/RustySecrets/commit/ed867ba)) 20 | * Rustfmt updates + refactor Travis configuration (#60) ([c25f661](https://github.com/SpinResearch/RustySecrets/commit/c25f661)), closes [#60](https://github.com/SpinResearch/RustySecrets/issues/60) 21 | * Simplify share threshold and secret length consistency validation ([88743ca](https://github.com/SpinResearch/RustySecrets/commit/88743ca)) 22 | * Simplify threshold consistency validation ([5b35c69](https://github.com/SpinResearch/RustySecrets/commit/5b35c69)) 23 | * Standardize validation var identifier on ([c437775](https://github.com/SpinResearch/RustySecrets/commit/c437775)) 24 | * Update rand to ^0.4.2 ([e34f45d](https://github.com/SpinResearch/RustySecrets/commit/e34f45d)) 25 | * Use barycentric Lagrange interpolation in all cases. ([36dc14e](https://github.com/SpinResearch/RustySecrets/commit/36dc14e)) 26 | * Use Horner's method for evaluating polynomials ([73e45bf](https://github.com/SpinResearch/RustySecrets/commit/73e45bf)) 27 | * Validate shares have the same data length ([a6046dd](https://github.com/SpinResearch/RustySecrets/commit/a6046dd)) 28 | * Validation consistency between format & validation modules ([3f215cd](https://github.com/SpinResearch/RustySecrets/commit/3f215cd)) 29 | 30 | ## [v0.2.2](https://github.com/SpinResearch/RustySecrets/compare/v0.2.1...v0.2.2) (2018-05-17) 31 | 32 | ## Changed 33 | 34 | - Pin protobuf to >=1.4 && <1.6. Fixes #67. 35 | 36 | ## [v0.2.1](https://github.com/SpinResearch/RustySecrets/compare/v0.1.0...v0.2.1) (2018-03-08) 37 | 38 | ## Fixed 39 | 40 | - Fix bug where threshold did not set deg of secret polynomial (@nvesely) 41 | 42 | ## Added 43 | 44 | - Implement {Add, Div, Mul, Sub}Assign for Gf256 (@nvesely) 45 | 46 | ## [v0.1.0](https://github.com/SpinResearch/RustySecrets/compare/0.0.2...v0.1.0) (2018-02-13) 47 | 48 | ### Added 49 | 50 | - Preliminary implementation of deterministic secret sharing (under feature `dss`). 51 | **WARNING:** This feature has not yet been audited, and should be considered pre-alpha. 52 | 53 | ### Changed 54 | 55 | - `sss::generate_shares` has been renamed to `sss::split_secret`. 56 | - `wrapped_secrets::generate_shares` has been renamed to `wrapped_secrets::split_secret`. 57 | - New share format which supports versioning. 58 | - Use `error-chain` instead of custom error struct. 59 | - Errors related to a particular share now contain the share number. 60 | - MIME type for wrapped share is now optional. 61 | - Updated dependencies. 62 | 63 | ## [v0.0.2](https://github.com/SpinResearch/RustySecrets/releases/tag/0.0.2) (2016-04-06) 64 | 65 | > Initial (alpha) release 66 | 67 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty_secrets" 3 | version = "0.2.3-pre" 4 | authors = [ 5 | "Frederic Jacobs ", 6 | "Romain Ruetschi ", 7 | "Dylan Bourgeois ", 8 | "Noah Vesely ", 9 | "sellibitze" 10 | ] 11 | description = "Implementation of threshold Shamir's secret sharing in the Rust programming language." 12 | homepage = "https://github.com/freedomofpress/RustySecrets" 13 | license = "BSD-3-Clause" 14 | readme = "README.md" 15 | build = "build.rs" 16 | 17 | exclude = ["Cargo.lock"] 18 | 19 | [badges] 20 | travis-ci = { repository = "SpinResearch/RustySecrets", branch = "master" } 21 | coveralls = { repository = "SpinResearch/RustySecrets", branch = "master", service = "github" } 22 | 23 | [features] 24 | default = [] 25 | dss = [] 26 | 27 | [dependencies] 28 | base64 = "0.9.0" 29 | rand = "^0.4.2" 30 | ring = "^0.12" 31 | merkle_sigs = "^1.4" 32 | protobuf = ">= 1.4, < 1.6" 33 | 34 | [dependencies.error-chain] 35 | version = "0.11.0" 36 | default-features = false 37 | 38 | [dev-dependencies] 39 | itertools = "^0.7" 40 | quickcheck = "^0.4" 41 | flate2 = "^0.2" 42 | rand = "^0.4.2" 43 | 44 | [profile.bench] 45 | opt-level = 3 46 | debug = false 47 | rpath = false 48 | lto = true 49 | debug-assertions = false 50 | codegen-units = 1 51 | 52 | [profile.release] 53 | opt-level = 3 54 | debug = false 55 | rpath = false 56 | lto = true 57 | debug-assertions = false 58 | codegen-units = 1 59 | 60 | [package.metadata.release] 61 | sign-commit = true 62 | upload-doc = true 63 | doc-branch = "gh-pages" 64 | pre-release-commit-message = "Release version {{version}}." 65 | pro-release-commit-message = "Start next development iteration {{version}}." 66 | tag-prefix = "v" 67 | tag-message = "Release version {{version}}." 68 | doc-commit-message = "Update documentation." 69 | dev-version-ext = "pre" 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016-2018, Spin Research 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | doc: 2 | rm -rf docs/ 3 | cargo doc --no-deps 4 | mv target/doc docs/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rusty Secrets 2 | 3 | [![Build Status](https://travis-ci.org/SpinResearch/RustySecrets.svg?branch=master)](https://travis-ci.org/SpinResearch/RustySecrets) 4 | [![Coverage Status](https://coveralls.io/repos/github/SpinResearch/RustySecrets/badge.svg?branch=master)](https://coveralls.io/github/SpinResearch/RustySecrets?branch=master) 5 | [![Crates.io](https://img.shields.io/crates/v/rusty_secrets.svg)](https://crates.io/crates/rusty_secrets) 6 | [![LICENSE](https://img.shields.io/crates/l/rusty_secrets.svg)](https://github.com/SpinResearch/RustySecrets/blob/master/LICENSE) 7 | 8 | > Rusty Secrets is an implementation of a threshold [Shamir's secret sharing scheme](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing). 9 | 10 | [**Documentation (latest)**](https://docs.rs/rusty_secrets/) 11 | [**Documentation (master)**](http://spinresearch.github.io/RustySecrets/rusty_secrets/index.html) 12 | 13 | ## Design goals 14 | 15 | The main use for this library is to split a secret of an arbitrary length in *n* different shares and *k*-out-of-*n* shares are required to recover it. The dealer is assumed to be honest (and competent). We further assume that our adversary will only be able to compromise at most *k-1* shares. Shares are kept offline. 16 | 17 | A typical use case for this library would be splitting an encryption key to a TrueCrypt-like volume. 18 | 19 | ## Implementation 20 | 21 | ### Structure of the shares 22 | 23 | ``` 24 | 2-1-LiTyeXwEP71IUA 25 | ^ ^ ^^^^^^^^^^^^^^ 26 | K N D 27 | ``` 28 | 29 | A share is built out of three parts separated with a dash: K-N-D. 30 | 31 | - K specifies the number of shares necessary to recover the secret. 32 | - N is the identifier of the share and varies between 1 and *n* where *n* is the total number of generated shares. 33 | - The D part is a Base64 encoding of a `ShareData` protobuf containing information about the share, and if signed, the signature. 34 | 35 | ### Signatures 36 | 37 | There are a few issues with regular Shamir's secret sharing that we wanted to address: 38 | 39 | - a share can be corrupted or incorrectly entered. 40 | - a malicious share holder can modify the secret that would be recovered by modifying his share. 41 | - a user has multiple shares from different secret shares and he doesn't know which one belongs to a specific instance. 42 | 43 | All of these issues would result in a corrupted secret being outputted and the program, that wouldn't even know that the secret got corrupted, wouldn't be able to give any actionable information. 44 | 45 | We addressed this by signing the shares by the dealer and encoding the public key into each share. After the generation of the shares, the dealer erases both the secret and the private signing key used to sign the shares. When recovering the secret, the program verifies that public keys and if some shares do not have the same public key, or a valid signature of that public key, signals the issue to the user with a helpful message. 46 | 47 | Signing shares is optional and the usefulness of signing the shares depends on the use case. Since we're using hash-based signatures (using SHA-512 Merkle signing), there is a large overhead from using signatures. 48 | 49 | ## Bug Reporting 50 | 51 | Please report bugs either as pull requests or as issues in [the issue 52 | tracker](https://github.com/SpinResearch/RustySecrets/issues). *RustySecrets* has a 53 | **full disclosure** vulnerability policy. **Please do NOT attempt to report 54 | any security vulnerability in this code privately to anybody.** 55 | 56 | ## License 57 | 58 | RustySecrets is distributed under the BSD 3-Clause license. See the [LICENSE](LICENSE) file for more information. 59 | 60 | ## Vocabulary 61 | 62 | - Dealer: Entity that will perform key splitting from a master secret 63 | - Shares: Part of the split secret distributed 64 | 65 | ## Credits 66 | 67 | Rusty Secrets was forked off [sellibitze's secretshare.](https://github.com/sellibitze/secretshare) 68 | -------------------------------------------------------------------------------- /benches/resources/1KB.txt: -------------------------------------------------------------------------------- 1 | Privacy isn't about something to hide. Privacy is about something to protect. That's who you are. That's what you believe in, that's who you want to become. Privacy is the right to the self. Privacy is what gives you the ability to share with the world who you are, on your own terms, for them to understand what you're trying to be. And to protect for yourself the parts of you that you're not sure about, that you're still experimenting with. If we don't have privacy, what we're losing is the ability to make mistakes. We're losing the ability to be ourselves. Privacy is the fountainhead of all other rights. Freedom of speech doesn't have a lot of meaning if you can't have a quiet space. . . . to decide what it is that you actually wanna say. Freedom of religion doesn't mean that if you can't figure out what you actually believe without being influenced by the criticisms and sort of outside direction and peer pressure of others. And it goes on and on and on. But privacy is baked into our language, our core concepts of government and self in every way . . . without privacy, you won't have anything for yourself. So when people say that to me, I say back arguing that you don't have privacy because you have nothing to hide is like arguing that you don't care about free speech because you have nothing to say. 2 | -------------------------------------------------------------------------------- /benches/shared.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | pub fn secret_1kb() -> &'static [u8] { 4 | include_bytes!("resources/1KB.txt") 5 | } 6 | -------------------------------------------------------------------------------- /benches/ss1.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | #![feature(test)] 3 | #![cfg(feature = "dss")] 4 | 5 | extern crate rusty_secrets; 6 | extern crate test; 7 | 8 | mod shared; 9 | 10 | mod ss1 { 11 | 12 | use rusty_secrets::dss::ss1; 13 | use shared; 14 | use test::{black_box, Bencher}; 15 | 16 | macro_rules! bench_generate { 17 | ($name:ident, $k:expr, $n:expr, $secret:ident) => { 18 | #[bench] 19 | fn $name(b: &mut Bencher) { 20 | let secret = shared::$secret(); 21 | 22 | b.iter(move || { 23 | let shares = ss1::split_secret( 24 | $k, 25 | $n, 26 | &secret, 27 | ss1::Reproducibility::reproducible(), 28 | &None, 29 | ).unwrap(); 30 | black_box(shares); 31 | }); 32 | } 33 | }; 34 | } 35 | 36 | macro_rules! bench_recover { 37 | ($name:ident, $k:expr, $n:expr, $secret:ident) => { 38 | #[bench] 39 | fn $name(b: &mut Bencher) { 40 | let secret = shared::$secret(); 41 | let all_shares = 42 | ss1::split_secret($k, $n, &secret, ss1::Reproducibility::reproducible(), &None) 43 | .unwrap(); 44 | let shares = &all_shares.into_iter().take($k).collect::>().clone(); 45 | 46 | b.iter(|| { 47 | let result = ss1::recover_secret(&shares.to_vec()).unwrap(); 48 | black_box(result); 49 | }); 50 | } 51 | }; 52 | } 53 | 54 | bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb); 55 | bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb); 56 | 57 | bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb); 58 | bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /benches/sss.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | #![feature(test)] 3 | 4 | extern crate rusty_secrets; 5 | extern crate test; 6 | 7 | mod shared; 8 | 9 | mod sss { 10 | 11 | use rusty_secrets::sss; 12 | use shared; 13 | use test::{black_box, Bencher}; 14 | 15 | macro_rules! bench_generate { 16 | ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => { 17 | #[bench] 18 | fn $name(b: &mut Bencher) { 19 | let secret = shared::$secret(); 20 | 21 | b.iter(move || { 22 | let shares = sss::split_secret($k, $n, secret, $signed).unwrap(); 23 | black_box(shares); 24 | }); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! bench_recover { 30 | ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => { 31 | #[bench] 32 | fn $name(b: &mut Bencher) { 33 | let secret = shared::$secret(); 34 | let all_shares = sss::split_secret($k, $n, &secret, $signed).unwrap(); 35 | let shares = all_shares.into_iter().take($k).collect::>(); 36 | 37 | b.iter(|| { 38 | let result = sss::recover_secret(&shares, $signed).unwrap(); 39 | black_box(result); 40 | }); 41 | } 42 | }; 43 | } 44 | 45 | bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb, false); 46 | bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb, false); 47 | 48 | bench_generate!(generate_1kb_3_5_signed, 3, 5, secret_1kb, true); 49 | bench_recover!(recover_1kb_3_5_signed, 3, 5, secret_1kb, true); 50 | 51 | bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb, false); 52 | bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb, false); 53 | 54 | bench_generate!(generate_1kb_10_25_signed, 10, 25, secret_1kb, true); 55 | bench_recover!(recover_1kb_10_25_signed, 10, 25, secret_1kb, true); 56 | 57 | } 58 | -------------------------------------------------------------------------------- /benches/thss.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | #![feature(test)] 3 | #![cfg(feature = "dss")] 4 | 5 | extern crate rusty_secrets; 6 | extern crate test; 7 | 8 | mod shared; 9 | 10 | mod thss { 11 | 12 | use rusty_secrets::dss::thss; 13 | use shared; 14 | use test::{black_box, Bencher}; 15 | 16 | macro_rules! bench_generate { 17 | ($name:ident, $k:expr, $n:expr, $secret:ident) => { 18 | #[bench] 19 | fn $name(b: &mut Bencher) { 20 | let secret = shared::$secret(); 21 | 22 | b.iter(move || { 23 | let shares = thss::split_secret($k, $n, &secret, &None).unwrap(); 24 | black_box(shares); 25 | }); 26 | } 27 | }; 28 | } 29 | 30 | macro_rules! bench_recover { 31 | ($name:ident, $k:expr, $n:expr, $secret:ident) => { 32 | #[bench] 33 | fn $name(b: &mut Bencher) { 34 | let secret = shared::$secret(); 35 | let all_shares = thss::split_secret($k, $n, &secret, &None).unwrap(); 36 | let shares = &all_shares.into_iter().take($k).collect::>().clone(); 37 | 38 | b.iter(|| { 39 | let result = thss::recover_secret(&shares.to_vec()).unwrap(); 40 | black_box(result); 41 | }); 42 | } 43 | }; 44 | } 45 | 46 | bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb); 47 | bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb); 48 | 49 | bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb); 50 | bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /benches/wrapped_secrets.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | #![feature(test)] 3 | 4 | extern crate rusty_secrets; 5 | extern crate test; 6 | 7 | mod shared; 8 | 9 | mod wrapped_secrets { 10 | 11 | use rusty_secrets::wrapped_secrets; 12 | use shared; 13 | use test::{black_box, Bencher}; 14 | 15 | macro_rules! bench_generate { 16 | ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => { 17 | #[bench] 18 | fn $name(b: &mut Bencher) { 19 | let secret = shared::$secret(); 20 | 21 | b.iter(move || { 22 | let shares = 23 | wrapped_secrets::split_secret($k, $n, secret, None, $signed).unwrap(); 24 | black_box(shares); 25 | }); 26 | } 27 | }; 28 | } 29 | 30 | macro_rules! bench_recover { 31 | ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => { 32 | #[bench] 33 | fn $name(b: &mut Bencher) { 34 | let secret = shared::$secret(); 35 | let all_shares = 36 | wrapped_secrets::split_secret($k, $n, &secret, None, $signed).unwrap(); 37 | let shares = all_shares.into_iter().take($k).collect::>(); 38 | 39 | b.iter(|| { 40 | let result = wrapped_secrets::recover_secret(&shares, $signed).unwrap(); 41 | black_box(result); 42 | }); 43 | } 44 | }; 45 | } 46 | 47 | bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb, false); 48 | bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb, false); 49 | 50 | bench_generate!(generate_1kb_3_5_signed, 3, 5, secret_1kb, true); 51 | bench_recover!(recover_1kb_3_5_signed, 3, 5, secret_1kb, true); 52 | 53 | bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb, false); 54 | bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb, false); 55 | 56 | bench_generate!(generate_1kb_10_25_signed, 10, 25, secret_1kb, true); 57 | bench_recover!(recover_1kb_10_25_signed, 10, 25, secret_1kb, true); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fmt; 3 | use std::fs::File; 4 | use std::io::Write; 5 | use std::num::Wrapping; 6 | use std::path::Path; 7 | 8 | const POLY: u8 = 0x1D; 9 | 10 | /// replicates the least significant bit to every other bit 11 | #[inline] 12 | fn mask(bit: u8) -> u8 { 13 | (Wrapping(0u8) - Wrapping(bit & 1)).0 14 | } 15 | 16 | /// multiplies a polynomial with x and returns the residual 17 | /// of the polynomial division with POLY as divisor 18 | #[inline] 19 | fn xtimes(poly: u8) -> u8 { 20 | (poly << 1) ^ (mask(poly >> 7) & POLY) 21 | } 22 | 23 | struct Tables { 24 | exp: [u8; 256], 25 | log: [u8; 256], 26 | } 27 | 28 | fn generate_tables(mut file: &File) { 29 | let mut tabs = Tables { 30 | exp: [0; 256], 31 | log: [0; 256], 32 | }; 33 | 34 | let mut tmp = 1; 35 | for power in 0..255usize { 36 | tabs.exp[power] = tmp; 37 | tabs.log[tmp as usize] = power as u8; 38 | tmp = xtimes(tmp); 39 | } 40 | tabs.exp[255] = 1; 41 | 42 | match write!(file, "{}", tabs) { 43 | Ok(()) => {} 44 | Err(_) => panic!("Could not format the table. Aborting build."), 45 | }; 46 | } 47 | 48 | fn farray(array: [u8; 256], f: &mut fmt::Formatter) -> fmt::Result { 49 | for (index, value) in array.into_iter().enumerate() { 50 | try!(write!(f, "{}", value)); 51 | if index != array.len() - 1 { 52 | try!(write!(f, ",")); 53 | } 54 | } 55 | Ok(()) 56 | } 57 | 58 | impl fmt::Display for Tables { 59 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 60 | try!(write!(f, "Tables {{\n")); 61 | try!(write!(f, " exp: [")); 62 | try!(farray(self.exp, f)); 63 | try!(write!(f, "],\n")); 64 | try!(write!(f, " log: [")); 65 | try!(farray(self.log, f)); 66 | try!(write!(f, "]\n")); 67 | write!(f, "}};") 68 | } 69 | } 70 | 71 | #[allow(unused_must_use)] 72 | fn main() { 73 | let out_dir = env::var("OUT_DIR").unwrap(); 74 | let dest = Path::new(&out_dir).join("nothinghardcoded.rs"); 75 | 76 | let mut f = File::create(&dest).unwrap(); 77 | 78 | write!( 79 | f, 80 | "pub struct Tables {{ \ 81 | pub exp: [u8; 256], \ 82 | pub log: [u8; 256] \ 83 | }} \ 84 | \ 85 | pub static TABLES: Tables = " 86 | ); 87 | 88 | generate_tables(&f); 89 | } 90 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "rusty_secrets-fuzz" 3 | version = "0.0.1" 4 | dependencies = [ 5 | "arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "libfuzzer-sys 0.1.0 (git+https://github.com/rust-fuzz/libfuzzer-sys.git)", 7 | "rusty_secrets 0.0.3", 8 | ] 9 | 10 | [[package]] 11 | name = "arbitrary" 12 | version = "0.1.0" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | 15 | [[package]] 16 | name = "bitflags" 17 | version = "0.7.0" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | 20 | [[package]] 21 | name = "block-buffer" 22 | version = "0.2.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "byte-tools" 31 | version = "0.2.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | 34 | [[package]] 35 | name = "coco" 36 | version = "0.1.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | dependencies = [ 39 | "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 41 | ] 42 | 43 | [[package]] 44 | name = "conv" 45 | version = "0.3.3" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "custom_derive" 53 | version = "0.1.7" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | 56 | [[package]] 57 | name = "digest" 58 | version = "0.6.2" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | dependencies = [ 61 | "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "either" 66 | version = "1.1.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | 69 | [[package]] 70 | name = "error-chain" 71 | version = "0.11.0-rc.2" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | 74 | [[package]] 75 | name = "futures" 76 | version = "0.1.14" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | 79 | [[package]] 80 | name = "gcc" 81 | version = "0.3.53" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | 84 | [[package]] 85 | name = "generic-array" 86 | version = "0.8.2" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 91 | ] 92 | 93 | [[package]] 94 | name = "lamport_sigs" 95 | version = "0.3.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | dependencies = [ 98 | "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", 99 | "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 100 | ] 101 | 102 | [[package]] 103 | name = "lazy_static" 104 | version = "0.2.8" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | 107 | [[package]] 108 | name = "libc" 109 | version = "0.2.29" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | 112 | [[package]] 113 | name = "libfuzzer-sys" 114 | version = "0.1.0" 115 | source = "git+https://github.com/rust-fuzz/libfuzzer-sys.git#67f73995f183099b2c8a736bc95b07d8b5903afe" 116 | dependencies = [ 117 | "arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", 119 | ] 120 | 121 | [[package]] 122 | name = "magenta" 123 | version = "0.1.1" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | dependencies = [ 126 | "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 127 | "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 128 | ] 129 | 130 | [[package]] 131 | name = "magenta-sys" 132 | version = "0.1.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | dependencies = [ 135 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 136 | ] 137 | 138 | [[package]] 139 | name = "merkle" 140 | version = "1.3.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | dependencies = [ 143 | "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 145 | ] 146 | 147 | [[package]] 148 | name = "merkle_sigs" 149 | version = "1.2.1" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 154 | "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 155 | ] 156 | 157 | [[package]] 158 | name = "nodrop" 159 | version = "0.1.9" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | dependencies = [ 162 | "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", 163 | ] 164 | 165 | [[package]] 166 | name = "num_cpus" 167 | version = "1.6.2" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | dependencies = [ 170 | "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", 171 | ] 172 | 173 | [[package]] 174 | name = "odds" 175 | version = "0.2.25" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | 178 | [[package]] 179 | name = "protobuf" 180 | version = "1.4.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | 183 | [[package]] 184 | name = "rand" 185 | version = "0.3.16" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | dependencies = [ 188 | "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", 189 | "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 190 | ] 191 | 192 | [[package]] 193 | name = "rayon" 194 | version = "0.7.1" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | dependencies = [ 197 | "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 198 | ] 199 | 200 | [[package]] 201 | name = "rayon-core" 202 | version = "1.2.1" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | dependencies = [ 205 | "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 206 | "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 207 | "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 208 | "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", 209 | "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 210 | "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", 211 | ] 212 | 213 | [[package]] 214 | name = "ring" 215 | version = "0.11.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | dependencies = [ 218 | "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", 219 | "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", 221 | "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 222 | "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 223 | ] 224 | 225 | [[package]] 226 | name = "rustc-serialize" 227 | version = "0.3.24" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | 230 | [[package]] 231 | name = "rusty_secrets" 232 | version = "0.0.3" 233 | dependencies = [ 234 | "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 235 | "error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)", 236 | "merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 237 | "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 238 | "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", 239 | "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 240 | "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", 241 | "sha3 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 242 | ] 243 | 244 | [[package]] 245 | name = "scopeguard" 246 | version = "0.3.2" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | 249 | [[package]] 250 | name = "sha3" 251 | version = "0.6.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | dependencies = [ 254 | "block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 255 | "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 256 | "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 257 | "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 258 | ] 259 | 260 | [[package]] 261 | name = "typenum" 262 | version = "1.9.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | 265 | [[package]] 266 | name = "untrusted" 267 | version = "0.5.0" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | 270 | [metadata] 271 | "checksum arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baa5f4eaa3a3603a0d83861560ab55dfa6c8dd094b05604e5d006b41ffaeb1d3" 272 | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 273 | "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" 274 | "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 275 | "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" 276 | "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" 277 | "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" 278 | "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" 279 | "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" 280 | "checksum error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38d3a55d9a7a456748f2a3912c0941a5d9a68006eb15b3c3c9836b8420dc102d" 281 | "checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" 282 | "checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" 283 | "checksum generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6181b378c58e5aacf4d3e17836737465cb2857750b53f6b46672a3509f2a8d9d" 284 | "checksum lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2169eee511fb4b2af1d9581f74d9503b5a86e4dbfa52ca1f5ee0d1193bf1d913" 285 | "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" 286 | "checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" 287 | "checksum libfuzzer-sys 0.1.0 (git+https://github.com/rust-fuzz/libfuzzer-sys.git)" = "" 288 | "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" 289 | "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" 290 | "checksum merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "204bbb6953e7cc6c2cec3f63e108f0d61311a3dab33d33582b1f6f4d4ae6f992" 291 | "checksum merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b446a57d9a060a9db764b6c6bd44bf79e46c512733ed9b6c23206e74394d3255" 292 | "checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" 293 | "checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" 294 | "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" 295 | "checksum protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "568a15e4d572d9a5e63ae3a55f84328c984842887db179b40b4cc6a608bac6a4" 296 | "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" 297 | "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" 298 | "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" 299 | "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" 300 | "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 301 | "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" 302 | "checksum sha3 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26405905b6a56a94c60109cfda62610507ac14a65be531f5767dec5c5a8dd6a0" 303 | "checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd" 304 | "checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673" 305 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "rusty_secrets-fuzz" 4 | version = "0.0.1" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | arbitrary = "0.1.0" 13 | 14 | [dependencies.rusty_secrets] 15 | path = ".." 16 | [dependencies.libfuzzer-sys] 17 | git = "https://github.com/rust-fuzz/libfuzzer-sys.git" 18 | 19 | # Prevent this from interfering with workspaces 20 | [workspace] 21 | members = ["."] 22 | 23 | [[bin]] 24 | name = "ss1_1" 25 | path = "fuzz_targets/ss1_1.rs" 26 | 27 | [[bin]] 28 | name = "thss_1" 29 | path = "fuzz_targets/thss_1.rs" 30 | 31 | [[bin]] 32 | name = "sss_1" 33 | path = "fuzz_targets/sss_1.rs" 34 | 35 | [[bin]] 36 | name = "wrapped_secrets_1" 37 | path = "fuzz_targets/wrapped_secrets_1.rs" 38 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/ss1_1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate rusty_secrets; 5 | extern crate arbitrary; 6 | 7 | use rusty_secrets::dss::ss1::*; 8 | use arbitrary::{RingBuffer, Unstructured}; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // --- 12 | if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { 13 | let mut kn = vec![0; 2]; 14 | buffer.fill_buffer(&mut kn).unwrap(); 15 | 16 | let k = kn[0]; 17 | let n = kn[1]; 18 | 19 | split_secret(k, n, &data, Reproducibility::reproducible(), &None) 20 | .and_then(|ss| recover_secret(&ss)) 21 | .map(|_| ()) 22 | .unwrap_or(()) 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/sss_1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | extern crate arbitrary; 3 | #[macro_use] 4 | extern crate libfuzzer_sys; 5 | extern crate rusty_secrets; 6 | 7 | use rusty_secrets::sss; 8 | use arbitrary::{RingBuffer, Unstructured}; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // --- 12 | if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { 13 | let mut kn = vec![0; 2]; 14 | buffer.fill_buffer(&mut kn).unwrap(); 15 | 16 | let k = kn[0]; 17 | let n = kn[1]; 18 | 19 | sss::split_secret(k, n, &data, false) 20 | .map_err(|err| err.into()) 21 | .and_then(|ss| sss::recover_secret(&ss, false)) 22 | .map(|_| ()) 23 | .unwrap_or(()) 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/thss_1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate rusty_secrets; 5 | extern crate arbitrary; 6 | 7 | use rusty_secrets::dss::thss::*; 8 | use arbitrary::{RingBuffer, Unstructured}; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // --- 12 | if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { 13 | let mut kn = vec![0; 2]; 14 | buffer.fill_buffer(&mut kn).unwrap(); 15 | 16 | let k = kn[0]; 17 | let n = kn[1]; 18 | 19 | split_secret(k, n, &data, &None) 20 | .and_then(|ss| recover_secret(&ss)) 21 | .map(|_| ()) 22 | .unwrap_or(()) 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/wrapped_secrets_1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | extern crate arbitrary; 3 | #[macro_use] 4 | extern crate libfuzzer_sys; 5 | extern crate rusty_secrets; 6 | 7 | use rusty_secrets::wrapped_secrets; 8 | use arbitrary::{RingBuffer, Unstructured}; 9 | 10 | fuzz_target!(|data: &[u8]| { 11 | // --- 12 | if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { 13 | let mut kn = vec![0; 2]; 14 | buffer.fill_buffer(&mut kn).unwrap(); 15 | 16 | let k = kn[0]; 17 | let n = kn[1]; 18 | 19 | wrapped_secrets::split_secret(k, n, &data, false) 20 | .map_err(|err| err.into()) 21 | .and_then(|ss| wrapped_secrets::recover_secret(&ss, false)) 22 | .map(|_| ()) 23 | .unwrap_or(()) 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /protobuf/.gitignore: -------------------------------------------------------------------------------- 1 | _out/ 2 | -------------------------------------------------------------------------------- /protobuf/Makefile: -------------------------------------------------------------------------------- 1 | SHELL = bash 2 | 3 | PROTOC := protoc 4 | 5 | DEST_DIR := ../src/proto 6 | 7 | BASE_PROTOS := $(wildcard *.proto) 8 | BASE_RUSTS := $(addprefix $(DEST_DIR)/, $(BASE_PROTOS:.proto=.rs)) 9 | 10 | DSS_PROTOS := $(wildcard dss/*.proto) 11 | DSS_RUSTS := $(addprefix $(DEST_DIR)/, $(DSS_PROTOS:.proto=.rs)) 12 | 13 | WRAPPED_PROTOS := $(wildcard wrapped/*.proto) 14 | WRAPPED_RUSTS := $(addprefix $(DEST_DIR)/, $(WRAPPED_PROTOS:.proto=.rs)) 15 | 16 | OUT_DIR := _out 17 | 18 | .PHONY: all base wrapped dss clean 19 | 20 | all: base wrapped dss 21 | 22 | base: $(BASE_RUSTS) 23 | 24 | wrapped: $(WRAPPED_RUSTS) 25 | 26 | dss: $(DSS_RUSTS) 27 | 28 | $(DEST_DIR)/%.rs: %.proto 29 | @echo -n "Processing '$<'..." 30 | @$(RM) -r $(OUT_DIR) 31 | @mkdir -p $(OUT_DIR) 32 | @$(PROTOC) --rust_out $(OUT_DIR) $< 33 | @echo " Done." 34 | @echo -n "Moving generated file to '$(dir $@)'..." 35 | @mkdir -p $(dir $@) 36 | @mv $(OUT_DIR)/*.rs $(dir $@) 37 | @echo " Done." 38 | 39 | clean: 40 | $(RM) $(BASE_RUSTS) 41 | $(RM) $(WRAPPED_RUSTS) 42 | $(RM) $(DSS_RUSTS) 43 | -------------------------------------------------------------------------------- /protobuf/dss/metadata.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package dss; 4 | 5 | message MetaDataProto { 6 | map tags = 1; 7 | } 8 | -------------------------------------------------------------------------------- /protobuf/dss/secret.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "version.proto"; 4 | import "dss/metadata.proto"; 5 | 6 | message SecretProto { 7 | VersionProto version = 1; 8 | bytes secret = 2; 9 | dss.MetaDataProto meta_data = 3; 10 | } 11 | -------------------------------------------------------------------------------- /protobuf/dss/share.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package dss; 4 | 5 | import "dss/metadata.proto"; 6 | 7 | message ShareProto { 8 | uint32 id = 1; 9 | uint32 threshold = 2; 10 | uint32 shares_count = 3; 11 | bytes data = 4; 12 | bytes hash = 5; 13 | dss.MetaDataProto meta_data = 6; 14 | } 15 | -------------------------------------------------------------------------------- /protobuf/version.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | 4 | enum VersionProto { 5 | INITIAL_RELEASE = 0; 6 | } 7 | -------------------------------------------------------------------------------- /protobuf/wrapped/secret.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package wrapped; 4 | 5 | import "version.proto"; 6 | 7 | message SecretProto { 8 | VersionProto version = 1; 9 | bytes secret = 2; 10 | string mime_type = 3; 11 | } 12 | -------------------------------------------------------------------------------- /protobuf/wrapped/share.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package wrapped; 4 | 5 | message ShareProto { 6 | bytes shamir_data = 1; 7 | repeated bytes signature = 2; 8 | bytes proof = 3; 9 | } 10 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | 1.24.1 2 | -------------------------------------------------------------------------------- /src/dss/format.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use base64; 4 | use protobuf::{self, Message}; 5 | 6 | use errors::*; 7 | use proto::dss::ShareProto; 8 | 9 | const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; 10 | 11 | pub(crate) fn format_share_protobuf(share: &ShareProto) -> String { 12 | let bytes = share.write_to_bytes().unwrap(); 13 | let base64_data = base64::encode_config(&bytes, BASE64_CONFIG); 14 | format!("{}-{}-{}", share.threshold, share.id, base64_data) 15 | } 16 | 17 | pub(crate) fn parse_share_protobuf(raw: &str) -> Result { 18 | let (threshold, id, base64_data) = parse_raw_share(raw)?; 19 | 20 | let data = base64::decode_config(&base64_data, BASE64_CONFIG).chain_err(|| { 21 | ErrorKind::ShareParsingError("Base64 decoding of data block failed".to_string()) 22 | })?; 23 | 24 | let share_proto = protobuf::parse_from_bytes::(data.as_slice()).map_err(|e| { 25 | ErrorKind::ShareParsingError(format!( 26 | "Protobuf decoding of data block failed with error: {} .", 27 | e.description() 28 | )) 29 | })?; 30 | 31 | if threshold != share_proto.threshold { 32 | bail! { 33 | ErrorKind::ShareParsingError( 34 | format!( 35 | "Incompatible thresholds between decoded Protobuf provided \ 36 | (k={}) and raw share (k={})", share_proto.threshold, threshold 37 | ) 38 | )} 39 | } 40 | 41 | if id != share_proto.id { 42 | bail! { 43 | ErrorKind::ShareParsingError( 44 | format!( 45 | "Incompatible ids between decoded Protobuf provided \ 46 | (i={}) and raw share (i={})", share_proto.id, id 47 | ) 48 | )} 49 | } 50 | 51 | Ok(share_proto) 52 | } 53 | 54 | fn parse_raw_share(raw: &str) -> Result<(u32, u32, String)> { 55 | let parts: Vec<_> = raw.trim().split('-').collect(); 56 | 57 | if parts.len() != 3 { 58 | bail! { 59 | ErrorKind::ShareParsingError( 60 | format!( 61 | "Expected 3 parts separated by a minus sign. Found {}.", 62 | raw 63 | ), 64 | ) 65 | }; 66 | } 67 | 68 | let mut iter = parts.into_iter(); 69 | let k = iter.next().unwrap().parse::()?; 70 | let i = iter.next().unwrap().parse::()?; 71 | let data = iter.next().unwrap(); 72 | Ok((k, i, data.to_string())) 73 | } 74 | -------------------------------------------------------------------------------- /src/dss/metadata.rs: -------------------------------------------------------------------------------- 1 | use ring::digest; 2 | use std::collections::BTreeMap; 3 | 4 | /// A share's public metadata. 5 | #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] 6 | pub struct MetaData { 7 | /// The tags associated with the share 8 | pub tags: BTreeMap, 9 | } 10 | 11 | impl MetaData { 12 | /// Construct a new MetaData struct. 13 | pub fn new() -> Self { 14 | MetaData { 15 | tags: BTreeMap::new(), 16 | } 17 | } 18 | 19 | /// Construct a new MetaData struct, holding the given tags 20 | pub fn with_tags(tags: BTreeMap) -> Self { 21 | Self { tags } 22 | } 23 | 24 | pub(crate) fn hash_into(&self, ctx: &mut digest::Context) { 25 | for (tag, value) in &self.tags { 26 | ctx.update(tag.as_bytes()); 27 | ctx.update(b":"); 28 | ctx.update(value.as_bytes()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/dss/mod.rs: -------------------------------------------------------------------------------- 1 | //! Defines two different deterministic sharing schemes, ThSS and SS1. 2 | //! 3 | //! # Deterministic secret sharing 4 | //! 5 | //! TODO: Doc 6 | //! 7 | //! # Schemes 8 | //! 9 | //! The two schemes differ by the security properties that they satisfy. 10 | //! The following table summarizes which properties are satisfied by each scheme. 11 | //! The definitions of the properties can be found under the 'Security properties' section. 12 | //! 13 | //! **Scheme / Property** | **Basic** | **Priv1** | **Priv2** | **Auth1** | **Auth2** | **ErrDet** | **Repro** | 14 | //! :--------------------:|:---------:|:---------:|:---------:|:---------:|:---------:|:----------:|:---------:| 15 | //! **ThSS** | Yes | Yes | No | No | No | Yes | No | 16 | //! **SS1** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | 17 | //! 18 | //! # Security properties 19 | //! 20 | //! **Property** | **Description** 21 | //! :-----------:|----------------|---------------- 22 | //! **Basic** | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. 23 | //! **Priv1** | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. 24 | //! **Priv2** | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. 25 | //! **Auth1** | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. 26 | //! **Auth2** | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. 27 | //! **ErrDet** | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. 28 | //! **Repro** | Share reproducible: The scheme can produce shares in a deterministic way. 29 | 30 | pub mod ss1; 31 | pub mod thss; 32 | 33 | mod metadata; 34 | 35 | mod format; 36 | mod random; 37 | mod utils; 38 | 39 | /// Define the access structure used to deal and recover the shares. 40 | /// 41 | /// For example, if one wants to deal 10 shares, and require 7 of them to 42 | /// recover the secret, one would express it as: 43 | /// 44 | /// ```rust 45 | /// # use rusty_secrets::dss::AccessStructure; 46 | /// AccessStructure { 47 | /// threshold: 7, 48 | /// shares_count: 10, 49 | /// }; 50 | /// ``` 51 | #[derive(Copy, Clone, Debug)] 52 | pub struct AccessStructure { 53 | /// The minimum amount of shares required to recover the secret. 54 | pub threshold: u8, 55 | 56 | /// The total number of shares generated when splitting up the secret. 57 | /// Always greater than or equal to `threshold`. 58 | pub shares_count: u8, 59 | } 60 | -------------------------------------------------------------------------------- /src/dss/random.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | 3 | use errors::*; 4 | 5 | use ring::error::Unspecified; 6 | use ring::rand::SecureRandom; 7 | 8 | /// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. 9 | /// Moreover, given the current performances, it is almost unpractical to run 10 | /// the sharing scheme on message larger than that. 11 | pub(crate) const MAX_MESSAGE_SIZE: usize = std::usize::MAX / (std::u8::MAX - 1) as usize; 12 | /// Minimum allowed message size in bytes 13 | pub(crate) static MIN_MESSAGE_SIZE: usize = 1; 14 | 15 | /// Returns the number of random bytes to read from the secure random number generator. 16 | /// As defined in section 3.1 of the 'New Directions in Secret Sharing' paper. 17 | pub(crate) fn random_bytes_count(threshold: u8, message_size: usize) -> usize { 18 | assert!(threshold >= MIN_THRESHOLD); 19 | assert!(message_size >= MIN_MESSAGE_SIZE); 20 | assert!(message_size <= MAX_MESSAGE_SIZE); 21 | 22 | (threshold as usize - 1) * message_size 23 | } 24 | 25 | /// Attempts to read `count` random bytes from the given secure random generator. 26 | pub(crate) fn random_bytes(random: &SecureRandom, count: usize) -> Result> { 27 | if count == 0 { 28 | return Ok(Vec::new()); 29 | } 30 | 31 | let mut rl = vec![0; count]; 32 | random 33 | .fill(&mut rl) 34 | .chain_err(|| ErrorKind::CannotGenerateRandomNumbers)?; 35 | 36 | Ok(rl) 37 | } 38 | 39 | /// An implementation of SecureRandom that fills the output slice with the slice in `src`. 40 | /// The length of `src` must be larger than any slice that we attempt to fill. 41 | pub(crate) struct FixedRandom { 42 | src: Vec, 43 | } 44 | 45 | impl FixedRandom { 46 | /// Create a new fixed random generator. 47 | /// The length of `src` must be larger than any slice that we attempt to fill. 48 | pub(crate) fn new(src: Vec) -> Self { 49 | if src.is_empty() { 50 | panic!("The source slice of FixedRandom cannot be empty!"); 51 | } 52 | FixedRandom { src } 53 | } 54 | } 55 | 56 | impl SecureRandom for FixedRandom { 57 | fn fill(&self, dst: &mut [u8]) -> std::result::Result<(), Unspecified> { 58 | if dst.len() > self.src.len() { 59 | return Err(Unspecified); 60 | } 61 | 62 | let len = dst.len(); 63 | dst.copy_from_slice(&self.src[0..len]); 64 | Ok(()) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/dss/ss1/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implements the `SS1` deterministic threshold secret sharing scheme. 2 | //! 3 | //! This scheme is implemented as the *T2 transform* over the ThSS threshold sharing scheme. 4 | //! found in the `rusty_secrets::dss::thss` module. 5 | //! 6 | //! # Security properties 7 | //! 8 | //! This scheme satisfies the following security properties: 9 | //! 10 | //! **Property** | **Satisifed?** | **Description** 11 | //! -------------|----------------|---------------- 12 | //! **Basic** | Yes | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. 13 | //! **Priv1** | Yes | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. 14 | //! **Priv2** | Yes | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. 15 | //! **Auth1** | Yes | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. 16 | //! **Auth2** | Yes | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. 17 | //! **ErrDet** | Yes | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. 18 | //! **Repro** | Yes | Share reproducible: The scheme can produce shares in a deterministic way. 19 | //! 20 | //! # References 21 | //! 22 | //! - *New Directions in Secret Sharing* (TODO: Full reference) 23 | 24 | use errors::*; 25 | 26 | mod serialize; 27 | 28 | mod share; 29 | pub use self::share::*; 30 | 31 | mod scheme; 32 | pub use self::scheme::Reproducibility; 33 | use self::scheme::SS1; 34 | 35 | use dss::AccessStructure; 36 | 37 | /// Performs threshold k-out-of-n deterministic secret sharing. 38 | /// 39 | /// # Examples 40 | /// 41 | /// ``` 42 | /// use rusty_secrets::dss::ss1::{self, Reproducibility, MetaData}; 43 | /// 44 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 45 | /// social control, and diplomatic manipulation. They’re about power."; 46 | /// 47 | /// let mut metadata = MetaData::new(); 48 | /// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); 49 | /// 50 | /// match ss1::split_secret(7, 10, &secret.as_bytes(), Reproducibility::reproducible(), &Some(metadata)) { 51 | /// Ok(shares) => { 52 | /// // Do something with the shares 53 | /// }, 54 | /// Err(_) => { 55 | /// // Deal with error 56 | /// } 57 | /// } 58 | /// ``` 59 | pub fn split_secret( 60 | k: u8, 61 | n: u8, 62 | secret: &[u8], 63 | reproducibility: Reproducibility, 64 | metadata: &Option, 65 | ) -> Result> { 66 | SS1::default().split_secret(k, n, secret, reproducibility, metadata) 67 | } 68 | 69 | /// Recovers the secret from a k-out-of-n deterministic secret sharing scheme (`SS1`). 70 | /// 71 | /// At least `k` distinct shares need to be provided to recover the secret. 72 | /// 73 | /// # Examples 74 | /// 75 | /// ```rust 76 | /// use rusty_secrets::dss::ss1::{self, Reproducibility, MetaData}; 77 | /// 78 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 79 | /// social control, and diplomatic manipulation. They’re about power."; 80 | /// 81 | /// let mut metadata = MetaData::new(); 82 | /// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); 83 | /// 84 | /// let shares = ss1::split_secret( 85 | /// 7, 86 | /// 10, 87 | /// &secret.as_bytes(), 88 | /// Reproducibility::reproducible(), 89 | /// &Some(metadata) 90 | /// ).unwrap(); 91 | /// 92 | /// match ss1::recover_secret(&shares) { 93 | /// Ok((secret, access_structure, metadata)) => { 94 | /// // Do something with the secret and the metadata 95 | /// }, 96 | /// Err(e) => { 97 | /// // Deal with the error 98 | /// } 99 | /// } 100 | /// ``` 101 | pub fn recover_secret(shares: &[Share]) -> Result<(Vec, AccessStructure, Option)> { 102 | SS1::default().recover_secret(shares) 103 | } 104 | 105 | #[cfg(test)] 106 | mod tests { 107 | 108 | use super::*; 109 | 110 | #[test] 111 | fn nonreproducible_split_then_recover_yields_original_secret() { 112 | let secret = "Hello, World!".to_string().into_bytes(); 113 | 114 | let shares = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); 115 | 116 | assert_eq!(shares.len(), 10); 117 | 118 | let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); 119 | 120 | assert_eq!(secret, recovered); 121 | assert_eq!(access_structure.threshold, 7); 122 | assert_eq!(access_structure.shares_count, 10); 123 | assert_eq!(None, metadata); 124 | } 125 | 126 | #[test] 127 | fn reproducible_split_then_recover_yields_original_secret() { 128 | let secret = "Hello, World!".to_string().into_bytes(); 129 | 130 | let shares = split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); 131 | 132 | assert_eq!(shares.len(), 10); 133 | 134 | let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); 135 | 136 | assert_eq!(secret, recovered); 137 | assert_eq!(access_structure.threshold, 7); 138 | assert_eq!(access_structure.shares_count, 10); 139 | assert_eq!(None, metadata); 140 | } 141 | 142 | #[test] 143 | fn seeded_reproducible_split_then_recover_yields_original_secret() { 144 | let secret = "Hello, World!".to_string().into_bytes(); 145 | 146 | let seed = vec![1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16u8]; 147 | let shares = split_secret(7, 10, &secret, Reproducibility::seeded(seed), &None).unwrap(); 148 | 149 | assert_eq!(shares.len(), 10); 150 | 151 | let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); 152 | 153 | assert_eq!(secret, recovered); 154 | assert_eq!(access_structure.threshold, 7); 155 | assert_eq!(access_structure.shares_count, 10); 156 | assert_eq!(None, metadata); 157 | } 158 | 159 | #[test] 160 | fn reproducible_split() { 161 | let secret = "Hello, World!".to_string().into_bytes(); 162 | 163 | let shares_1 = 164 | split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); 165 | let shares_2 = 166 | split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); 167 | 168 | assert_eq!(shares_1, shares_2); 169 | } 170 | 171 | #[test] 172 | fn nonreproducible_split() { 173 | let secret = "Hello, World!".to_string().into_bytes(); 174 | 175 | let shares_1 = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); 176 | let shares_2 = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); 177 | 178 | assert!(shares_1 != shares_2); 179 | } 180 | 181 | #[test] 182 | fn seeded_split() { 183 | let secret = "Hello, World!".to_string().into_bytes(); 184 | 185 | let seed = vec![1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16u8]; 186 | let shares_1 = 187 | split_secret(7, 10, &secret, Reproducibility::seeded(seed.clone()), &None).unwrap(); 188 | let shares_2 = 189 | split_secret(7, 10, &secret, Reproducibility::seeded(seed.clone()), &None).unwrap(); 190 | 191 | assert_eq!(shares_1, shares_2); 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /src/dss/ss1/scheme.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use rand::{ChaChaRng, Rng, SeedableRng}; 4 | use ring::digest::{Context, SHA256}; 5 | use ring::rand::{SecureRandom, SystemRandom}; 6 | use ring::{hkdf, hmac}; 7 | 8 | use super::share::*; 9 | use dss::random::{random_bytes_count, FixedRandom, MAX_MESSAGE_SIZE}; 10 | use dss::thss::{MetaData, ThSS}; 11 | use dss::utils; 12 | use dss::{thss, AccessStructure}; 13 | use errors::*; 14 | use share::validation::{validate_share_count, validate_shares}; 15 | use vol_hash::VOLHash; 16 | 17 | /// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. 18 | /// Moreover, given the current performances, it is almost unpractical to run 19 | /// the sharing scheme on message larger than that. 20 | const MAX_SECRET_SIZE: usize = MAX_MESSAGE_SIZE; 21 | 22 | const DEFAULT_PRESEED: &[u8] = b"rusty_secrets::dss::ss1"; 23 | 24 | /// There are situations where it's useful to generate shares in a reproducible manner. 25 | /// In particular, this allows a secret that’s in someone’s head, a passphrase, 26 | /// to be shared out in a manner in which different shares can be given to 27 | /// different people at different points in time. 28 | /// 29 | /// On the other hand, there is some privacy cost. 30 | /// For example, if you know the secret is one of two possibilities, 31 | /// M0 or M1, in a share-reproducible scheme, acquiring a single share 32 | /// will probably let you decide which of the two possibilities it was. 33 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 34 | pub enum Reproducibility { 35 | /// Shares will be produced in a deterministic way, using 36 | /// a default, fixed seed for the internal random number generator 37 | /// used to generate entropy. 38 | Reproducible, 39 | /// Shares will be produced in non-deterministic way, using 40 | /// the system's random number generator to produce entropy. 41 | None, 42 | /// Shares will be produced in a deterministic way, using 43 | /// the given seed for the internal random number generator used to 44 | /// generate entropy. 45 | Seeded(Vec), 46 | /// Shares will be produced in a deterministic way, using 47 | /// the given byte vector as the entropy source. 48 | /// *Warning: Never use this variant unless you are sure of what you are doing* 49 | WithEntropy(Vec), 50 | } 51 | 52 | impl Reproducibility { 53 | /// Shares will be produced in a deterministic way, using 54 | /// a default, fixed seed for the internal random number generator 55 | /// used to generate entropy. 56 | pub fn reproducible() -> Self { 57 | Reproducibility::Reproducible 58 | } 59 | 60 | /// Shares will be produced in a deterministic way, using 61 | /// the given seed for the internal random number generator used to 62 | /// generate entropy. 63 | pub fn seeded(seed: Vec) -> Self { 64 | assert!(!seed.is_empty(), "Reproducibility: seed cannot be empty"); 65 | Reproducibility::Seeded(seed) 66 | } 67 | 68 | /// Shares will be produced in a deterministic way, using 69 | /// the given byte vector as the entropy source. 70 | /// *Warning: Never use this variant unless you are sure of what you are doing* 71 | pub fn with_entropy(entropy: Vec) -> Self { 72 | assert!( 73 | !entropy.is_empty(), 74 | "Reproducibility: entropy cannot be empty" 75 | ); 76 | Reproducibility::WithEntropy(entropy) 77 | } 78 | 79 | /// Shares will be produced in non-deterministic way, using 80 | /// the system's random number generator to produce entropy. 81 | pub fn none() -> Self { 82 | Reproducibility::None 83 | } 84 | } 85 | 86 | /// Defines a `SS1` deterministic threshold secret sharing scheme. 87 | /// 88 | /// This scheme is implemented as the *T2 transform* over the ThSS threshold sharing scheme. 89 | /// found in the `rusty_secrets::dss::thss` module. 90 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 91 | pub(crate) struct SS1 { 92 | /// How many random bytes to read from `random` to use as 93 | /// padding to the hash function (param `r` from the paper) 94 | /// and to the message in the underlying ThSS scheme. 95 | pub random_padding_len: usize, 96 | /// The length of the hash used for all shares (param `s` from the paper) 97 | pub hash_len: usize, 98 | } 99 | 100 | // TODO: Are those good parameters? 101 | // TODO: Add max length ? 102 | static DEFAULT_RANDOM_PADDING_LEN: usize = 512; // r 103 | static MIN_RANDOM_PADDING_LEN: usize = 128; // r min 104 | static DEFAULT_HASH_LEN: usize = 256; // s 105 | static MIN_HASH_LEN: usize = 128; // s min 106 | 107 | impl Default for SS1 { 108 | fn default() -> Self { 109 | Self::new(DEFAULT_RANDOM_PADDING_LEN, DEFAULT_HASH_LEN).unwrap() 110 | } 111 | } 112 | 113 | impl SS1 { 114 | /// Constructs a new sharing scheme 115 | pub fn new(random_padding_len: usize, hash_len: usize) -> Result { 116 | if random_padding_len < MIN_RANDOM_PADDING_LEN || hash_len < MIN_HASH_LEN { 117 | bail!(ErrorKind::InvalidSS1Parameters( 118 | random_padding_len, 119 | hash_len, 120 | )); 121 | } 122 | 123 | Ok(Self { 124 | random_padding_len, 125 | hash_len, 126 | }) 127 | } 128 | 129 | /// Split a secret following a given sharing `scheme`, 130 | /// with `threshold` being the number of shares necessary to recover the secret, 131 | /// and `shares_count` the total number of shares to be dealt. 132 | pub fn split_secret( 133 | &self, 134 | threshold: u8, 135 | shares_count: u8, 136 | secret: &[u8], 137 | reproducibility: Reproducibility, 138 | metadata: &Option, 139 | ) -> Result> { 140 | let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; 141 | let secret_len = secret.len(); 142 | 143 | if secret_len == 0 { 144 | bail!(ErrorKind::EmptySecret); 145 | } 146 | if secret_len > MAX_SECRET_SIZE { 147 | bail!(ErrorKind::SecretTooBig(secret_len, MAX_SECRET_SIZE)); 148 | } 149 | 150 | let random_padding = self.generate_random_padding(reproducibility, secret, metadata)?; 151 | 152 | let mut vol_hash = VOLHash::new(&SHA256); 153 | vol_hash.process(&[0]); 154 | vol_hash.process(&[threshold, shares_count]); 155 | vol_hash.process(secret); 156 | vol_hash.process(&random_padding); 157 | 158 | let randomness_len = random_bytes_count(threshold, secret.len() + self.random_padding_len); 159 | let total_hash_len = self.hash_len + randomness_len; 160 | let mut full_hash = vec![0; total_hash_len]; 161 | 162 | vol_hash.finish(&mut full_hash); 163 | let (hash, randomness) = full_hash.split_at(self.hash_len); 164 | 165 | let underlying = ThSS::new(Box::new(FixedRandom::new(randomness.to_vec()))); 166 | 167 | let message = [secret, &random_padding].concat(); 168 | let shares = underlying.split_secret(threshold, shares_count, &message, metadata)?; 169 | 170 | let res = shares 171 | .into_iter() 172 | .map(|share| Share { 173 | id: share.id, 174 | threshold: share.threshold, 175 | shares_count: share.shares_count, 176 | data: share.data, 177 | hash: hash.to_vec(), 178 | metadata: share.metadata.clone(), 179 | }) 180 | .collect(); 181 | 182 | Ok(res) 183 | } 184 | 185 | fn generate_random_padding( 186 | &self, 187 | reproducibility: Reproducibility, 188 | secret: &[u8], 189 | metadata: &Option, 190 | ) -> Result> { 191 | match reproducibility { 192 | Reproducibility::None => { 193 | let rng = SystemRandom::new(); 194 | let mut result = vec![0u8; self.random_padding_len]; 195 | rng.fill(&mut result) 196 | .chain_err(|| ErrorKind::CannotGenerateRandomNumbers)?; 197 | Ok(result) 198 | } 199 | Reproducibility::Reproducible => { 200 | let seed = self.generate_seed(DEFAULT_PRESEED, secret, metadata); 201 | let mut rng = ChaChaRng::from_seed(&seed); 202 | let mut result = vec![0u8; self.random_padding_len]; 203 | rng.fill_bytes(result.as_mut_slice()); 204 | Ok(result) 205 | } 206 | Reproducibility::Seeded(preseed) => { 207 | let seed = self.generate_seed(&preseed, secret, metadata); 208 | let mut rng = ChaChaRng::from_seed(&seed); 209 | let mut result = vec![0u8; self.random_padding_len]; 210 | rng.fill_bytes(result.as_mut_slice()); 211 | Ok(result) 212 | } 213 | Reproducibility::WithEntropy(entropy) => Ok(entropy), 214 | } 215 | } 216 | 217 | /// Generate a seed of 8 32-bits word for the ChaCha20 PRNG by hashing 218 | /// together the preseed, secret, and metadata, in order to obtain a salt 219 | /// for performing HKDF over the preseed. 220 | fn generate_seed( 221 | &self, 222 | preseed: &[u8], 223 | secret: &[u8], 224 | metadata: &Option, 225 | ) -> Vec { 226 | let mut ctx = Context::new(&SHA256); 227 | ctx.update(preseed); 228 | ctx.update(secret); 229 | for md in metadata { 230 | md.hash_into(&mut ctx); 231 | } 232 | let preseed_hash = ctx.finish(); 233 | 234 | let salt = hmac::SigningKey::new(&SHA256, &[]); 235 | let mut seed_bytes = vec![0u8; 32]; 236 | hkdf::extract_and_expand(&salt, preseed_hash.as_ref(), &[], &mut seed_bytes); 237 | 238 | // We can safely call `utils::slice_u8_to_slice_u32` because 239 | // the `digest` produced with `SHA256` is 256 bits long, as is 240 | // `seed_bytes`, and the latter can thus be represented both as a 241 | // slice of 32 bytes or as a slice of 8 32-bit words. 242 | utils::slice_u8_to_slice_u32(&seed_bytes).to_vec() 243 | } 244 | 245 | /// Recover the secret from the given set of shares 246 | pub fn recover_secret( 247 | &self, 248 | shares: &[Share], 249 | ) -> Result<(Vec, AccessStructure, Option)> { 250 | let shares = shares.to_vec(); 251 | validate_shares(&shares)?; 252 | 253 | let underlying_shares = shares 254 | .iter() 255 | .map(|share| thss::Share { 256 | id: share.id, 257 | threshold: share.threshold, 258 | shares_count: share.shares_count, 259 | data: share.data.clone(), 260 | metadata: share.metadata.clone(), 261 | }) 262 | .collect::>(); 263 | 264 | let underlying = ThSS::default(); 265 | let (mut secret, _, metadata) = underlying.recover_secret(&underlying_shares)?; 266 | let secret_len = secret.len() - self.random_padding_len; 267 | let random_padding = secret.split_off(secret_len); 268 | // `secret` nows holds the secret 269 | 270 | let sub_scheme = Self::new(self.random_padding_len, self.hash_len)?; 271 | 272 | let test_shares = sub_scheme.split_secret( 273 | shares[0].threshold, 274 | shares[0].shares_count, 275 | &secret, 276 | Reproducibility::WithEntropy(random_padding.to_vec()), 277 | &metadata, 278 | )?; 279 | 280 | let access_structure = { 281 | let first_share = shares.first().unwrap(); 282 | AccessStructure { 283 | threshold: first_share.threshold, 284 | shares_count: first_share.shares_count, 285 | } 286 | }; 287 | 288 | self.verify_test_shares(shares, test_shares)?; 289 | 290 | Ok((secret, access_structure, metadata)) 291 | } 292 | 293 | fn verify_test_shares( 294 | &self, 295 | mut shares: Vec, 296 | mut test_shares: Vec, 297 | ) -> Result<()> { 298 | shares.sort_by_key(|share| share.id); 299 | test_shares.sort_by_key(|share| share.id); 300 | 301 | let relevant_ids = shares.iter().map(|share| share.id).collect::>(); 302 | let relevant_test_shares = test_shares 303 | .iter() 304 | .filter(|share| relevant_ids.contains(&share.id)); 305 | let matching_shares = shares.iter().zip(relevant_test_shares); 306 | 307 | for (share, test_share) in matching_shares { 308 | if share != test_share { 309 | bail!(ErrorKind::MismatchingShares( 310 | share.clone(), 311 | test_share.clone(), 312 | )); 313 | } 314 | } 315 | 316 | Ok(()) 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/dss/ss1/serialize.rs: -------------------------------------------------------------------------------- 1 | use super::{MetaData, Share}; 2 | use dss::format::{format_share_protobuf, parse_share_protobuf}; 3 | use dss::utils::{btreemap_to_hashmap, hashmap_to_btreemap}; 4 | use errors::*; 5 | use proto::dss::{MetaDataProto, ShareProto}; 6 | 7 | pub(crate) fn share_to_string(share: Share) -> String { 8 | let proto = share_to_protobuf(share); 9 | format_share_protobuf(&proto) 10 | } 11 | 12 | pub(crate) fn share_from_string(raw: &str) -> Result { 13 | let mut proto = parse_share_protobuf(raw)?; 14 | 15 | let metadata_proto = if proto.has_meta_data() { 16 | Some(metadata_from_proto(proto.take_meta_data())) 17 | } else { 18 | None 19 | }; 20 | 21 | let i = proto.get_id() as u8; 22 | let k = proto.get_threshold() as u8; 23 | let n = proto.get_shares_count() as u8; 24 | 25 | if k < 1 || i < 1 { 26 | bail! { 27 | ErrorKind::ShareParsingError( 28 | format!("Found illegal share info: threshold = {}, identifier = {}.", k, i), 29 | ) 30 | } 31 | } 32 | 33 | if n < 1 || k > n || i > n { 34 | bail! { 35 | ErrorKind::ShareParsingError( 36 | format!("Found illegal share info: shares_count = {}, threshold = {}, identifier = {}.", n, k, i), 37 | ) 38 | } 39 | } 40 | 41 | let share = Share { 42 | id: i, 43 | threshold: k, 44 | shares_count: n, 45 | data: proto.take_data(), 46 | hash: proto.take_hash(), 47 | metadata: metadata_proto, 48 | }; 49 | 50 | Ok(share) 51 | } 52 | 53 | pub(crate) fn share_to_protobuf(share: Share) -> ShareProto { 54 | let mut proto = ShareProto::new(); 55 | 56 | proto.set_id(share.id.into()); 57 | proto.set_threshold(share.threshold.into()); 58 | proto.set_shares_count(share.shares_count.into()); 59 | proto.set_data(share.data); 60 | proto.set_hash(share.hash); 61 | 62 | if let Some(meta_data) = share.metadata { 63 | let metadata_proto = metadata_to_proto(meta_data); 64 | proto.set_meta_data(metadata_proto); 65 | } 66 | 67 | proto 68 | } 69 | 70 | fn metadata_to_proto(meta_data: MetaData) -> MetaDataProto { 71 | let mut proto = MetaDataProto::new(); 72 | proto.set_tags(btreemap_to_hashmap(meta_data.tags)); 73 | proto 74 | } 75 | 76 | fn metadata_from_proto(mut proto: MetaDataProto) -> MetaData { 77 | MetaData { 78 | tags: hashmap_to_btreemap(proto.take_tags()), 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/dss/ss1/share.rs: -------------------------------------------------------------------------------- 1 | use super::serialize::{share_from_string, share_to_string}; 2 | use errors::*; 3 | use share::IsShare; 4 | 5 | pub use dss::metadata::MetaData; 6 | 7 | /// A share identified by an `id`, a threshold `k`, a number of total shares `n`, 8 | /// the `data` held in the share, and the share's `metadata`. 9 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 10 | pub struct Share { 11 | /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) 12 | pub id: u8, 13 | /// The number of shares necessary to recover the secret, aka a threshold 14 | pub threshold: u8, 15 | /// The total number of shares that have been dealt 16 | pub shares_count: u8, 17 | /// The share data itself 18 | pub data: Vec, 19 | /// The hash value common to the whole deal 20 | pub hash: Vec, 21 | /// The metadata associated with this share 22 | pub metadata: Option, 23 | } 24 | 25 | impl Share { 26 | /// Format this share a string suitable for sharing 27 | /// over an ASCII-encoded channel, such as a text file, 28 | /// or an e-mail. 29 | pub fn into_string(self) -> String { 30 | share_to_string(self) 31 | } 32 | 33 | /// Parse the given string into a `Share`. 34 | /// The `raw` string must have been generated by the 35 | /// `Share::to_string` method for it to succeed. 36 | pub fn from_string(raw: &str) -> Result { 37 | share_from_string(raw) 38 | } 39 | } 40 | 41 | impl IsShare for Share { 42 | fn get_id(&self) -> u8 { 43 | self.id 44 | } 45 | 46 | fn get_data(&self) -> &[u8] { 47 | &self.data 48 | } 49 | 50 | fn get_threshold(&self) -> u8 { 51 | self.threshold 52 | } 53 | 54 | fn get_shares_count(&self) -> Option { 55 | Some(self.shares_count) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/dss/thss/encode.rs: -------------------------------------------------------------------------------- 1 | use gf256::Gf256; 2 | use poly::Poly; 3 | 4 | /// Encode the given `secret` using the `ThSS[N].Share` algorithm described 5 | /// in the *New directions in Secret Sharing* paper. 6 | /// 7 | /// Reference: Figure 7 from the *New Directions in Secret Sharing* paper. 8 | pub(crate) fn encode_secret(secret: &[u8], k: u8, share_id: u8, rands: &[u8]) -> Vec { 9 | secret 10 | .into_iter() 11 | .enumerate() 12 | .map(|(i, m)| { 13 | let k_pred = (k - 1) as usize; 14 | let coeffs = (0..k_pred) 15 | .map(|l| { 16 | let n = rands[i * k_pred + l]; 17 | Gf256::from_byte(n) 18 | }) 19 | .collect(); 20 | let poly = Poly::new(coeffs); 21 | encode_secret_byte(*m, share_id, &poly) 22 | }) 23 | .collect() 24 | } 25 | 26 | /// Encode the given secret byte `m`, by evaluating the given 27 | /// polynomial at x = `j`, and adding the result to `m`. 28 | /// 29 | /// Reference: Figure 7 from the *New Directions in Secret Sharing* paper. 30 | pub(crate) fn encode_secret_byte(m: u8, j: u8, poly: &Poly) -> u8 { 31 | let mut acc = Gf256::from_byte(m); 32 | for (l, &r) in poly.coeffs.iter().enumerate() { 33 | let s = Gf256::from_byte(j).pow(l as u8 + 1); 34 | acc += r * s; 35 | } 36 | acc.to_byte() 37 | } 38 | -------------------------------------------------------------------------------- /src/dss/thss/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implements the `ThSS` threshold secret sharing scheme. 2 | //! 3 | //! This scheme satisfies the following security properties: 4 | //! 5 | //! **Property** | **Satisifed?** | **Description** 6 | //! -------------|----------------|---------------- 7 | //! **Basic** | Yes | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. 8 | //! **Priv1** | Yes | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. 9 | //! **Priv2** | No | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. 10 | //! **Auth1** | No | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. 11 | //! **Auth2** | No | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. 12 | //! **ErrDet** | Yes | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. 13 | //! **Repro** | No | Share reproducible: The scheme can produce shares in a deterministic way. 14 | 15 | use errors::*; 16 | 17 | mod encode; 18 | mod serialize; 19 | 20 | mod share; 21 | pub use self::share::*; 22 | 23 | mod scheme; 24 | pub(crate) use self::scheme::ThSS; 25 | 26 | use dss::AccessStructure; 27 | 28 | /// Performs threshold k-out-of-n secret sharing using the `ThSS` scheme. 29 | /// 30 | /// # Examples 31 | /// 32 | /// ```rust 33 | /// use rusty_secrets::dss::thss; 34 | /// 35 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 36 | /// social control, and diplomatic manipulation. They’re about power."; 37 | /// 38 | /// let mut metadata = thss::MetaData::new(); 39 | /// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); 40 | /// 41 | /// let result = thss::split_secret( 42 | /// 7, 43 | /// 10, 44 | /// &secret.as_bytes(), 45 | /// &Some(metadata) 46 | /// ); 47 | /// 48 | /// match result { 49 | /// Ok(shares) => { 50 | /// // Do something with the shares 51 | /// }, 52 | /// Err(e) => { 53 | /// // Deal with error 54 | /// } 55 | /// } 56 | /// 57 | /// ``` 58 | pub fn split_secret( 59 | k: u8, 60 | n: u8, 61 | secret: &[u8], 62 | metadata: &Option, 63 | ) -> Result> { 64 | ThSS::default().split_secret(k, n, secret, metadata) 65 | } 66 | 67 | /// Recovers the secret from a k-out-of-n secret sharing scheme (`ThSS`). 68 | /// 69 | /// At least `k` distinct shares need to be provided to recover the secret. 70 | /// 71 | /// # Examples 72 | /// 73 | /// ```rust 74 | /// use rusty_secrets::dss::thss; 75 | /// 76 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 77 | /// social control, and diplomatic manipulation. They’re about power."; 78 | /// 79 | /// let mut metadata = thss::MetaData::new(); 80 | /// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); 81 | /// 82 | /// let shares = thss::split_secret( 83 | /// 7, 84 | /// 10, 85 | /// &secret.as_bytes(), 86 | /// &Some(metadata) 87 | /// ).unwrap(); 88 | /// 89 | /// match thss::recover_secret(&shares) { 90 | /// Ok((secret, access_structure, metadata)) => { 91 | /// // Do something with the secret and the metadata 92 | /// }, 93 | /// Err(e) => { 94 | /// // Deal with the error 95 | /// } 96 | /// } 97 | /// ``` 98 | pub fn recover_secret(shares: &[Share]) -> Result<(Vec, AccessStructure, Option)> { 99 | ThSS::default().recover_secret(shares) 100 | } 101 | 102 | #[cfg(test)] 103 | mod tests { 104 | 105 | use super::*; 106 | 107 | #[test] 108 | fn split_then_recover_yields_original_secret() { 109 | let secret = "Hello, World!".to_string().into_bytes(); 110 | 111 | let shares = split_secret(7, 10, &secret, &None).unwrap(); 112 | assert_eq!(shares.len(), 10); 113 | 114 | let (recovered, access, metadata) = recover_secret(&shares[2..9]).unwrap(); 115 | 116 | assert_eq!(secret, recovered); 117 | assert_eq!(access.threshold, 7); 118 | assert_eq!(access.shares_count, 10); 119 | assert_eq!(None, metadata); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/dss/thss/scheme.rs: -------------------------------------------------------------------------------- 1 | //! Simple threshold secret sharing scheme 2 | 3 | use std::fmt; 4 | 5 | use ring::rand::{SecureRandom, SystemRandom}; 6 | 7 | use dss::random::{random_bytes, random_bytes_count, MAX_MESSAGE_SIZE}; 8 | use errors::*; 9 | use gf256::Gf256; 10 | use lagrange; 11 | use share::validation::{validate_share_count, validate_shares}; 12 | 13 | use super::AccessStructure; 14 | use super::encode::encode_secret; 15 | use super::share::*; 16 | 17 | /// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. 18 | /// Moreover, given the current performances, it is almost unpractical to run 19 | /// the sharing scheme on message larger than that. 20 | const MAX_SECRET_SIZE: usize = MAX_MESSAGE_SIZE; 21 | 22 | /// A simple threshold sharing scheme 23 | #[allow(missing_debug_implementations)] 24 | pub(crate) struct ThSS { 25 | /// The randomness source 26 | random: Box, 27 | } 28 | 29 | impl fmt::Debug for ThSS { 30 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 31 | write!(f, "ThSS") 32 | } 33 | } 34 | 35 | impl Default for ThSS { 36 | fn default() -> Self { 37 | Self::new(Box::new(SystemRandom::new())) 38 | } 39 | } 40 | 41 | impl ThSS { 42 | /// Constructs a new sharing scheme 43 | pub fn new(random: Box) -> Self { 44 | Self { random } 45 | } 46 | 47 | /// Split a secret following a given sharing `scheme`, 48 | /// with `threshold` being the number of shares necessary to recover the secret, 49 | /// and `shares_count` the total number of shares to be dealt. 50 | pub fn split_secret( 51 | &self, 52 | threshold: u8, 53 | shares_count: u8, 54 | secret: &[u8], 55 | metadata: &Option, 56 | ) -> Result> { 57 | let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; 58 | let secret_len = secret.len(); 59 | 60 | if secret_len == 0 { 61 | bail!(ErrorKind::EmptySecret); 62 | } 63 | if secret_len > MAX_SECRET_SIZE { 64 | bail!(ErrorKind::SecretTooBig(secret_len, MAX_SECRET_SIZE)); 65 | } 66 | 67 | let rands_len = random_bytes_count(threshold, secret_len); 68 | let rands = random_bytes(self.random.as_ref(), rands_len)?; 69 | 70 | let shares = (1..shares_count + 1) 71 | .map(|id| { 72 | let data = encode_secret(secret, threshold, id, &rands); 73 | 74 | Share { 75 | id, 76 | threshold, 77 | shares_count, 78 | data, 79 | metadata: metadata.clone(), 80 | } 81 | }) 82 | .collect(); 83 | 84 | Ok(shares) 85 | } 86 | 87 | /// Recover the secret from the given set of shares 88 | pub fn recover_secret( 89 | &self, 90 | shares: &[Share], 91 | ) -> Result<(Vec, AccessStructure, Option)> { 92 | let shares = shares.to_vec(); 93 | let (threshold, cypher_len) = validate_shares(&shares)?; 94 | 95 | let polys = (0..cypher_len) 96 | .map(|i| { 97 | let points = shares 98 | .iter() 99 | .take(threshold as usize) 100 | .map(|share| (Gf256::from_byte(share.id), Gf256::from_byte(share.data[i]))) 101 | .collect::>(); 102 | 103 | lagrange::interpolate(&points) 104 | }) 105 | .collect::>(); 106 | 107 | for (i, poly) in polys.iter().enumerate() { 108 | // Check remaining shares for consistency. 109 | // See Figure 7 of the paper 110 | let remaining_shares = shares.iter().enumerate().skip(threshold as usize); 111 | 112 | for (u, share) in remaining_shares { 113 | let value = poly.evaluate_at(Gf256::from_byte(u as u8 + 1)).to_byte(); 114 | if value != share.data[i] { 115 | bail!(ErrorKind::InconsistentShares); 116 | } 117 | } 118 | } 119 | 120 | let metadata = shares[0].metadata.clone(); 121 | let secret = polys 122 | .iter() 123 | .map(|p| p.evaluate_at_zero().to_byte()) 124 | .collect(); 125 | 126 | let access_structure = AccessStructure { 127 | threshold: threshold, 128 | shares_count: shares.first().unwrap().shares_count, 129 | }; 130 | 131 | Ok((secret, access_structure, metadata)) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/dss/thss/serialize.rs: -------------------------------------------------------------------------------- 1 | use super::{MetaData, Share}; 2 | use dss::format::{format_share_protobuf, parse_share_protobuf}; 3 | use dss::utils::{btreemap_to_hashmap, hashmap_to_btreemap}; 4 | use errors::*; 5 | use proto::dss::{MetaDataProto, ShareProto}; 6 | 7 | pub(crate) fn share_to_string(share: Share) -> String { 8 | let proto = share_to_protobuf(share); 9 | format_share_protobuf(&proto) 10 | } 11 | 12 | pub(crate) fn share_from_string(raw: &str) -> Result { 13 | let mut proto = parse_share_protobuf(raw)?; 14 | 15 | let metadata_proto = if proto.has_meta_data() { 16 | Some(metadata_from_proto(proto.take_meta_data())) 17 | } else { 18 | None 19 | }; 20 | 21 | let i = proto.get_id() as u8; 22 | let k = proto.get_threshold() as u8; 23 | let n = proto.get_shares_count() as u8; 24 | 25 | if k < 1 || i < 1 { 26 | bail! { 27 | ErrorKind::ShareParsingError( 28 | format!("Found illegal share info: threshold = {}, identifier = {}.", k, i), 29 | ) 30 | } 31 | } 32 | 33 | if n < 1 || k > n || i > n { 34 | bail! { 35 | ErrorKind::ShareParsingError( 36 | format!("Found illegal share info: shares_count = {}, threshold = {}, identifier = {}.", n, k, i), 37 | ) 38 | } 39 | } 40 | 41 | let share = Share { 42 | id: i, 43 | threshold: k, 44 | shares_count: n, 45 | data: proto.take_data(), 46 | metadata: metadata_proto, 47 | }; 48 | 49 | Ok(share) 50 | } 51 | 52 | pub(crate) fn share_to_protobuf(share: Share) -> ShareProto { 53 | let mut proto = ShareProto::new(); 54 | 55 | proto.set_id(share.id.into()); 56 | proto.set_threshold(share.threshold.into()); 57 | proto.set_shares_count(share.shares_count.into()); 58 | proto.set_data(share.data); 59 | 60 | if let Some(meta_data) = share.metadata { 61 | let metadata_proto = metadata_to_proto(meta_data); 62 | proto.set_meta_data(metadata_proto); 63 | } 64 | 65 | proto 66 | } 67 | 68 | fn metadata_to_proto(meta_data: MetaData) -> MetaDataProto { 69 | let mut proto = MetaDataProto::new(); 70 | proto.set_tags(btreemap_to_hashmap(meta_data.tags)); 71 | proto 72 | } 73 | 74 | fn metadata_from_proto(mut proto: MetaDataProto) -> MetaData { 75 | MetaData { 76 | tags: hashmap_to_btreemap(proto.take_tags()), 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/dss/thss/share.rs: -------------------------------------------------------------------------------- 1 | use super::serialize::{share_from_string, share_to_string}; 2 | use errors::*; 3 | use share::IsShare; 4 | 5 | pub use dss::metadata::MetaData; 6 | 7 | /// A share identified by an `id`, a threshold `k`, a number of total shares `n`, 8 | /// the `data` held in the share, and the share's `metadata`. 9 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 10 | pub struct Share { 11 | /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) 12 | pub id: u8, 13 | /// The number of shares necessary to recover the secret, aka a threshold 14 | pub threshold: u8, 15 | /// The total number of shares that have been dealt 16 | pub shares_count: u8, 17 | /// The share data itself 18 | pub data: Vec, 19 | /// The metadata associated with this share 20 | pub metadata: Option, 21 | } 22 | 23 | impl Share { 24 | /// Format this share a string suitable for sharing 25 | /// over an ASCII-encoded channel, such as a text file, 26 | /// or an e-mail. 27 | pub fn into_string(self) -> String { 28 | share_to_string(self) 29 | } 30 | 31 | /// Parse the given string into a `Share`. 32 | /// The `raw` string must have been generated by the 33 | /// `Share::to_string` method for it to succeed. 34 | pub fn from_string(raw: &str) -> Result { 35 | share_from_string(raw) 36 | } 37 | } 38 | 39 | impl IsShare for Share { 40 | fn get_id(&self) -> u8 { 41 | self.id 42 | } 43 | 44 | fn get_data(&self) -> &[u8] { 45 | &self.data 46 | } 47 | 48 | fn get_threshold(&self) -> u8 { 49 | self.threshold 50 | } 51 | 52 | fn get_shares_count(&self) -> Option { 53 | Some(self.shares_count) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/dss/utils.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | 3 | use std::collections::{BTreeMap, HashMap}; 4 | use std::hash::Hash; 5 | 6 | /// Transmutes a `&[u8]` into a `&[u32]`. 7 | /// Despite `std::mem::transmute` being very unsafe in 8 | /// general, this should actually be safe as long as 9 | /// `input` contains a multiple of 4 bytes. 10 | #[allow(unsafe_code)] 11 | pub(crate) fn slice_u8_to_slice_u32(input: &[u8]) -> &[u32] { 12 | assert_eq!(input.len() % 4, 0); 13 | unsafe { std::mem::transmute(input) } 14 | } 15 | 16 | /// Creates a `HashMap` from a `BTreeMap` 17 | pub(crate) fn btreemap_to_hashmap(btree: BTreeMap) -> HashMap { 18 | let mut hash = HashMap::new(); 19 | hash.extend(btree.into_iter()); 20 | hash 21 | } 22 | 23 | /// Creates a `BTreeMap` from a `HashMap` 24 | pub(crate) fn hashmap_to_btreemap(hash: HashMap) -> BTreeMap { 25 | let mut btree = BTreeMap::new(); 26 | btree.extend(hash.into_iter()); 27 | btree 28 | } 29 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | //! Define the various error kinds specific to deterministic secret sharing. 2 | 3 | #![allow(unknown_lints, missing_docs)] 4 | 5 | use std::collections::HashSet; 6 | use std::fmt; 7 | 8 | #[cfg(feature = "dss")] 9 | use dss::ss1; 10 | 11 | /// Minimum allowed number of shares (n) 12 | pub(crate) static MIN_SHARES: u8 = 2; 13 | /// Minimum allowed threshold (k) 14 | pub(crate) static MIN_THRESHOLD: u8 = 2; 15 | /// Maximum allowed number of shares (k,n) 16 | pub(crate) static MAX_SHARES: u8 = 255; 17 | /// SSS Shares should be structured as k-n-data hence 3 parts 18 | pub(crate) static SSS_SHARE_PARTS_COUNT: usize = 3; 19 | 20 | /// Create the Error, ErrorKind, ResultExt, and Result types 21 | error_chain! { 22 | errors { 23 | ThresholdTooBig(k: u8, n: u8) { 24 | description("Threshold k must be smaller than or equal to n") 25 | display("Threshold k must be smaller than or equal to n, got: k = {}, n = {}.", k, n) 26 | } 27 | 28 | ThresholdTooSmall(k: u8) { 29 | description("Threshold k must be bigger than or equal to 2") 30 | display("Threshold k must be bigger than or equal to 2, got: k = {}", k) 31 | } 32 | 33 | SecretTooBig(len: usize, max: usize) { 34 | description("The secret is too long") 35 | display("The secret is too long, maximum allowed size = {} bytes, got {} bytes", max, len) 36 | } 37 | 38 | InvalidShareCountMax(nb_shares: u8, max: u8) { 39 | description("Number of shares is too big") 40 | display("Number of shares must be smaller than or equal {}, got: {} shares.", max, nb_shares) 41 | } 42 | 43 | InvalidShareCountMin(nb_shares: u8, min: u8) { 44 | description("Number of shares is too small") 45 | display("Number of shares must be larger than or equal {}, got: {} shares.", min, nb_shares) 46 | } 47 | 48 | EmptySecret { 49 | description("The secret cannot be empty") 50 | display("The secret cannot be empty") 51 | } 52 | 53 | EmptyShares { 54 | description("No shares provided") 55 | display("No shares were provided.") 56 | } 57 | 58 | IncompatibleSets(sets: Vec>) { 59 | description("The shares are incompatible with each other.") 60 | display("The shares are incompatible with each other.") 61 | } 62 | 63 | MissingShares(provided: usize, required: u8) { 64 | description("The number of shares provided is insufficient to recover the secret.") 65 | display("{} shares are required to recover the secret, found only {}.", required, provided) 66 | } 67 | 68 | InvalidSignature(share_id: u8, signature: String) { 69 | description("The signature of this share is not valid.") 70 | } 71 | 72 | MissingSignature(share_id: u8) { 73 | description("Signature is missing while shares are required to be signed.") 74 | } 75 | 76 | SecretDeserializationError { 77 | description("An issue was encountered deserializing the secret. \ 78 | Updating to the latest version of RustySecrets might help fix this.") 79 | } 80 | 81 | ShareParsingError(reason: String) { 82 | description("This share is incorrectly formatted.") 83 | display("This share is incorrectly formatted. Reason: {}", reason) 84 | } 85 | 86 | ShareParsingErrorEmptyShare(share_id: u8) { 87 | description("This share is empty.") 88 | display("Found empty share for share identifier ({})", share_id) 89 | } 90 | 91 | ShareParsingInvalidShareId(share_id: u8) { 92 | description("Invalid share identifier.") 93 | display("Found invalid share identifier ({})", share_id) 94 | } 95 | 96 | ShareParsingInvalidShareThreshold(k: u8, id: u8) { 97 | description("Threshold k must be bigger than or equal to 2") 98 | display("Threshold k must be bigger than or equal to 2. Got k = {} for share identifier {}.", k, id) 99 | } 100 | 101 | InvalidSS1Parameters(r: usize, s: usize) { 102 | description("Invalid parameters for the SS1 sharing scheme") 103 | display("Invalid parameters for the SS1 sharing scheme: r = {}, s = {}.", r, s) 104 | } 105 | 106 | InvalidSplitParametersZero(k: u8, n: u8) { 107 | description("Parameters k and n must be greater than zero") 108 | display("Parameters k and n must be greater than zero.") 109 | } 110 | 111 | #[cfg(feature = "dss")] 112 | MismatchingShares(got: ss1::Share, expected: ss1::Share) { 113 | description("Share mismatch during verification of secret recovery") 114 | display("Share mismatch during verification of secret recovery.") 115 | } 116 | 117 | CannotGenerateRandomNumbers { 118 | description("Cannot generate random numbers") 119 | display("Cannot generate random numbers.") 120 | } 121 | 122 | DuplicateShareId(share_id: u8) { 123 | description("This share number has already been used by a previous share.") 124 | display("This share number ({}) has already been used by a previous share.", share_id) 125 | } 126 | 127 | InconsistentSecretLengths(id: u8, slen_: usize, ids: Vec, slen: usize) { 128 | description("The shares are incompatible with each other because they do not all have the same secret length.") 129 | display("The share identifier {} had secret length {}, while the secret length {} was found for share identifier(s): {}.", id, slen_, slen, no_more_than_five(ids)) 130 | } 131 | 132 | InconsistentShares { 133 | description("The shares are inconsistent") 134 | display("The shares are inconsistent") 135 | } 136 | 137 | InconsistentThresholds(id: u8, k_: u8, ids: Vec, k: u8) { 138 | description("The shares are incompatible with each other because they do not all have the same threshold.") 139 | display("The share identifier {} had k = {}, while k = {} was found for share identifier(s): {}.", id, k_, k, no_more_than_five(ids)) 140 | } 141 | 142 | } 143 | 144 | foreign_links { 145 | Io(::std::io::Error); 146 | IntegerParsingError(::std::num::ParseIntError); 147 | } 148 | } 149 | 150 | /// Takes a `Vec` and formats it like the normal `fmt::Debug` implementation, unless it has more 151 | //than five elements, in which case the rest are replaced by ellipsis. 152 | fn no_more_than_five(vec: &Vec) -> String { 153 | let len = vec.len(); 154 | if len > 5 { 155 | let mut string = String::from("["); 156 | for item in vec.iter().take(5) { 157 | string += &format!("{}, ", item); 158 | } 159 | string.push_str("...]"); 160 | string 161 | } else { 162 | format!("{:?}", vec) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/gf256.rs: -------------------------------------------------------------------------------- 1 | //! This module provides the Gf256 type which is used to represent 2 | //! elements of a finite field with 256 elements. 3 | 4 | use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; 5 | 6 | include!(concat!(env!("OUT_DIR"), "/nothinghardcoded.rs")); 7 | 8 | fn get_tables() -> &'static Tables { 9 | &TABLES 10 | } 11 | 12 | /// Type for elements of a finite field with 256 elements 13 | #[derive(Copy, Debug, Clone, PartialEq, Eq)] 14 | pub struct Gf256 { 15 | pub poly: u8, 16 | } 17 | 18 | impl Gf256 { 19 | /// returns the additive neutral element of the field 20 | #[inline] 21 | pub fn zero() -> Gf256 { 22 | Gf256 { poly: 0 } 23 | } 24 | /// returns the multiplicative neutral element of the field 25 | #[inline] 26 | pub fn one() -> Gf256 { 27 | Gf256 { poly: 1 } 28 | } 29 | #[inline] 30 | pub fn from_byte(b: u8) -> Gf256 { 31 | Gf256 { poly: b } 32 | } 33 | #[inline] 34 | pub fn to_byte(&self) -> u8 { 35 | self.poly 36 | } 37 | pub fn exp(power: u8) -> Gf256 { 38 | let tabs = get_tables(); 39 | Gf256::from_byte(tabs.exp[power as usize]) 40 | } 41 | pub fn log(&self) -> Option { 42 | if self.poly == 0 { 43 | None 44 | } else { 45 | let tabs = get_tables(); 46 | Some(tabs.log[self.poly as usize]) 47 | } 48 | } 49 | pub fn pow(&self, mut exp: u8) -> Gf256 { 50 | let mut base = *self; 51 | let mut acc = Self::one(); 52 | 53 | while exp > 1 { 54 | if (exp & 1) == 1 { 55 | acc = acc * base; 56 | } 57 | exp /= 2; 58 | base = base * base; 59 | } 60 | 61 | if exp == 1 { 62 | acc = acc * base; 63 | } 64 | 65 | acc 66 | } 67 | } 68 | 69 | impl Add for Gf256 { 70 | type Output = Gf256; 71 | #[inline] 72 | fn add(self, rhs: Gf256) -> Gf256 { 73 | Gf256::from_byte(self.poly ^ rhs.poly) 74 | } 75 | } 76 | 77 | impl AddAssign for Gf256 { 78 | #[inline] 79 | fn add_assign(&mut self, rhs: Gf256) { 80 | *self = *self + rhs; 81 | } 82 | } 83 | 84 | impl Sub for Gf256 { 85 | type Output = Gf256; 86 | #[inline] 87 | fn sub(self, rhs: Gf256) -> Gf256 { 88 | Gf256::from_byte(self.poly ^ rhs.poly) 89 | } 90 | } 91 | 92 | impl SubAssign for Gf256 { 93 | #[inline] 94 | fn sub_assign(&mut self, rhs: Gf256) { 95 | *self = *self - rhs; 96 | } 97 | } 98 | 99 | impl Mul for Gf256 { 100 | type Output = Gf256; 101 | fn mul(self, rhs: Gf256) -> Gf256 { 102 | if let (Some(l1), Some(l2)) = (self.log(), rhs.log()) { 103 | let tmp = (u16::from(l1) + u16::from(l2)) % 255; 104 | Gf256::exp(tmp as u8) 105 | } else { 106 | Gf256 { poly: 0 } 107 | } 108 | } 109 | } 110 | 111 | impl MulAssign for Gf256 { 112 | fn mul_assign(&mut self, rhs: Gf256) { 113 | *self = *self * rhs; 114 | } 115 | } 116 | 117 | impl Div for Gf256 { 118 | type Output = Gf256; 119 | fn div(self, rhs: Gf256) -> Gf256 { 120 | let l2 = rhs.log().expect("division by zero"); 121 | if let Some(l1) = self.log() { 122 | let tmp = (u16::from(l1) + 255 - u16::from(l2)) % 255; 123 | Gf256::exp(tmp as u8) 124 | } else { 125 | Gf256 { poly: 0 } 126 | } 127 | } 128 | } 129 | 130 | impl DivAssign for Gf256 { 131 | fn div_assign(&mut self, rhs: Gf256) { 132 | *self = *self / rhs; 133 | } 134 | } 135 | 136 | impl Neg for Gf256 { 137 | type Output = Gf256; 138 | fn neg(self) -> Gf256 { 139 | Gf256::zero() - self 140 | } 141 | } 142 | 143 | #[macro_export] 144 | #[doc(hidden)] 145 | macro_rules! gf256 { 146 | ($e:expr) => { 147 | Gf256::from_byte($e) 148 | }; 149 | } 150 | 151 | #[macro_export] 152 | #[doc(hidden)] 153 | macro_rules! gf256_vec { 154 | ( $( ($x:expr, $y:expr) ),* ) => { 155 | { 156 | let mut temp_vec = Vec::new(); 157 | $( 158 | temp_vec.push((Gf256::from_byte($x), Gf256::from_byte($y))); 159 | )* 160 | temp_vec 161 | } 162 | }; 163 | ( $( $x:expr ),* ) => { 164 | { 165 | let mut temp_vec = Vec::new(); 166 | $( 167 | temp_vec.push(Gf256::from_byte($x)); 168 | )* 169 | temp_vec 170 | } 171 | }; 172 | } 173 | 174 | #[cfg(test)] 175 | #[allow(trivial_casts)] 176 | mod tests { 177 | 178 | use super::*; 179 | use quickcheck::*; 180 | 181 | mod vectors { 182 | use super::*; 183 | use flate2::read::GzDecoder; 184 | use itertools::Itertools; 185 | use std::fs::File; 186 | use std::io::{BufRead, BufReader}; 187 | 188 | macro_rules! mk_test { 189 | ($id:ident, $op:expr, $val:expr) => { 190 | mk_test!($id, $op, $val, 0); 191 | }; 192 | ($id:ident, $op:expr, $val:expr, $y:expr) => { 193 | #[test] 194 | fn $id() { 195 | let results = (0..256).cartesian_product($y..256).map(|(i, j)| { 196 | let (i, j) = (Gf256::from_byte(i as u8), Gf256::from_byte(j as u8)); 197 | (i.to_byte(), j.to_byte(), $val(i, j).to_byte()) 198 | }); 199 | 200 | let ref_path = format!("tests/fixtures/gf256/gf256_{}.txt.gz", stringify!($id)); 201 | let reference = 202 | BufReader::new(GzDecoder::new(File::open(ref_path).unwrap()).unwrap()); 203 | 204 | for ((i, j, k), line) in results.zip(reference.lines()) { 205 | let left = format!("{} {} {} = {}", i, $op, j, k); 206 | let right = line.unwrap(); 207 | assert_eq!(left, right); 208 | } 209 | } 210 | }; 211 | } 212 | 213 | mk_test!(add, "+", |i: Gf256, j: Gf256| i + j); 214 | mk_test!(sub, "-", |i: Gf256, j: Gf256| i - j); 215 | mk_test!(mul, "*", |i: Gf256, j: Gf256| i * j); 216 | mk_test!(div, "/", |i: Gf256, j: Gf256| i.div(j), 1); 217 | mk_test!(pow, "^", |i: Gf256, j: Gf256| i.pow(j.to_byte())); 218 | } 219 | 220 | impl Arbitrary for Gf256 { 221 | fn arbitrary(gen: &mut G) -> Gf256 { 222 | Gf256::from_byte(u8::arbitrary(gen)) 223 | } 224 | } 225 | 226 | mod addition { 227 | use super::*; 228 | 229 | quickcheck! { 230 | fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool { 231 | (a + b) + c == a + (b + c) 232 | } 233 | 234 | fn law_commutativity(a: Gf256, b: Gf256) -> bool { 235 | a + b == b + a 236 | } 237 | 238 | fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool { 239 | a * (b + c) == a * b + a * c 240 | } 241 | 242 | fn law_identity(a: Gf256) -> bool { 243 | a + Gf256::zero() == a && Gf256::zero() + a == a 244 | } 245 | 246 | fn law_inverses(a: Gf256) -> bool { 247 | a + (-a) == Gf256::zero() && (-a) + a == Gf256::zero() 248 | } 249 | } 250 | } 251 | 252 | mod multiplication { 253 | use super::*; 254 | 255 | quickcheck! { 256 | fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool { 257 | (a * b) * c == a * (b * c) 258 | } 259 | 260 | fn law_commutativity(a: Gf256, b: Gf256) -> bool { 261 | a * b == b * a 262 | } 263 | 264 | fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool { 265 | (a + b) * c == a * c + b * c 266 | } 267 | 268 | fn law_identity(a: Gf256) -> bool { 269 | a * Gf256::one() == a && Gf256::one() * a == a 270 | } 271 | 272 | fn law_inverses(a: Gf256) -> TestResult { 273 | if a == Gf256::zero() { 274 | return TestResult::discard(); 275 | } 276 | 277 | let left = a * (Gf256::one() / a) == Gf256::one(); 278 | let right = (Gf256::one() / a) * a == Gf256::one(); 279 | 280 | TestResult::from_bool(left && right) 281 | } 282 | } 283 | 284 | } 285 | 286 | } 287 | -------------------------------------------------------------------------------- /src/lagrange.rs: -------------------------------------------------------------------------------- 1 | use gf256::Gf256; 2 | use poly::Poly; 3 | 4 | /// Evaluates an interpolated polynomial at `Gf256::zero()` where 5 | /// the polynomial is determined using barycentric Lagrange 6 | /// interpolation based on the given `points` in 7 | /// the G(2^8) Galois field. 8 | pub(crate) fn interpolate_at(k: u8, points: &[(u8, u8)]) -> u8 { 9 | barycentric_interpolate_at(k as usize, points) 10 | } 11 | 12 | /// Barycentric Lagrange interpolation algorithm from "Polynomial 13 | /// Interpolation: Langrange vs Newton" by Wilhelm Werner. Evaluates 14 | /// the polynomial at `Gf256::zero()`. 15 | #[inline] 16 | fn barycentric_interpolate_at(k: usize, points: &[(u8, u8)]) -> u8 { 17 | // Compute the barycentric weights `w`. 18 | let mut w = vec![Gf256::zero(); k]; 19 | w[0] = Gf256::one(); 20 | 21 | let mut x = Vec::with_capacity(k); 22 | x.push(Gf256::from_byte(points[0].0)); 23 | 24 | for i in 1..k { 25 | x.push(Gf256::from_byte(points[i].0)); 26 | for j in 0..i { 27 | let delta = x[j] - x[i]; 28 | assert_ne!(delta.poly, 0, "Duplicate shares"); 29 | w[j] /= delta; 30 | w[i] -= w[j]; 31 | } 32 | } 33 | 34 | // Evaluate the second or "true" form of the barycentric 35 | // interpolation formula at `Gf256::zero()`. 36 | let (mut num, mut denom) = (Gf256::zero(), Gf256::zero()); 37 | for i in 0..k { 38 | assert_ne!(x[i].poly, 0, "Invalid share x = 0"); 39 | let diff = w[i] / x[i]; 40 | num += diff * Gf256::from_byte(points[i].1); 41 | denom += diff; 42 | } 43 | 44 | (num / denom).to_byte() 45 | } 46 | 47 | /// Computeds the coefficient of the Lagrange polynomial interpolated 48 | /// from the given `points`, in the G(2^8) Galois field. 49 | pub(crate) fn interpolate(points: &[(Gf256, Gf256)]) -> Poly { 50 | let len = points.len(); 51 | 52 | let mut poly = vec![Gf256::zero(); len]; 53 | 54 | for &(x, y) in points { 55 | assert_ne!(x.poly, 0, "Invalid share x = 0"); 56 | let mut coeffs = vec![Gf256::zero(); len]; 57 | coeffs[0] = y; 58 | 59 | let mut prod = Gf256::one(); 60 | for &(x1, _) in points { 61 | if x != x1 { 62 | prod *= x - x1; 63 | 64 | let mut prec = Gf256::zero(); 65 | coeffs = coeffs 66 | .into_iter() 67 | .map(|coeff| { 68 | let new_coeff = coeff * (-x1) + prec; 69 | prec = coeff; 70 | new_coeff 71 | }) 72 | .collect(); 73 | } 74 | } 75 | 76 | poly = poly.iter() 77 | .zip(coeffs.iter()) 78 | .map(|(&old_coeff, &add)| old_coeff + add / prod) 79 | .collect(); 80 | } 81 | 82 | Poly::new(poly) 83 | } 84 | 85 | #[cfg(test)] 86 | #[allow(trivial_casts)] 87 | mod tests { 88 | 89 | use super::*; 90 | use gf256::*; 91 | use quickcheck::*; 92 | use std; 93 | 94 | quickcheck! { 95 | 96 | fn interpolate_evaluate_at_works(ys: Vec) -> TestResult { 97 | if ys.is_empty() || ys.len() > std::u8::MAX as usize { 98 | return TestResult::discard(); 99 | } 100 | 101 | let points = ys.into_iter() 102 | .zip(1..std::u8::MAX) 103 | .map(|(y, x)| (gf256!(x), y)) 104 | .collect::>(); 105 | let poly = interpolate(&points); 106 | 107 | for (x, y) in points { 108 | if poly.evaluate_at(x) != y { 109 | return TestResult::failed(); 110 | } 111 | } 112 | 113 | TestResult::passed() 114 | } 115 | 116 | fn interpolate_evaluate_at_0_eq_evaluate_at(ys: Vec) -> TestResult { 117 | if ys.is_empty() || ys.len() > std::u8::MAX as usize { 118 | return TestResult::discard(); 119 | } 120 | 121 | let points = ys.into_iter() 122 | .zip(1..std::u8::MAX) 123 | .map(|(y, x)| (x, y)) 124 | .collect::>(); 125 | 126 | let elems = points 127 | .iter() 128 | .map(|&(x, y)| (gf256!(x), gf256!(y))) 129 | .collect::>(); 130 | 131 | let poly = interpolate(&elems); 132 | 133 | let equals = poly.evaluate_at(Gf256::zero()).to_byte() 134 | == interpolate_at(points.len() as u8, points.as_slice()); 135 | 136 | TestResult::from_bool(equals) 137 | } 138 | 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `RustySecrets` implements Shamir's secret sharing in Rust. It provides the possibility to sign shares. 2 | 3 | #![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, 4 | trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, 5 | unused_qualifications)] 6 | #![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))] 7 | // `error_chain!` can recurse deeply 8 | #![recursion_limit = "1024"] 9 | 10 | #[macro_use] 11 | extern crate error_chain; 12 | 13 | extern crate base64; 14 | extern crate merkle_sigs; 15 | extern crate protobuf; 16 | extern crate rand; 17 | extern crate ring; 18 | 19 | #[macro_use] 20 | mod gf256; 21 | mod lagrange; 22 | mod poly; 23 | mod share; 24 | mod vol_hash; 25 | 26 | pub mod errors; 27 | pub mod proto; 28 | pub mod sss; 29 | pub mod wrapped_secrets; 30 | 31 | #[cfg(feature = "dss")] 32 | pub mod dss; 33 | 34 | #[cfg(test)] 35 | extern crate itertools; 36 | 37 | #[cfg(test)] 38 | extern crate flate2; 39 | 40 | #[cfg(test)] 41 | #[macro_use] 42 | extern crate quickcheck; 43 | -------------------------------------------------------------------------------- /src/poly.rs: -------------------------------------------------------------------------------- 1 | use gf256::Gf256; 2 | 3 | static MAX_COEFFS: usize = 256; 4 | 5 | pub(crate) struct Poly { 6 | pub coeffs: Vec, 7 | } 8 | 9 | impl Poly { 10 | pub fn new(coeffs: Vec) -> Self { 11 | Self { coeffs } 12 | } 13 | 14 | pub fn evaluate_at_zero(&self) -> Gf256 { 15 | self.coeffs[0] 16 | } 17 | 18 | pub fn evaluate_at(&self, x: Gf256) -> Gf256 { 19 | assert!(self.coeffs.len() < MAX_COEFFS); 20 | 21 | let mut result = Gf256::zero(); 22 | 23 | for (i, c) in self.coeffs.iter().enumerate() { 24 | result += *c * x.pow(i as u8); 25 | } 26 | 27 | result 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/proto/dss/metadata.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | 21 | use protobuf::Message as Message_imported_for_functions; 22 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 23 | 24 | #[derive(PartialEq, Clone, Default)] 25 | pub struct MetaDataProto { 26 | // message fields 27 | pub tags: ::std::collections::HashMap<::std::string::String, ::std::string::String>, 28 | // special fields 29 | unknown_fields: ::protobuf::UnknownFields, 30 | cached_size: ::protobuf::CachedSize, 31 | } 32 | 33 | // see codegen.rs for the explanation why impl Sync explicitly 34 | unsafe impl ::std::marker::Sync for MetaDataProto {} 35 | 36 | impl MetaDataProto { 37 | pub fn new() -> MetaDataProto { 38 | ::std::default::Default::default() 39 | } 40 | 41 | pub fn default_instance() -> &'static MetaDataProto { 42 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { 43 | lock: ::protobuf::lazy::ONCE_INIT, 44 | ptr: 0 as *const MetaDataProto, 45 | }; 46 | unsafe { instance.get(MetaDataProto::new) } 47 | } 48 | 49 | // repeated .dss.MetaDataProto.TagsEntry tags = 1; 50 | 51 | pub fn clear_tags(&mut self) { 52 | self.tags.clear(); 53 | } 54 | 55 | // Param is passed by value, moved 56 | pub fn set_tags( 57 | &mut self, 58 | v: ::std::collections::HashMap<::std::string::String, ::std::string::String>, 59 | ) { 60 | self.tags = v; 61 | } 62 | 63 | // Mutable pointer to the field. 64 | pub fn mut_tags( 65 | &mut self, 66 | ) -> &mut ::std::collections::HashMap<::std::string::String, ::std::string::String> { 67 | &mut self.tags 68 | } 69 | 70 | // Take field 71 | pub fn take_tags( 72 | &mut self, 73 | ) -> ::std::collections::HashMap<::std::string::String, ::std::string::String> { 74 | ::std::mem::replace(&mut self.tags, ::std::collections::HashMap::new()) 75 | } 76 | 77 | pub fn get_tags( 78 | &self, 79 | ) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> { 80 | &self.tags 81 | } 82 | 83 | fn get_tags_for_reflect( 84 | &self, 85 | ) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> { 86 | &self.tags 87 | } 88 | 89 | fn mut_tags_for_reflect( 90 | &mut self, 91 | ) -> &mut ::std::collections::HashMap<::std::string::String, ::std::string::String> { 92 | &mut self.tags 93 | } 94 | } 95 | 96 | impl ::protobuf::Message for MetaDataProto { 97 | fn is_initialized(&self) -> bool { 98 | true 99 | } 100 | 101 | fn merge_from( 102 | &mut self, 103 | is: &mut ::protobuf::CodedInputStream, 104 | ) -> ::protobuf::ProtobufResult<()> { 105 | while !is.eof()? { 106 | let (field_number, wire_type) = is.read_tag_unpack()?; 107 | match field_number { 108 | 1 => { 109 | ::protobuf::rt::read_map_into::< 110 | ::protobuf::types::ProtobufTypeString, 111 | ::protobuf::types::ProtobufTypeString, 112 | >(wire_type, is, &mut self.tags)?; 113 | } 114 | _ => { 115 | ::protobuf::rt::read_unknown_or_skip_group( 116 | field_number, 117 | wire_type, 118 | is, 119 | self.mut_unknown_fields(), 120 | )?; 121 | } 122 | }; 123 | } 124 | ::std::result::Result::Ok(()) 125 | } 126 | 127 | // Compute sizes of nested messages 128 | #[allow(unused_variables)] 129 | fn compute_size(&self) -> u32 { 130 | let mut my_size = 0; 131 | my_size += ::protobuf::rt::compute_map_size::< 132 | ::protobuf::types::ProtobufTypeString, 133 | ::protobuf::types::ProtobufTypeString, 134 | >(1, &self.tags); 135 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 136 | self.cached_size.set(my_size); 137 | my_size 138 | } 139 | 140 | fn write_to_with_cached_sizes( 141 | &self, 142 | os: &mut ::protobuf::CodedOutputStream, 143 | ) -> ::protobuf::ProtobufResult<()> { 144 | ::protobuf::rt::write_map_with_cached_sizes::< 145 | ::protobuf::types::ProtobufTypeString, 146 | ::protobuf::types::ProtobufTypeString, 147 | >(1, &self.tags, os)?; 148 | os.write_unknown_fields(self.get_unknown_fields())?; 149 | ::std::result::Result::Ok(()) 150 | } 151 | 152 | fn get_cached_size(&self) -> u32 { 153 | self.cached_size.get() 154 | } 155 | 156 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 157 | &self.unknown_fields 158 | } 159 | 160 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 161 | &mut self.unknown_fields 162 | } 163 | 164 | fn as_any(&self) -> &::std::any::Any { 165 | self as &::std::any::Any 166 | } 167 | fn as_any_mut(&mut self) -> &mut ::std::any::Any { 168 | self as &mut ::std::any::Any 169 | } 170 | fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { 171 | self 172 | } 173 | 174 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 175 | ::protobuf::MessageStatic::descriptor_static(None::) 176 | } 177 | } 178 | 179 | impl ::protobuf::MessageStatic for MetaDataProto { 180 | fn new() -> MetaDataProto { 181 | MetaDataProto::new() 182 | } 183 | 184 | fn descriptor_static( 185 | _: ::std::option::Option, 186 | ) -> &'static ::protobuf::reflect::MessageDescriptor { 187 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = 188 | ::protobuf::lazy::Lazy { 189 | lock: ::protobuf::lazy::ONCE_INIT, 190 | ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, 191 | }; 192 | unsafe { 193 | descriptor.get(|| { 194 | let mut fields = ::std::vec::Vec::new(); 195 | fields.push(::protobuf::reflect::accessor::make_map_accessor::<_, ::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>( 196 | "tags", 197 | MetaDataProto::get_tags_for_reflect, 198 | MetaDataProto::mut_tags_for_reflect, 199 | )); 200 | ::protobuf::reflect::MessageDescriptor::new::( 201 | "MetaDataProto", 202 | fields, 203 | file_descriptor_proto() 204 | ) 205 | }) 206 | } 207 | } 208 | } 209 | 210 | impl ::protobuf::Clear for MetaDataProto { 211 | fn clear(&mut self) { 212 | self.clear_tags(); 213 | self.unknown_fields.clear(); 214 | } 215 | } 216 | 217 | impl ::std::fmt::Debug for MetaDataProto { 218 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 219 | ::protobuf::text_format::fmt(self, f) 220 | } 221 | } 222 | 223 | impl ::protobuf::reflect::ProtobufValue for MetaDataProto { 224 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 225 | ::protobuf::reflect::ProtobufValueRef::Message(self) 226 | } 227 | } 228 | 229 | static file_descriptor_proto_data: &'static [u8] = b"\ 230 | \n\x12dss/metadata.proto\x12\x03dss\"z\n\rMetaDataProto\x120\n\x04tags\ 231 | \x18\x01\x20\x03(\x0b2\x1c.dss.MetaDataProto.TagsEntryR\x04tags\x1a7\n\t\ 232 | TagsEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x14\n\x05value\ 233 | \x18\x02\x20\x01(\tR\x05value:\x028\x01Jz\n\x06\x12\x04\0\0\x06\x01\n\ 234 | \x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0b\n\n\n\ 235 | \x02\x04\0\x12\x04\x04\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\x08\x15\ 236 | \n\x0b\n\x04\x04\0\x02\0\x12\x03\x05\x02\x1f\n\r\n\x05\x04\0\x02\0\x04\ 237 | \x12\x04\x05\x02\x04\x17\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x05\x02\x15\ 238 | \n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x05\x16\x1a\n\x0c\n\x05\x04\0\x02\0\ 239 | \x03\x12\x03\x05\x1d\x1eb\x06proto3\ 240 | "; 241 | 242 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 243 | lock: ::protobuf::lazy::ONCE_INIT, 244 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 245 | }; 246 | 247 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 248 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 249 | } 250 | 251 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 252 | unsafe { file_descriptor_proto_lazy.get(|| parse_descriptor_proto()) } 253 | } 254 | -------------------------------------------------------------------------------- /src/proto/dss/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_qualifications, deprecated, missing_docs)] 2 | mod secret; 3 | pub use self::secret::SecretProto; 4 | 5 | #[allow(unused_qualifications, deprecated, missing_docs)] 6 | mod share; 7 | pub use self::share::ShareProto; 8 | 9 | #[allow(unused_qualifications, deprecated, missing_docs)] 10 | mod metadata; 11 | pub use self::metadata::MetaDataProto; 12 | 13 | use super::version; 14 | -------------------------------------------------------------------------------- /src/proto/dss/secret.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | 21 | use protobuf::Message as Message_imported_for_functions; 22 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 23 | 24 | #[derive(PartialEq, Clone, Default)] 25 | pub struct SecretProto { 26 | // message fields 27 | pub version: super::version::VersionProto, 28 | pub secret: ::std::vec::Vec, 29 | pub meta_data: ::protobuf::SingularPtrField, 30 | // special fields 31 | unknown_fields: ::protobuf::UnknownFields, 32 | cached_size: ::protobuf::CachedSize, 33 | } 34 | 35 | // see codegen.rs for the explanation why impl Sync explicitly 36 | unsafe impl ::std::marker::Sync for SecretProto {} 37 | 38 | impl SecretProto { 39 | pub fn new() -> SecretProto { 40 | ::std::default::Default::default() 41 | } 42 | 43 | pub fn default_instance() -> &'static SecretProto { 44 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { 45 | lock: ::protobuf::lazy::ONCE_INIT, 46 | ptr: 0 as *const SecretProto, 47 | }; 48 | unsafe { instance.get(SecretProto::new) } 49 | } 50 | 51 | // .VersionProto version = 1; 52 | 53 | pub fn clear_version(&mut self) { 54 | self.version = super::version::VersionProto::INITIAL_RELEASE; 55 | } 56 | 57 | // Param is passed by value, moved 58 | pub fn set_version(&mut self, v: super::version::VersionProto) { 59 | self.version = v; 60 | } 61 | 62 | pub fn get_version(&self) -> super::version::VersionProto { 63 | self.version 64 | } 65 | 66 | fn get_version_for_reflect(&self) -> &super::version::VersionProto { 67 | &self.version 68 | } 69 | 70 | fn mut_version_for_reflect(&mut self) -> &mut super::version::VersionProto { 71 | &mut self.version 72 | } 73 | 74 | // bytes secret = 2; 75 | 76 | pub fn clear_secret(&mut self) { 77 | self.secret.clear(); 78 | } 79 | 80 | // Param is passed by value, moved 81 | pub fn set_secret(&mut self, v: ::std::vec::Vec) { 82 | self.secret = v; 83 | } 84 | 85 | // Mutable pointer to the field. 86 | // If field is not initialized, it is initialized with default value first. 87 | pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { 88 | &mut self.secret 89 | } 90 | 91 | // Take field 92 | pub fn take_secret(&mut self) -> ::std::vec::Vec { 93 | ::std::mem::replace(&mut self.secret, ::std::vec::Vec::new()) 94 | } 95 | 96 | pub fn get_secret(&self) -> &[u8] { 97 | &self.secret 98 | } 99 | 100 | fn get_secret_for_reflect(&self) -> &::std::vec::Vec { 101 | &self.secret 102 | } 103 | 104 | fn mut_secret_for_reflect(&mut self) -> &mut ::std::vec::Vec { 105 | &mut self.secret 106 | } 107 | 108 | // .dss.MetaDataProto meta_data = 3; 109 | 110 | pub fn clear_meta_data(&mut self) { 111 | self.meta_data.clear(); 112 | } 113 | 114 | pub fn has_meta_data(&self) -> bool { 115 | self.meta_data.is_some() 116 | } 117 | 118 | // Param is passed by value, moved 119 | pub fn set_meta_data(&mut self, v: super::metadata::MetaDataProto) { 120 | self.meta_data = ::protobuf::SingularPtrField::some(v); 121 | } 122 | 123 | // Mutable pointer to the field. 124 | // If field is not initialized, it is initialized with default value first. 125 | pub fn mut_meta_data(&mut self) -> &mut super::metadata::MetaDataProto { 126 | if self.meta_data.is_none() { 127 | self.meta_data.set_default(); 128 | } 129 | self.meta_data.as_mut().unwrap() 130 | } 131 | 132 | // Take field 133 | pub fn take_meta_data(&mut self) -> super::metadata::MetaDataProto { 134 | self.meta_data.take().unwrap_or_else(|| { 135 | super::metadata::MetaDataProto::new() 136 | }) 137 | } 138 | 139 | pub fn get_meta_data(&self) -> &super::metadata::MetaDataProto { 140 | self.meta_data.as_ref().unwrap_or_else(|| { 141 | super::metadata::MetaDataProto::default_instance() 142 | }) 143 | } 144 | 145 | fn get_meta_data_for_reflect( 146 | &self, 147 | ) -> &::protobuf::SingularPtrField { 148 | &self.meta_data 149 | } 150 | 151 | fn mut_meta_data_for_reflect( 152 | &mut self, 153 | ) -> &mut ::protobuf::SingularPtrField { 154 | &mut self.meta_data 155 | } 156 | } 157 | 158 | impl ::protobuf::Message for SecretProto { 159 | fn is_initialized(&self) -> bool { 160 | for v in &self.meta_data { 161 | if !v.is_initialized() { 162 | return false; 163 | } 164 | } 165 | true 166 | } 167 | 168 | fn merge_from( 169 | &mut self, 170 | is: &mut ::protobuf::CodedInputStream, 171 | ) -> ::protobuf::ProtobufResult<()> { 172 | while !is.eof()? { 173 | let (field_number, wire_type) = is.read_tag_unpack()?; 174 | match field_number { 175 | 1 => { 176 | if wire_type != ::protobuf::wire_format::WireTypeVarint { 177 | return ::std::result::Result::Err( 178 | ::protobuf::rt::unexpected_wire_type(wire_type), 179 | ); 180 | } 181 | let tmp = is.read_enum()?; 182 | self.version = tmp; 183 | } 184 | 2 => { 185 | ::protobuf::rt::read_singular_proto3_bytes_into( 186 | wire_type, 187 | is, 188 | &mut self.secret, 189 | )?; 190 | } 191 | 3 => { 192 | ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.meta_data)?; 193 | } 194 | _ => { 195 | ::protobuf::rt::read_unknown_or_skip_group( 196 | field_number, 197 | wire_type, 198 | is, 199 | self.mut_unknown_fields(), 200 | )?; 201 | } 202 | }; 203 | } 204 | ::std::result::Result::Ok(()) 205 | } 206 | 207 | // Compute sizes of nested messages 208 | #[allow(unused_variables)] 209 | fn compute_size(&self) -> u32 { 210 | let mut my_size = 0; 211 | if self.version != super::version::VersionProto::INITIAL_RELEASE { 212 | my_size += ::protobuf::rt::enum_size(1, self.version); 213 | } 214 | if !self.secret.is_empty() { 215 | my_size += ::protobuf::rt::bytes_size(2, &self.secret); 216 | } 217 | if let Some(ref v) = self.meta_data.as_ref() { 218 | let len = v.compute_size(); 219 | my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; 220 | } 221 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 222 | self.cached_size.set(my_size); 223 | my_size 224 | } 225 | 226 | fn write_to_with_cached_sizes( 227 | &self, 228 | os: &mut ::protobuf::CodedOutputStream, 229 | ) -> ::protobuf::ProtobufResult<()> { 230 | if self.version != super::version::VersionProto::INITIAL_RELEASE { 231 | os.write_enum(1, self.version.value())?; 232 | } 233 | if !self.secret.is_empty() { 234 | os.write_bytes(2, &self.secret)?; 235 | } 236 | if let Some(ref v) = self.meta_data.as_ref() { 237 | os.write_tag( 238 | 3, 239 | ::protobuf::wire_format::WireTypeLengthDelimited, 240 | )?; 241 | os.write_raw_varint32(v.get_cached_size())?; 242 | v.write_to_with_cached_sizes(os)?; 243 | } 244 | os.write_unknown_fields(self.get_unknown_fields())?; 245 | ::std::result::Result::Ok(()) 246 | } 247 | 248 | fn get_cached_size(&self) -> u32 { 249 | self.cached_size.get() 250 | } 251 | 252 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 253 | &self.unknown_fields 254 | } 255 | 256 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 257 | &mut self.unknown_fields 258 | } 259 | 260 | fn as_any(&self) -> &::std::any::Any { 261 | self as &::std::any::Any 262 | } 263 | fn as_any_mut(&mut self) -> &mut ::std::any::Any { 264 | self as &mut ::std::any::Any 265 | } 266 | fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { 267 | self 268 | } 269 | 270 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 271 | ::protobuf::MessageStatic::descriptor_static(None::) 272 | } 273 | } 274 | 275 | impl ::protobuf::MessageStatic for SecretProto { 276 | fn new() -> SecretProto { 277 | SecretProto::new() 278 | } 279 | 280 | fn descriptor_static( 281 | _: ::std::option::Option, 282 | ) -> &'static ::protobuf::reflect::MessageDescriptor { 283 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = 284 | ::protobuf::lazy::Lazy { 285 | lock: ::protobuf::lazy::ONCE_INIT, 286 | ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, 287 | }; 288 | unsafe { 289 | descriptor.get(|| { 290 | let mut fields = ::std::vec::Vec::new(); 291 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( 292 | "version", 293 | SecretProto::get_version_for_reflect, 294 | SecretProto::mut_version_for_reflect, 295 | )); 296 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( 297 | "secret", 298 | SecretProto::get_secret_for_reflect, 299 | SecretProto::mut_secret_for_reflect, 300 | )); 301 | fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( 302 | "meta_data", 303 | SecretProto::get_meta_data_for_reflect, 304 | SecretProto::mut_meta_data_for_reflect, 305 | )); 306 | ::protobuf::reflect::MessageDescriptor::new::( 307 | "SecretProto", 308 | fields, 309 | file_descriptor_proto() 310 | ) 311 | }) 312 | } 313 | } 314 | } 315 | 316 | impl ::protobuf::Clear for SecretProto { 317 | fn clear(&mut self) { 318 | self.clear_version(); 319 | self.clear_secret(); 320 | self.clear_meta_data(); 321 | self.unknown_fields.clear(); 322 | } 323 | } 324 | 325 | impl ::std::fmt::Debug for SecretProto { 326 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 327 | ::protobuf::text_format::fmt(self, f) 328 | } 329 | } 330 | 331 | impl ::protobuf::reflect::ProtobufValue for SecretProto { 332 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 333 | ::protobuf::reflect::ProtobufValueRef::Message(self) 334 | } 335 | } 336 | 337 | static file_descriptor_proto_data: &'static [u8] = b"\ 338 | \n\x10dss/secret.proto\x1a\rversion.proto\x1a\x12dss/metadata.proto\"\ 339 | \x7f\n\x0bSecretProto\x12'\n\x07version\x18\x01\x20\x01(\x0e2\r.VersionP\ 340 | rotoR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x0cR\x06secret\x12\ 341 | /\n\tmeta_data\x18\x03\x20\x01(\x0b2\x12.dss.MetaDataProtoR\x08metaDataJ\ 342 | \x92\x02\n\x06\x12\x04\0\0\t\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\ 343 | \x02\x03\0\x12\x03\x02\x07\x16\n\t\n\x02\x03\x01\x12\x03\x03\x07\x1b\n\n\ 344 | \n\x02\x04\0\x12\x04\x05\0\t\x01\n\n\n\x03\x04\0\x01\x12\x03\x05\x08\x13\ 345 | \n\x0b\n\x04\x04\0\x02\0\x12\x03\x06\x08!\n\r\n\x05\x04\0\x02\0\x04\x12\ 346 | \x04\x06\x08\x05\x15\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x06\x08\x14\n\ 347 | \x0c\n\x05\x04\0\x02\0\x01\x12\x03\x06\x15\x1c\n\x0c\n\x05\x04\0\x02\0\ 348 | \x03\x12\x03\x06\x1f\x20\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x07\x08\x19\n\ 349 | \r\n\x05\x04\0\x02\x01\x04\x12\x04\x07\x08\x06!\n\x0c\n\x05\x04\0\x02\ 350 | \x01\x05\x12\x03\x07\x08\r\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x07\x0e\ 351 | \x14\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x07\x17\x18\n\x0b\n\x04\x04\0\ 352 | \x02\x02\x12\x03\x08\x08(\n\r\n\x05\x04\0\x02\x02\x04\x12\x04\x08\x08\ 353 | \x07\x19\n\x0c\n\x05\x04\0\x02\x02\x06\x12\x03\x08\x08\x19\n\x0c\n\x05\ 354 | \x04\0\x02\x02\x01\x12\x03\x08\x1a#\n\x0c\n\x05\x04\0\x02\x02\x03\x12\ 355 | \x03\x08&'b\x06proto3\ 356 | "; 357 | 358 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 359 | lock: ::protobuf::lazy::ONCE_INIT, 360 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 361 | }; 362 | 363 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 364 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 365 | } 366 | 367 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 368 | unsafe { file_descriptor_proto_lazy.get(|| parse_descriptor_proto()) } 369 | } 370 | -------------------------------------------------------------------------------- /src/proto/mod.rs: -------------------------------------------------------------------------------- 1 | //! Protocol buffer definitions. 2 | 3 | #[allow(unused_qualifications, deprecated, missing_docs)] 4 | pub mod wrapped; 5 | 6 | #[cfg(feature = "dss")] 7 | #[allow(unused_qualifications, deprecated, missing_docs)] 8 | pub mod dss; 9 | 10 | #[allow(unused_qualifications, deprecated, missing_docs)] 11 | mod version; 12 | 13 | pub use self::version::VersionProto; 14 | -------------------------------------------------------------------------------- /src/proto/version.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | 21 | use protobuf::Message as Message_imported_for_functions; 22 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 23 | 24 | #[derive(Clone,PartialEq,Eq,Debug,Hash)] 25 | pub enum VersionProto { 26 | INITIAL_RELEASE = 0, 27 | } 28 | 29 | impl ::protobuf::ProtobufEnum for VersionProto { 30 | fn value(&self) -> i32 { 31 | *self as i32 32 | } 33 | 34 | fn from_i32(value: i32) -> ::std::option::Option { 35 | match value { 36 | 0 => ::std::option::Option::Some(VersionProto::INITIAL_RELEASE), 37 | _ => ::std::option::Option::None 38 | } 39 | } 40 | 41 | fn values() -> &'static [Self] { 42 | static values: &'static [VersionProto] = &[ 43 | VersionProto::INITIAL_RELEASE, 44 | ]; 45 | values 46 | } 47 | 48 | fn enum_descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::EnumDescriptor { 49 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { 50 | lock: ::protobuf::lazy::ONCE_INIT, 51 | ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, 52 | }; 53 | unsafe { 54 | descriptor.get(|| { 55 | ::protobuf::reflect::EnumDescriptor::new("VersionProto", file_descriptor_proto()) 56 | }) 57 | } 58 | } 59 | } 60 | 61 | impl ::std::marker::Copy for VersionProto { 62 | } 63 | 64 | impl ::std::default::Default for VersionProto { 65 | fn default() -> Self { 66 | VersionProto::INITIAL_RELEASE 67 | } 68 | } 69 | 70 | impl ::protobuf::reflect::ProtobufValue for VersionProto { 71 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 72 | ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) 73 | } 74 | } 75 | 76 | static file_descriptor_proto_data: &'static [u8] = b"\ 77 | \n\rversion.proto*#\n\x0cVersionProto\x12\x13\n\x0fINITIAL_RELEASE\x10\0\ 78 | JS\n\x06\x12\x04\x01\0\x05\x01\n\x08\n\x01\x0c\x12\x03\x01\0\x12\n\n\n\ 79 | \x02\x05\0\x12\x04\x03\0\x05\x01\n\n\n\x03\x05\0\x01\x12\x03\x03\x05\x11\ 80 | \n\x0b\n\x04\x05\0\x02\0\x12\x03\x04\x02\x16\n\x0c\n\x05\x05\0\x02\0\x01\ 81 | \x12\x03\x04\x02\x11\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x04\x14\x15b\ 82 | \x06proto3\ 83 | "; 84 | 85 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 86 | lock: ::protobuf::lazy::ONCE_INIT, 87 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 88 | }; 89 | 90 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 91 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 92 | } 93 | 94 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 95 | unsafe { 96 | file_descriptor_proto_lazy.get(|| { 97 | parse_descriptor_proto() 98 | }) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/proto/wrapped/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_qualifications, deprecated, missing_docs)] 2 | mod secret; 3 | pub use self::secret::SecretProto; 4 | 5 | #[allow(unused_qualifications, deprecated, missing_docs)] 6 | mod share; 7 | pub use self::share::ShareProto; 8 | 9 | use super::version; 10 | -------------------------------------------------------------------------------- /src/proto/wrapped/secret.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | 21 | use protobuf::Message as Message_imported_for_functions; 22 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 23 | 24 | #[derive(PartialEq,Clone,Default)] 25 | pub struct SecretProto { 26 | // message fields 27 | pub version: super::version::VersionProto, 28 | pub secret: ::std::vec::Vec, 29 | pub mime_type: ::std::string::String, 30 | // special fields 31 | unknown_fields: ::protobuf::UnknownFields, 32 | cached_size: ::protobuf::CachedSize, 33 | } 34 | 35 | // see codegen.rs for the explanation why impl Sync explicitly 36 | unsafe impl ::std::marker::Sync for SecretProto {} 37 | 38 | impl SecretProto { 39 | pub fn new() -> SecretProto { 40 | ::std::default::Default::default() 41 | } 42 | 43 | pub fn default_instance() -> &'static SecretProto { 44 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { 45 | lock: ::protobuf::lazy::ONCE_INIT, 46 | ptr: 0 as *const SecretProto, 47 | }; 48 | unsafe { 49 | instance.get(SecretProto::new) 50 | } 51 | } 52 | 53 | // .VersionProto version = 1; 54 | 55 | pub fn clear_version(&mut self) { 56 | self.version = super::version::VersionProto::INITIAL_RELEASE; 57 | } 58 | 59 | // Param is passed by value, moved 60 | pub fn set_version(&mut self, v: super::version::VersionProto) { 61 | self.version = v; 62 | } 63 | 64 | pub fn get_version(&self) -> super::version::VersionProto { 65 | self.version 66 | } 67 | 68 | fn get_version_for_reflect(&self) -> &super::version::VersionProto { 69 | &self.version 70 | } 71 | 72 | fn mut_version_for_reflect(&mut self) -> &mut super::version::VersionProto { 73 | &mut self.version 74 | } 75 | 76 | // bytes secret = 2; 77 | 78 | pub fn clear_secret(&mut self) { 79 | self.secret.clear(); 80 | } 81 | 82 | // Param is passed by value, moved 83 | pub fn set_secret(&mut self, v: ::std::vec::Vec) { 84 | self.secret = v; 85 | } 86 | 87 | // Mutable pointer to the field. 88 | // If field is not initialized, it is initialized with default value first. 89 | pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { 90 | &mut self.secret 91 | } 92 | 93 | // Take field 94 | pub fn take_secret(&mut self) -> ::std::vec::Vec { 95 | ::std::mem::replace(&mut self.secret, ::std::vec::Vec::new()) 96 | } 97 | 98 | pub fn get_secret(&self) -> &[u8] { 99 | &self.secret 100 | } 101 | 102 | fn get_secret_for_reflect(&self) -> &::std::vec::Vec { 103 | &self.secret 104 | } 105 | 106 | fn mut_secret_for_reflect(&mut self) -> &mut ::std::vec::Vec { 107 | &mut self.secret 108 | } 109 | 110 | // string mime_type = 3; 111 | 112 | pub fn clear_mime_type(&mut self) { 113 | self.mime_type.clear(); 114 | } 115 | 116 | // Param is passed by value, moved 117 | pub fn set_mime_type(&mut self, v: ::std::string::String) { 118 | self.mime_type = v; 119 | } 120 | 121 | // Mutable pointer to the field. 122 | // If field is not initialized, it is initialized with default value first. 123 | pub fn mut_mime_type(&mut self) -> &mut ::std::string::String { 124 | &mut self.mime_type 125 | } 126 | 127 | // Take field 128 | pub fn take_mime_type(&mut self) -> ::std::string::String { 129 | ::std::mem::replace(&mut self.mime_type, ::std::string::String::new()) 130 | } 131 | 132 | pub fn get_mime_type(&self) -> &str { 133 | &self.mime_type 134 | } 135 | 136 | fn get_mime_type_for_reflect(&self) -> &::std::string::String { 137 | &self.mime_type 138 | } 139 | 140 | fn mut_mime_type_for_reflect(&mut self) -> &mut ::std::string::String { 141 | &mut self.mime_type 142 | } 143 | } 144 | 145 | impl ::protobuf::Message for SecretProto { 146 | fn is_initialized(&self) -> bool { 147 | true 148 | } 149 | 150 | fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { 151 | while !is.eof()? { 152 | let (field_number, wire_type) = is.read_tag_unpack()?; 153 | match field_number { 154 | 1 => { 155 | if wire_type != ::protobuf::wire_format::WireTypeVarint { 156 | return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); 157 | } 158 | let tmp = is.read_enum()?; 159 | self.version = tmp; 160 | }, 161 | 2 => { 162 | ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.secret)?; 163 | }, 164 | 3 => { 165 | ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.mime_type)?; 166 | }, 167 | _ => { 168 | ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; 169 | }, 170 | }; 171 | } 172 | ::std::result::Result::Ok(()) 173 | } 174 | 175 | // Compute sizes of nested messages 176 | #[allow(unused_variables)] 177 | fn compute_size(&self) -> u32 { 178 | let mut my_size = 0; 179 | if self.version != super::version::VersionProto::INITIAL_RELEASE { 180 | my_size += ::protobuf::rt::enum_size(1, self.version); 181 | } 182 | if !self.secret.is_empty() { 183 | my_size += ::protobuf::rt::bytes_size(2, &self.secret); 184 | } 185 | if !self.mime_type.is_empty() { 186 | my_size += ::protobuf::rt::string_size(3, &self.mime_type); 187 | } 188 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 189 | self.cached_size.set(my_size); 190 | my_size 191 | } 192 | 193 | fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { 194 | if self.version != super::version::VersionProto::INITIAL_RELEASE { 195 | os.write_enum(1, self.version.value())?; 196 | } 197 | if !self.secret.is_empty() { 198 | os.write_bytes(2, &self.secret)?; 199 | } 200 | if !self.mime_type.is_empty() { 201 | os.write_string(3, &self.mime_type)?; 202 | } 203 | os.write_unknown_fields(self.get_unknown_fields())?; 204 | ::std::result::Result::Ok(()) 205 | } 206 | 207 | fn get_cached_size(&self) -> u32 { 208 | self.cached_size.get() 209 | } 210 | 211 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 212 | &self.unknown_fields 213 | } 214 | 215 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 216 | &mut self.unknown_fields 217 | } 218 | 219 | fn as_any(&self) -> &::std::any::Any { 220 | self as &::std::any::Any 221 | } 222 | fn as_any_mut(&mut self) -> &mut ::std::any::Any { 223 | self as &mut ::std::any::Any 224 | } 225 | fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { 226 | self 227 | } 228 | 229 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 230 | ::protobuf::MessageStatic::descriptor_static(None::) 231 | } 232 | } 233 | 234 | impl ::protobuf::MessageStatic for SecretProto { 235 | fn new() -> SecretProto { 236 | SecretProto::new() 237 | } 238 | 239 | fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { 240 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { 241 | lock: ::protobuf::lazy::ONCE_INIT, 242 | ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, 243 | }; 244 | unsafe { 245 | descriptor.get(|| { 246 | let mut fields = ::std::vec::Vec::new(); 247 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( 248 | "version", 249 | SecretProto::get_version_for_reflect, 250 | SecretProto::mut_version_for_reflect, 251 | )); 252 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( 253 | "secret", 254 | SecretProto::get_secret_for_reflect, 255 | SecretProto::mut_secret_for_reflect, 256 | )); 257 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( 258 | "mime_type", 259 | SecretProto::get_mime_type_for_reflect, 260 | SecretProto::mut_mime_type_for_reflect, 261 | )); 262 | ::protobuf::reflect::MessageDescriptor::new::( 263 | "SecretProto", 264 | fields, 265 | file_descriptor_proto() 266 | ) 267 | }) 268 | } 269 | } 270 | } 271 | 272 | impl ::protobuf::Clear for SecretProto { 273 | fn clear(&mut self) { 274 | self.clear_version(); 275 | self.clear_secret(); 276 | self.clear_mime_type(); 277 | self.unknown_fields.clear(); 278 | } 279 | } 280 | 281 | impl ::std::fmt::Debug for SecretProto { 282 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 283 | ::protobuf::text_format::fmt(self, f) 284 | } 285 | } 286 | 287 | impl ::protobuf::reflect::ProtobufValue for SecretProto { 288 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 289 | ::protobuf::reflect::ProtobufValueRef::Message(self) 290 | } 291 | } 292 | 293 | static file_descriptor_proto_data: &'static [u8] = b"\ 294 | \n\x14wrapped/secret.proto\x12\x07wrapped\x1a\rversion.proto\"k\n\x0bSec\ 295 | retProto\x12'\n\x07version\x18\x01\x20\x01(\x0e2\r.VersionProtoR\x07vers\ 296 | ion\x12\x16\n\x06secret\x18\x02\x20\x01(\x0cR\x06secret\x12\x1b\n\tmime_\ 297 | type\x18\x03\x20\x01(\tR\x08mimeTypeJ\x91\x02\n\x06\x12\x04\0\0\n\x01\n\ 298 | \x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0f\n\t\n\ 299 | \x02\x03\0\x12\x03\x04\x07\x16\n\n\n\x02\x04\0\x12\x04\x06\0\n\x01\n\n\n\ 300 | \x03\x04\0\x01\x12\x03\x06\x08\x13\n\x0b\n\x04\x04\0\x02\0\x12\x03\x07\ 301 | \x08!\n\r\n\x05\x04\0\x02\0\x04\x12\x04\x07\x08\x06\x15\n\x0c\n\x05\x04\ 302 | \0\x02\0\x06\x12\x03\x07\x08\x14\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x07\ 303 | \x15\x1c\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x07\x1f\x20\n\x0b\n\x04\x04\ 304 | \0\x02\x01\x12\x03\x08\x08\x19\n\r\n\x05\x04\0\x02\x01\x04\x12\x04\x08\ 305 | \x08\x07!\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x08\x08\r\n\x0c\n\x05\ 306 | \x04\0\x02\x01\x01\x12\x03\x08\x0e\x14\n\x0c\n\x05\x04\0\x02\x01\x03\x12\ 307 | \x03\x08\x17\x18\n\x0b\n\x04\x04\0\x02\x02\x12\x03\t\x08\x1d\n\r\n\x05\ 308 | \x04\0\x02\x02\x04\x12\x04\t\x08\x08\x19\n\x0c\n\x05\x04\0\x02\x02\x05\ 309 | \x12\x03\t\x08\x0e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\t\x0f\x18\n\x0c\ 310 | \n\x05\x04\0\x02\x02\x03\x12\x03\t\x1b\x1cb\x06proto3\ 311 | "; 312 | 313 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 314 | lock: ::protobuf::lazy::ONCE_INIT, 315 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 316 | }; 317 | 318 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 319 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 320 | } 321 | 322 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 323 | unsafe { 324 | file_descriptor_proto_lazy.get(|| { 325 | parse_descriptor_proto() 326 | }) 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/proto/wrapped/share.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | 21 | use protobuf::Message as Message_imported_for_functions; 22 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 23 | 24 | #[derive(PartialEq,Clone,Default)] 25 | pub struct ShareProto { 26 | // message fields 27 | pub shamir_data: ::std::vec::Vec, 28 | pub signature: ::protobuf::RepeatedField<::std::vec::Vec>, 29 | pub proof: ::std::vec::Vec, 30 | // special fields 31 | unknown_fields: ::protobuf::UnknownFields, 32 | cached_size: ::protobuf::CachedSize, 33 | } 34 | 35 | // see codegen.rs for the explanation why impl Sync explicitly 36 | unsafe impl ::std::marker::Sync for ShareProto {} 37 | 38 | impl ShareProto { 39 | pub fn new() -> ShareProto { 40 | ::std::default::Default::default() 41 | } 42 | 43 | pub fn default_instance() -> &'static ShareProto { 44 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { 45 | lock: ::protobuf::lazy::ONCE_INIT, 46 | ptr: 0 as *const ShareProto, 47 | }; 48 | unsafe { 49 | instance.get(ShareProto::new) 50 | } 51 | } 52 | 53 | // bytes shamir_data = 1; 54 | 55 | pub fn clear_shamir_data(&mut self) { 56 | self.shamir_data.clear(); 57 | } 58 | 59 | // Param is passed by value, moved 60 | pub fn set_shamir_data(&mut self, v: ::std::vec::Vec) { 61 | self.shamir_data = v; 62 | } 63 | 64 | // Mutable pointer to the field. 65 | // If field is not initialized, it is initialized with default value first. 66 | pub fn mut_shamir_data(&mut self) -> &mut ::std::vec::Vec { 67 | &mut self.shamir_data 68 | } 69 | 70 | // Take field 71 | pub fn take_shamir_data(&mut self) -> ::std::vec::Vec { 72 | ::std::mem::replace(&mut self.shamir_data, ::std::vec::Vec::new()) 73 | } 74 | 75 | pub fn get_shamir_data(&self) -> &[u8] { 76 | &self.shamir_data 77 | } 78 | 79 | fn get_shamir_data_for_reflect(&self) -> &::std::vec::Vec { 80 | &self.shamir_data 81 | } 82 | 83 | fn mut_shamir_data_for_reflect(&mut self) -> &mut ::std::vec::Vec { 84 | &mut self.shamir_data 85 | } 86 | 87 | // repeated bytes signature = 2; 88 | 89 | pub fn clear_signature(&mut self) { 90 | self.signature.clear(); 91 | } 92 | 93 | // Param is passed by value, moved 94 | pub fn set_signature(&mut self, v: ::protobuf::RepeatedField<::std::vec::Vec>) { 95 | self.signature = v; 96 | } 97 | 98 | // Mutable pointer to the field. 99 | pub fn mut_signature(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { 100 | &mut self.signature 101 | } 102 | 103 | // Take field 104 | pub fn take_signature(&mut self) -> ::protobuf::RepeatedField<::std::vec::Vec> { 105 | ::std::mem::replace(&mut self.signature, ::protobuf::RepeatedField::new()) 106 | } 107 | 108 | pub fn get_signature(&self) -> &[::std::vec::Vec] { 109 | &self.signature 110 | } 111 | 112 | fn get_signature_for_reflect(&self) -> &::protobuf::RepeatedField<::std::vec::Vec> { 113 | &self.signature 114 | } 115 | 116 | fn mut_signature_for_reflect(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { 117 | &mut self.signature 118 | } 119 | 120 | // bytes proof = 3; 121 | 122 | pub fn clear_proof(&mut self) { 123 | self.proof.clear(); 124 | } 125 | 126 | // Param is passed by value, moved 127 | pub fn set_proof(&mut self, v: ::std::vec::Vec) { 128 | self.proof = v; 129 | } 130 | 131 | // Mutable pointer to the field. 132 | // If field is not initialized, it is initialized with default value first. 133 | pub fn mut_proof(&mut self) -> &mut ::std::vec::Vec { 134 | &mut self.proof 135 | } 136 | 137 | // Take field 138 | pub fn take_proof(&mut self) -> ::std::vec::Vec { 139 | ::std::mem::replace(&mut self.proof, ::std::vec::Vec::new()) 140 | } 141 | 142 | pub fn get_proof(&self) -> &[u8] { 143 | &self.proof 144 | } 145 | 146 | fn get_proof_for_reflect(&self) -> &::std::vec::Vec { 147 | &self.proof 148 | } 149 | 150 | fn mut_proof_for_reflect(&mut self) -> &mut ::std::vec::Vec { 151 | &mut self.proof 152 | } 153 | } 154 | 155 | impl ::protobuf::Message for ShareProto { 156 | fn is_initialized(&self) -> bool { 157 | true 158 | } 159 | 160 | fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { 161 | while !is.eof()? { 162 | let (field_number, wire_type) = is.read_tag_unpack()?; 163 | match field_number { 164 | 1 => { 165 | ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.shamir_data)?; 166 | }, 167 | 2 => { 168 | ::protobuf::rt::read_repeated_bytes_into(wire_type, is, &mut self.signature)?; 169 | }, 170 | 3 => { 171 | ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.proof)?; 172 | }, 173 | _ => { 174 | ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; 175 | }, 176 | }; 177 | } 178 | ::std::result::Result::Ok(()) 179 | } 180 | 181 | // Compute sizes of nested messages 182 | #[allow(unused_variables)] 183 | fn compute_size(&self) -> u32 { 184 | let mut my_size = 0; 185 | if !self.shamir_data.is_empty() { 186 | my_size += ::protobuf::rt::bytes_size(1, &self.shamir_data); 187 | } 188 | for value in &self.signature { 189 | my_size += ::protobuf::rt::bytes_size(2, &value); 190 | }; 191 | if !self.proof.is_empty() { 192 | my_size += ::protobuf::rt::bytes_size(3, &self.proof); 193 | } 194 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 195 | self.cached_size.set(my_size); 196 | my_size 197 | } 198 | 199 | fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { 200 | if !self.shamir_data.is_empty() { 201 | os.write_bytes(1, &self.shamir_data)?; 202 | } 203 | for v in &self.signature { 204 | os.write_bytes(2, &v)?; 205 | }; 206 | if !self.proof.is_empty() { 207 | os.write_bytes(3, &self.proof)?; 208 | } 209 | os.write_unknown_fields(self.get_unknown_fields())?; 210 | ::std::result::Result::Ok(()) 211 | } 212 | 213 | fn get_cached_size(&self) -> u32 { 214 | self.cached_size.get() 215 | } 216 | 217 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 218 | &self.unknown_fields 219 | } 220 | 221 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 222 | &mut self.unknown_fields 223 | } 224 | 225 | fn as_any(&self) -> &::std::any::Any { 226 | self as &::std::any::Any 227 | } 228 | fn as_any_mut(&mut self) -> &mut ::std::any::Any { 229 | self as &mut ::std::any::Any 230 | } 231 | fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { 232 | self 233 | } 234 | 235 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 236 | ::protobuf::MessageStatic::descriptor_static(None::) 237 | } 238 | } 239 | 240 | impl ::protobuf::MessageStatic for ShareProto { 241 | fn new() -> ShareProto { 242 | ShareProto::new() 243 | } 244 | 245 | fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { 246 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { 247 | lock: ::protobuf::lazy::ONCE_INIT, 248 | ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, 249 | }; 250 | unsafe { 251 | descriptor.get(|| { 252 | let mut fields = ::std::vec::Vec::new(); 253 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( 254 | "shamir_data", 255 | ShareProto::get_shamir_data_for_reflect, 256 | ShareProto::mut_shamir_data_for_reflect, 257 | )); 258 | fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( 259 | "signature", 260 | ShareProto::get_signature_for_reflect, 261 | ShareProto::mut_signature_for_reflect, 262 | )); 263 | fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( 264 | "proof", 265 | ShareProto::get_proof_for_reflect, 266 | ShareProto::mut_proof_for_reflect, 267 | )); 268 | ::protobuf::reflect::MessageDescriptor::new::( 269 | "ShareProto", 270 | fields, 271 | file_descriptor_proto() 272 | ) 273 | }) 274 | } 275 | } 276 | } 277 | 278 | impl ::protobuf::Clear for ShareProto { 279 | fn clear(&mut self) { 280 | self.clear_shamir_data(); 281 | self.clear_signature(); 282 | self.clear_proof(); 283 | self.unknown_fields.clear(); 284 | } 285 | } 286 | 287 | impl ::std::fmt::Debug for ShareProto { 288 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 289 | ::protobuf::text_format::fmt(self, f) 290 | } 291 | } 292 | 293 | impl ::protobuf::reflect::ProtobufValue for ShareProto { 294 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 295 | ::protobuf::reflect::ProtobufValueRef::Message(self) 296 | } 297 | } 298 | 299 | static file_descriptor_proto_data: &'static [u8] = b"\ 300 | \n\x13wrapped/share.proto\x12\x07wrapped\"a\n\nShareProto\x12\x1f\n\x0bs\ 301 | hamir_data\x18\x01\x20\x01(\x0cR\nshamirData\x12\x1c\n\tsignature\x18\ 302 | \x02\x20\x03(\x0cR\tsignature\x12\x14\n\x05proof\x18\x03\x20\x01(\x0cR\ 303 | \x05proofJ\x85\x02\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\ 304 | \x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0f\n\n\n\x02\x04\0\x12\x04\x04\0\ 305 | \x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\x08\x12\n\x0b\n\x04\x04\0\x02\0\ 306 | \x12\x03\x05\x08\x1e\n\r\n\x05\x04\0\x02\0\x04\x12\x04\x05\x08\x04\x14\n\ 307 | \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x05\x08\r\n\x0c\n\x05\x04\0\x02\0\x01\ 308 | \x12\x03\x05\x0e\x19\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x05\x1c\x1d\n\ 309 | \x0b\n\x04\x04\0\x02\x01\x12\x03\x06\x08%\n\x0c\n\x05\x04\0\x02\x01\x04\ 310 | \x12\x03\x06\x08\x10\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x06\x11\x16\n\ 311 | \x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x06\x17\x20\n\x0c\n\x05\x04\0\x02\ 312 | \x01\x03\x12\x03\x06#$\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x07\x08\x18\n\r\ 313 | \n\x05\x04\0\x02\x02\x04\x12\x04\x07\x08\x06%\n\x0c\n\x05\x04\0\x02\x02\ 314 | \x05\x12\x03\x07\x08\r\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x07\x0e\x13\ 315 | \n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x07\x16\x17b\x06proto3\ 316 | "; 317 | 318 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 319 | lock: ::protobuf::lazy::ONCE_INIT, 320 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 321 | }; 322 | 323 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 324 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 325 | } 326 | 327 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 328 | unsafe { 329 | file_descriptor_proto_lazy.get(|| { 330 | parse_descriptor_proto() 331 | }) 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /src/share/mod.rs: -------------------------------------------------------------------------------- 1 | //! Define the traits used to distinguish the various 2 | //! kind of shares internally used by the library. 3 | //! These traits are currently not exposed, but this might 4 | //! change in the future. 5 | 6 | use errors::*; 7 | 8 | pub(crate) mod validation; 9 | 10 | /// All types of share should implement this trait. 11 | pub(crate) trait IsShare: Sized { 12 | /// Returns the identifier of the share. 13 | /// Varies between 1 and n where n is the total number of generated shares. 14 | fn get_id(&self) -> u8; 15 | 16 | /// Returns the share data itself 17 | fn get_data(&self) -> &[u8]; 18 | 19 | /// Returns the number of shares necessary to recover the secret, aka the threshold 20 | fn get_threshold(&self) -> u8; 21 | 22 | /// Returns the total number of shares that have been dealt 23 | fn get_shares_count(&self) -> Option; 24 | } 25 | 26 | /// This trait must be implemented by shares' types wich can be signed. 27 | pub(crate) trait IsSignedShare: IsShare { 28 | /// The type of shares' sigature. 29 | type Signature; 30 | 31 | /// Returns whether this share is signed or not. 32 | fn is_signed(&self) -> bool; 33 | 34 | /// Return the signature itself. 35 | fn get_signature(&self) -> &Self::Signature; 36 | 37 | /// Verify the signatures of the given batch of shares. 38 | /// Returns `Ok(())` if validation succeeds, and an `Err` otherwise. 39 | fn verify_signatures(shares: &[Self]) -> Result<()>; 40 | } 41 | -------------------------------------------------------------------------------- /src/share/validation.rs: -------------------------------------------------------------------------------- 1 | use errors::*; 2 | use share::{IsShare, IsSignedShare}; 3 | 4 | // The order of validation that we think makes the most sense is the following: 5 | // 1) Validate shares individually 6 | // 2) Validate duplicate shares share num && data 7 | // 2) Validate group consistency 8 | // 3) Validate other properties, in no specific order 9 | 10 | /// TODO: Doc 11 | pub(crate) fn validate_signed_shares( 12 | shares: &Vec, 13 | verify_signatures: bool, 14 | ) -> Result<(u8, usize)> { 15 | let result = validate_shares(shares)?; 16 | 17 | if verify_signatures { 18 | S::verify_signatures(&shares)?; 19 | } 20 | 21 | Ok(result) 22 | } 23 | 24 | /// TODO: Doc 25 | pub(crate) fn validate_shares(shares: &Vec) -> Result<(u8, usize)> { 26 | if shares.is_empty() { 27 | bail!(ErrorKind::EmptyShares); 28 | } 29 | 30 | let shares_count = shares.len(); 31 | 32 | let mut ids = Vec::with_capacity(shares_count); 33 | let mut threshold = 0; 34 | let mut slen = 0; 35 | 36 | for share in shares { 37 | let id = share.get_id(); 38 | let threshold_ = share.get_threshold(); 39 | let slen_ = share.get_data().len(); 40 | 41 | // Public-facing `Share::share_from_string` performs these three tests, but in case another 42 | // type which implements `IsShare` is implemented later that doesn't do that validation, 43 | // we'll leave them. 44 | if id < 1 { 45 | bail!(ErrorKind::ShareParsingInvalidShareId(id)) 46 | } else if threshold_ < 2 { 47 | bail!(ErrorKind::ShareParsingInvalidShareThreshold(threshold, id)) 48 | } else if slen_ < 1 { 49 | bail!(ErrorKind::ShareParsingErrorEmptyShare(id)) 50 | } 51 | 52 | if ids.iter().any(|&x| x == id) { 53 | bail!(ErrorKind::DuplicateShareId(id)); 54 | } 55 | 56 | if threshold == 0 { 57 | threshold = threshold_; 58 | } else if threshold_ != threshold { 59 | bail!(ErrorKind::InconsistentThresholds( 60 | id, 61 | threshold_, 62 | ids, 63 | threshold 64 | )) 65 | } 66 | 67 | if slen == 0 { 68 | slen = slen_; 69 | } else if slen_ != slen { 70 | bail!(ErrorKind::InconsistentSecretLengths(id, slen_, ids, slen)) 71 | } 72 | 73 | ids.push(id); 74 | } 75 | 76 | // Only once the threshold is confirmed as consistent should we determine if shares are 77 | // missing. 78 | if shares_count < threshold as usize { 79 | bail!(ErrorKind::MissingShares(shares_count, threshold)) 80 | } 81 | 82 | Ok((threshold, slen)) 83 | } 84 | 85 | pub(crate) fn validate_share_count(threshold: u8, shares_count: u8) -> Result<(u8, u8)> { 86 | if threshold < MIN_THRESHOLD { 87 | bail!(ErrorKind::ThresholdTooSmall(threshold)); 88 | } 89 | if shares_count > MAX_SHARES { 90 | bail!(ErrorKind::InvalidShareCountMax(shares_count, MAX_SHARES)); 91 | } 92 | if shares_count < MIN_SHARES { 93 | bail!(ErrorKind::InvalidShareCountMin(shares_count, MIN_SHARES)); 94 | } 95 | if threshold > shares_count { 96 | bail!(ErrorKind::ThresholdTooBig(threshold, shares_count)); 97 | } 98 | 99 | Ok((threshold, shares_count)) 100 | } 101 | -------------------------------------------------------------------------------- /src/sss/encode.rs: -------------------------------------------------------------------------------- 1 | use gf256::Gf256; 2 | use std::io; 3 | use std::io::prelude::*; 4 | 5 | /// Evaluates a polynomial at x=1, 2, 3, ... n (inclusive) using 6 | /// Horner's method. 7 | pub(crate) fn encode_secret_byte(src: &[u8], n: u8, w: &mut W) -> io::Result<()> { 8 | for raw_x in 1..(u16::from(n) + 1) { 9 | let x = Gf256::from_byte(raw_x as u8); 10 | let sum = src.iter().rev().fold(Gf256::zero(), |acc, &coeff| { 11 | Gf256::from_byte(coeff) + acc * x 12 | }); 13 | w.write_all(&[sum.to_byte()])?; 14 | } 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /src/sss/format.rs: -------------------------------------------------------------------------------- 1 | use base64; 2 | use errors::*; 3 | use merkle_sigs::{MerklePublicKey, Proof, PublicKey}; 4 | use proto::wrapped::ShareProto; 5 | use protobuf::{self, Message, RepeatedField}; 6 | use sss::{Share, HASH_ALGO}; 7 | use std::error::Error; 8 | 9 | const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; 10 | 11 | pub(crate) fn share_to_string( 12 | share: Vec, 13 | threshold: u8, 14 | share_num: u8, 15 | signature_pair: Option<(Vec>, Proof)>, 16 | ) -> String { 17 | let mut share_protobuf = ShareProto::new(); 18 | share_protobuf.set_shamir_data(share); 19 | 20 | if signature_pair.is_some() { 21 | let (signature, proof) = signature_pair.unwrap(); 22 | share_protobuf.set_signature(RepeatedField::from_vec(signature)); 23 | share_protobuf.set_proof(proof.write_to_bytes().unwrap()); 24 | } 25 | 26 | let proto_buf = share_protobuf.write_to_bytes().unwrap(); 27 | let b64_share = base64::encode_config(&proto_buf, BASE64_CONFIG); 28 | format!("{}-{}-{}", threshold, share_num, b64_share) 29 | } 30 | 31 | pub(crate) fn share_from_string(s: &str, is_signed: bool) -> Result { 32 | let parts: Vec<_> = s.trim().split('-').collect(); 33 | 34 | if parts.len() != SSS_SHARE_PARTS_COUNT { 35 | bail! { 36 | ErrorKind::ShareParsingError( 37 | format!( 38 | "Expected 3 parts separated by a minus sign. Found {}.", 39 | s 40 | ), 41 | ) 42 | }; 43 | } 44 | let (k, i, p3) = { 45 | let mut iter = parts.into_iter(); 46 | let k = iter.next().unwrap().parse::()?; 47 | let i = iter.next().unwrap().parse::()?; 48 | let p3 = iter.next().unwrap(); 49 | (k, i, p3) 50 | }; 51 | 52 | if i < 1 { 53 | bail!(ErrorKind::ShareParsingInvalidShareId(i)) 54 | } else if k < 2 { 55 | bail!(ErrorKind::ShareParsingInvalidShareThreshold(k, i)) 56 | } else if p3.is_empty() { 57 | bail!(ErrorKind::ShareParsingErrorEmptyShare(i)) 58 | } 59 | 60 | let raw_data = base64::decode_config(p3, BASE64_CONFIG).chain_err(|| { 61 | ErrorKind::ShareParsingError("Base64 decoding of data block failed".to_owned()) 62 | })?; 63 | 64 | let protobuf_data = 65 | protobuf::parse_from_bytes::(raw_data.as_slice()).map_err(|e| { 66 | ErrorKind::ShareParsingError(format!( 67 | "Protobuf decoding of data block failed with error: {} .", 68 | e.description() 69 | )) 70 | })?; 71 | 72 | let data = Vec::from(protobuf_data.get_shamir_data()); 73 | 74 | let signature_pair = if is_signed { 75 | let p_result = Proof::parse_from_bytes(protobuf_data.get_proof(), HASH_ALGO); 76 | 77 | let p_opt = p_result.unwrap(); 78 | let p = p_opt.unwrap(); 79 | 80 | let proof = Proof { 81 | algorithm: HASH_ALGO, 82 | lemma: p.lemma, 83 | root_hash: p.root_hash, 84 | value: MerklePublicKey::new(PublicKey::from_vec(p.value, HASH_ALGO).unwrap()), 85 | }; 86 | 87 | let signature = protobuf_data.get_signature(); 88 | Some((Vec::from(signature), proof).into()) 89 | } else { 90 | None 91 | }; 92 | 93 | Ok(Share { 94 | id: i, 95 | data, 96 | threshold: k, 97 | signature_pair, 98 | }) 99 | } 100 | 101 | pub(crate) fn format_share_for_signing(k: u8, i: u8, data: &[u8]) -> Vec { 102 | let b64_data = base64::encode_config(data, BASE64_CONFIG); 103 | format!("{}-{}-{}", k, i, b64_data).into_bytes() 104 | } 105 | -------------------------------------------------------------------------------- /src/sss/mod.rs: -------------------------------------------------------------------------------- 1 | //! SSS provides Shamir's secret sharing with raw data. 2 | 3 | use errors::*; 4 | 5 | mod share; 6 | pub(crate) use self::share::*; 7 | 8 | mod format; 9 | // pub use self::format::*; 10 | 11 | mod scheme; 12 | pub(crate) use self::scheme::*; 13 | 14 | mod encode; 15 | 16 | use rand::{OsRng, Rng}; 17 | use ring::digest::{Algorithm, SHA512}; 18 | static HASH_ALGO: &'static Algorithm = &SHA512; 19 | 20 | /// Performs threshold k-out-of-n Shamir's secret sharing. 21 | /// 22 | /// Uses a `rand::OsRng` as a source of entropy. 23 | /// 24 | /// # Examples 25 | /// 26 | /// ``` 27 | /// use rusty_secrets::sss::split_secret; 28 | /// 29 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 30 | /// social control, and diplomatic manipulation. They’re about power."; 31 | /// 32 | /// match split_secret(7, 10, &secret.as_bytes(), true) { 33 | /// Ok(shares) => { 34 | /// // Do something with the shares 35 | /// }, 36 | /// Err(_) => { 37 | /// // Deal with error 38 | /// } 39 | /// } 40 | /// ``` 41 | pub fn split_secret(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> Result> { 42 | SSS::default() 43 | .split_secret(&mut OsRng::new()?, k, n, secret, sign_shares) 44 | .map(|shares| shares.into_iter().map(Share::into_string).collect()) 45 | } 46 | 47 | /// Performs threshold k-out-of-n Shamir's secret sharing with a custom RNG. 48 | /// 49 | /// # Examples 50 | /// 51 | /// ``` 52 | /// # extern crate rusty_secrets; 53 | /// # extern crate rand; 54 | /// # 55 | /// # use rand::ChaChaRng; 56 | /// # 57 | /// # fn some_custom_rng() -> ChaChaRng { 58 | /// # let mut rng = ChaChaRng::new_unseeded(); 59 | /// # rng.set_counter(42, 42); 60 | /// # rng 61 | /// # } 62 | /// # 63 | /// # fn main() { 64 | /// use rusty_secrets::sss::split_secret_rng; 65 | /// 66 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 67 | /// social control, and diplomatic manipulation. They’re about power."; 68 | /// 69 | /// let mut rng = some_custom_rng(); 70 | /// 71 | /// match split_secret_rng(&mut rng, 7, 10, &secret.as_bytes(), true) { 72 | /// Ok(shares) => { 73 | /// // Do something with the shares 74 | /// }, 75 | /// Err(_) => { 76 | /// // Deal with error 77 | /// } 78 | /// } 79 | /// # } 80 | /// ``` 81 | pub fn split_secret_rng( 82 | rng: &mut R, 83 | k: u8, 84 | n: u8, 85 | secret: &[u8], 86 | sign_shares: bool, 87 | ) -> Result> { 88 | SSS::default() 89 | .split_secret(rng, k, n, secret, sign_shares) 90 | .map(|shares| shares.into_iter().map(Share::into_string).collect()) 91 | } 92 | 93 | /// Recovers the secret from a k-out-of-n Shamir's secret sharing scheme. 94 | /// 95 | /// At least `k` distinct shares need to be provided to recover the secret. 96 | /// 97 | /// # Examples 98 | /// 99 | /// ``` 100 | /// use rusty_secrets::sss::recover_secret; 101 | /// 102 | /// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); 103 | /// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); 104 | /// let shares = vec![share1, share2]; 105 | /// 106 | /// match recover_secret(&shares, false) { 107 | /// Ok(secret) => { 108 | /// // Do something with the secret 109 | /// }, 110 | /// Err(e) => { 111 | /// // Deal with the error 112 | /// } 113 | /// } 114 | /// ``` 115 | pub fn recover_secret(shares: &[String], verify_signatures: bool) -> Result> { 116 | let shares = Share::parse_all(shares, verify_signatures)?; 117 | SSS::recover_secret(shares, verify_signatures) 118 | } 119 | -------------------------------------------------------------------------------- /src/sss/scheme.rs: -------------------------------------------------------------------------------- 1 | //! SSS provides Shamir's secret sharing with raw data. 2 | 3 | use merkle_sigs::sign_data_vec; 4 | use rand::Rng; 5 | 6 | use errors::*; 7 | use lagrange::interpolate_at; 8 | use share::validation::{validate_share_count, validate_signed_shares}; 9 | use sss::format::format_share_for_signing; 10 | use sss::{Share, HASH_ALGO}; 11 | 12 | use super::encode::encode_secret_byte; 13 | 14 | /// SSS provides Shamir's secret sharing with raw data. 15 | #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] 16 | pub(crate) struct SSS; 17 | 18 | impl SSS { 19 | /// Performs threshold k-out-of-n Shamir's secret sharing. 20 | pub fn split_secret( 21 | &self, 22 | rng: &mut R, 23 | threshold: u8, 24 | shares_count: u8, 25 | secret: &[u8], 26 | sign_shares: bool, 27 | ) -> Result> { 28 | let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; 29 | let shares = Self::secret_share(rng, secret, threshold, shares_count)?; 30 | 31 | let signatures = if sign_shares { 32 | let shares_to_sign = shares 33 | .iter() 34 | .enumerate() 35 | .map(|(i, x)| format_share_for_signing(threshold, (i + 1) as u8, x)) 36 | .collect::>(); 37 | 38 | let sign = sign_data_vec(&shares_to_sign, HASH_ALGO) 39 | .unwrap() 40 | .into_iter() 41 | .map(Some) 42 | .collect::>(); 43 | 44 | Some(sign) 45 | } else { 46 | None 47 | }; 48 | 49 | let sig_pairs = signatures 50 | .unwrap_or_else(|| vec![None; shares_count as usize]) 51 | .into_iter() 52 | .map(|sig_pair| sig_pair.map(From::from)); 53 | 54 | let shares_and_sigs = shares.into_iter().enumerate().zip(sig_pairs); 55 | 56 | let result = shares_and_sigs.map(|((index, data), signature_pair)| { 57 | // This is actually safe since we alwaays generate less than 256 shares. 58 | let id = (index + 1) as u8; 59 | 60 | Share { 61 | id, 62 | threshold, 63 | data, 64 | signature_pair, 65 | } 66 | }); 67 | 68 | Ok(result.collect()) 69 | } 70 | 71 | fn secret_share( 72 | rng: &mut R, 73 | src: &[u8], 74 | threshold: u8, 75 | shares_count: u8, 76 | ) -> Result>> { 77 | let mut result = Vec::with_capacity(shares_count as usize); 78 | for _ in 0..(shares_count as usize) { 79 | result.push(vec![0u8; src.len()]); 80 | } 81 | let mut col_in = vec![0u8; threshold as usize]; 82 | let mut col_out = Vec::with_capacity(shares_count as usize); 83 | for (c, &s) in src.iter().enumerate() { 84 | col_in[0] = s; 85 | // NOTE: switch to `try_fill_bytes` when it lands in a stable release: 86 | // https://github.com/rust-lang-nursery/rand/commit/230b2258dbd99ff8bd991008c972d923d4b5d10c 87 | rng.fill_bytes(&mut col_in[1..]); 88 | col_out.clear(); 89 | encode_secret_byte(&*col_in, shares_count, &mut col_out)?; 90 | for (&y, share) in col_out.iter().zip(result.iter_mut()) { 91 | share[c] = y; 92 | } 93 | } 94 | Ok(result) 95 | } 96 | 97 | /// Recovers the secret from a k-out-of-n Shamir's secret sharing. 98 | /// 99 | /// At least `k` distinct shares need to be provided to recover the share. 100 | pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result> { 101 | let (threshold, slen) = validate_signed_shares(&shares, verify_signatures)?; 102 | 103 | let mut col_in = Vec::with_capacity(threshold as usize); 104 | let mut secret = Vec::with_capacity(slen); 105 | for byteindex in 0..slen { 106 | col_in.clear(); 107 | for s in shares.iter().take(threshold as usize) { 108 | col_in.push((s.id, s.data[byteindex])); 109 | } 110 | secret.push(interpolate_at(threshold, &*col_in)); 111 | } 112 | 113 | Ok(secret) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/sss/share.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use std::error::Error; 3 | 4 | use merkle_sigs::verify_data_vec_signature; 5 | use merkle_sigs::{MerklePublicKey, Proof}; 6 | 7 | use errors::*; 8 | use share::{IsShare, IsSignedShare}; 9 | use sss::format::{format_share_for_signing, share_from_string, share_to_string}; 10 | 11 | /// A share identified by an `id`, a threshold `k`, a number of total shares `n`, 12 | /// the `data` held in the share, and the share's `metadata`. 13 | // #[derive(Clone, Debug, Hash, PartialEq, Eq)] 14 | // TODO: Write manual instances which ignore the signature / fix merkle_sigs+merkle.rs 15 | #[derive(Clone, Debug)] 16 | pub(crate) struct Share { 17 | /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) 18 | pub id: u8, 19 | /// The number of shares necessary to recover the secret, aka a threshold 20 | pub threshold: u8, 21 | /// The share data itself 22 | pub data: Vec, 23 | /// If the share is signed, this fields holds the signature 24 | /// along with the proof of inclusion into the underlying MerkleTree. 25 | pub signature_pair: Option, 26 | } 27 | 28 | impl Share { 29 | /// Attempts to parse the given string into a share which should have the given `id`. 30 | /// The string `raw` should follow the format of `Share::into_string`. 31 | pub(crate) fn from_string(raw: &str, is_signed: bool) -> Result { 32 | share_from_string(raw, is_signed) 33 | } 34 | 35 | /// Attempts to parse all the given strings into shares. 36 | /// Calls out to `Share::from_string`. 37 | pub(crate) fn parse_all(raws: &[String], is_signed: bool) -> Result> { 38 | raws.into_iter() 39 | .map(|raw| Self::from_string(raw, is_signed)) 40 | .collect() 41 | } 42 | 43 | /// Format the share as a string suitable for being stored in a file. 44 | /// The format is the following: 45 | /// 46 | /// ```text 47 | /// 2-1-LiTyeXwEP71IUA 48 | /// ^ ^ ^^^^^^^^^^^^^^ 49 | /// K N D 50 | /// 51 | /// It is built out of three parts separated with a dash: K-N-D. 52 | /// 53 | /// - K specifies the number of shares necessary to recover the secret. 54 | /// - N is the identifier of the share and varies between 1 and n where 55 | /// n is the total number of generated shares. 56 | /// - D is a Base64 encoding of a ShareData protobuf containing 57 | /// information about the share, and if signed, the signature. 58 | /// ``` 59 | pub fn into_string(self) -> String { 60 | share_to_string( 61 | self.data, 62 | self.threshold, 63 | self.id, 64 | self.signature_pair.map(Into::into), 65 | ) 66 | } 67 | } 68 | 69 | impl IsShare for Share { 70 | fn get_id(&self) -> u8 { 71 | self.id 72 | } 73 | 74 | fn get_data(&self) -> &[u8] { 75 | &self.data 76 | } 77 | 78 | fn get_threshold(&self) -> u8 { 79 | self.threshold 80 | } 81 | 82 | fn get_shares_count(&self) -> Option { 83 | None 84 | } 85 | } 86 | 87 | impl IsSignedShare for Share { 88 | type Signature = Option; 89 | 90 | fn verify_signatures(shares: &[Self]) -> Result<()> { 91 | let mut rh_compatibility_sets = HashMap::new(); 92 | 93 | for share in shares { 94 | if !share.is_signed() { 95 | bail!(ErrorKind::MissingSignature(share.get_id())); 96 | } 97 | 98 | let sig_pair = share.signature_pair.as_ref().unwrap(); 99 | let signature = &sig_pair.signature; 100 | let proof = &sig_pair.proof; 101 | let root_hash = &proof.root_hash; 102 | 103 | verify_data_vec_signature( 104 | format_share_for_signing(share.threshold, share.id, share.data.as_slice()), 105 | &(signature.to_vec(), proof.clone()), 106 | root_hash, 107 | ).map_err(|e| ErrorKind::InvalidSignature(share.id, String::from(e.description())))?; 108 | 109 | rh_compatibility_sets 110 | .entry(root_hash) 111 | .or_insert_with(HashSet::new); 112 | 113 | let rh_set = rh_compatibility_sets.get_mut(&root_hash).unwrap(); 114 | rh_set.insert(share.id); 115 | } 116 | 117 | let rh_sets = rh_compatibility_sets.keys().count(); 118 | 119 | match rh_sets { 120 | 0 => bail!(ErrorKind::EmptyShares), 121 | 1 => {} // All shares have the same roothash. 122 | _ => { 123 | bail! { 124 | ErrorKind::IncompatibleSets( 125 | rh_compatibility_sets 126 | .values() 127 | .map(|x| x.to_owned()) 128 | .collect(), 129 | ) 130 | } 131 | } 132 | } 133 | 134 | Ok(()) 135 | } 136 | 137 | fn is_signed(&self) -> bool { 138 | self.signature_pair.is_some() 139 | } 140 | 141 | fn get_signature(&self) -> &Self::Signature { 142 | &self.signature_pair 143 | } 144 | } 145 | 146 | #[derive(Clone, Debug)] 147 | /// Holds the signature along with the proof of inclusion 148 | /// in the underlying Merkle tree used in the Lamport signature scheme. 149 | pub struct SignaturePair { 150 | /// The signature 151 | pub signature: Vec>, 152 | /// The proof of inclusion 153 | pub proof: Proof, 154 | } 155 | 156 | impl From for (Vec>, Proof) { 157 | fn from(pair: SignaturePair) -> Self { 158 | (pair.signature, pair.proof) 159 | } 160 | } 161 | 162 | impl From<(Vec>, Proof)> for SignaturePair { 163 | fn from(pair: (Vec>, Proof)) -> Self { 164 | Self { 165 | signature: pair.0, 166 | proof: pair.1, 167 | } 168 | } 169 | } 170 | 171 | // TODO: Uncomment when re-implementating standard traits for `Share` 172 | // impl Hash for SignaturePair { 173 | // fn hash(&self, state: &mut H) { 174 | // self.signature.hash(state); 175 | // self.proof.root_hash.hash(state); 176 | // } 177 | // } 178 | -------------------------------------------------------------------------------- /src/vol_hash.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | use std::mem::transmute; 3 | 4 | use ring::digest::{Algorithm, Context}; 5 | 6 | #[allow(unsafe_code)] 7 | fn u32_to_bytes(x: u32) -> [u8; 4] { 8 | unsafe { transmute(x.to_be()) } 9 | } 10 | 11 | pub struct VOLHash { 12 | algorithm: &'static Algorithm, 13 | bytes: Vec, 14 | } 15 | 16 | impl VOLHash { 17 | pub fn new(algorithm: &'static Algorithm) -> VOLHash { 18 | Self { 19 | algorithm, 20 | bytes: Vec::new(), 21 | } 22 | } 23 | 24 | pub fn process(&mut self, bytes: &[u8]) { 25 | self.bytes.extend_from_slice(bytes) 26 | } 27 | 28 | pub fn finish(self, dest: &mut [u8]) { 29 | let len = dest.len(); 30 | assert!(len < std::u32::MAX as usize); 31 | 32 | let mut ctx = Context::new(self.algorithm); 33 | ctx.update(&[0u8]); 34 | ctx.update(&u32_to_bytes(len as u32)); 35 | ctx.update(&self.bytes); 36 | 37 | let mut state = ctx.finish().as_ref().to_vec(); 38 | 39 | let iter_num = len / self.algorithm.output_len; 40 | 41 | for i in 0..iter_num { 42 | let mut inner_ctx = Context::new(self.algorithm); 43 | inner_ctx.update(&[255u8]); 44 | inner_ctx.update(&u32_to_bytes(1 + i as u32)); 45 | inner_ctx.update(&state); 46 | 47 | state.extend_from_slice(inner_ctx.finish().as_ref()) 48 | } 49 | 50 | assert!(state.len() >= len); 51 | 52 | let src = state.drain(0..len).collect::>(); 53 | dest.copy_from_slice(&src); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/wrapped_secrets/mod.rs: -------------------------------------------------------------------------------- 1 | //! (Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data. 2 | 3 | use errors::*; 4 | use proto::wrapped::SecretProto; 5 | 6 | use rand::{OsRng, Rng}; 7 | 8 | mod scheme; 9 | pub(crate) use self::scheme::*; 10 | 11 | /// Performs threshold k-out-of-n Shamir's secret sharing. 12 | /// 13 | /// Uses an `OsRng` as a source of entropy. 14 | /// 15 | /// # Examples 16 | /// 17 | /// ``` 18 | /// use rusty_secrets::wrapped_secrets::split_secret; 19 | /// 20 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 21 | /// social control, and diplomatic manipulation. They’re about power."; 22 | /// 23 | /// let result = split_secret( 24 | /// 7, 25 | /// 10, 26 | /// &secret.as_bytes(), 27 | /// Some("text/html".to_string()), 28 | /// true, 29 | /// ); 30 | /// 31 | /// match result { 32 | /// Ok(shares) => { 33 | /// // Do something with the shares 34 | /// }, 35 | /// Err(_) => { 36 | /// // Deal with error 37 | /// } 38 | /// } 39 | /// ``` 40 | pub fn split_secret( 41 | k: u8, 42 | n: u8, 43 | secret: &[u8], 44 | mime_type: Option, 45 | sign_shares: bool, 46 | ) -> Result> { 47 | WrappedSecrets::default() 48 | .split_secret(&mut OsRng::new()?, k, n, secret, mime_type, sign_shares) 49 | .map(|shares| shares.into_iter().map(Share::into_string).collect()) 50 | } 51 | 52 | /// Performs threshold k-out-of-n Shamir's secret sharing with a custom RNG. 53 | /// 54 | /// # Examples 55 | /// 56 | /// ``` 57 | /// # extern crate rusty_secrets; 58 | /// # extern crate rand; 59 | /// # 60 | /// # fn main() { 61 | /// use rusty_secrets::wrapped_secrets::split_secret_rng; 62 | /// use rand::ChaChaRng; 63 | /// 64 | /// let secret = "These programs were never about terrorism: they’re about economic spying, \ 65 | /// social control, and diplomatic manipulation. They’re about power."; 66 | /// 67 | /// let result = split_secret_rng( 68 | /// &mut ChaChaRng::new_unseeded(), 69 | /// 7, 70 | /// 10, 71 | /// &secret.as_bytes(), 72 | /// Some("text/html".to_string()), 73 | /// true, 74 | /// ); 75 | /// 76 | /// match result { 77 | /// Ok(shares) => { 78 | /// // Do something with the shares 79 | /// }, 80 | /// Err(_) => { 81 | /// // Deal with error 82 | /// } 83 | /// } 84 | /// # } 85 | /// ``` 86 | pub fn split_secret_rng( 87 | rng: &mut R, 88 | k: u8, 89 | n: u8, 90 | secret: &[u8], 91 | mime_type: Option, 92 | sign_shares: bool, 93 | ) -> Result> { 94 | WrappedSecrets::default() 95 | .split_secret(rng, k, n, secret, mime_type, sign_shares) 96 | .map(|shares| shares.into_iter().map(Share::into_string).collect()) 97 | } 98 | 99 | /// Recovers the secret from a k-out-of-n Shamir's secret sharing. 100 | /// 101 | /// At least `k` distinct shares need to be provided to recover the share. 102 | /// 103 | /// # Examples 104 | /// 105 | /// ```rust 106 | /// use rusty_secrets::wrapped_secrets::recover_secret; 107 | /// 108 | /// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); 109 | /// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); 110 | /// let shares = vec![share1, share2]; 111 | /// 112 | /// match recover_secret(&shares, false) { 113 | /// Ok(secret) => { 114 | /// // Do something with the secret 115 | /// }, 116 | /// Err(e) => { 117 | /// // Deal with the error 118 | /// } 119 | /// } 120 | /// ``` 121 | pub fn recover_secret(shares: &[String], verify_signatures: bool) -> Result { 122 | let shares = Share::parse_all(shares, verify_signatures)?; 123 | WrappedSecrets::recover_secret(shares, verify_signatures) 124 | } 125 | -------------------------------------------------------------------------------- /src/wrapped_secrets/scheme.rs: -------------------------------------------------------------------------------- 1 | use errors::*; 2 | use proto::VersionProto; 3 | use proto::wrapped::SecretProto; 4 | use protobuf; 5 | use protobuf::Message; 6 | use rand::Rng; 7 | 8 | use sss::SSS; 9 | pub(crate) use sss::Share; 10 | 11 | #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] 12 | pub(crate) struct WrappedSecrets; 13 | 14 | impl WrappedSecrets { 15 | /// Performs threshold k-out-of-n Shamir's secret sharing. 16 | pub fn split_secret( 17 | &self, 18 | rng: &mut R, 19 | k: u8, 20 | n: u8, 21 | secret: &[u8], 22 | mime_type: Option, 23 | sign_shares: bool, 24 | ) -> Result> { 25 | let mut rusty_secret = SecretProto::new(); 26 | rusty_secret.set_version(VersionProto::INITIAL_RELEASE); 27 | rusty_secret.set_secret(secret.to_owned()); 28 | 29 | if let Some(mt) = mime_type { 30 | rusty_secret.set_mime_type(mt); 31 | } 32 | 33 | let data = rusty_secret.write_to_bytes().unwrap(); 34 | 35 | SSS::default().split_secret(rng, k, n, data.as_slice(), sign_shares) 36 | } 37 | 38 | /// Recovers the secret from a k-out-of-n Shamir's secret sharing. 39 | /// 40 | /// At least `k` distinct shares need to be provided to recover the share. 41 | pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result { 42 | let secret = SSS::recover_secret(shares, verify_signatures)?; 43 | 44 | protobuf::parse_from_bytes::(secret.as_slice()) 45 | .chain_err(|| ErrorKind::SecretDeserializationError) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/.gitignore: -------------------------------------------------------------------------------- 1 | *.py 2 | *.pyc 3 | *.sage.py 4 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SAGE = sage 3 | 4 | TARGETS = gf256_add.txt.gz gf256_sub.txt.gz gf256_div.txt.gz gf256_mul.txt.gz gf256_pow.txt.gz 5 | 6 | .PHONY: all clean 7 | 8 | all: $(TARGETS) 9 | 10 | %.txt.gz: %.sage common.py 11 | $(SAGE) $< | gzip > $@ 12 | 13 | common.py: common.sage 14 | $(SAGE) --preparse $< 15 | mv common.sage.py common.py 16 | 17 | clean: 18 | $(RM) $(TARGETS) common.py 19 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/common.sage: -------------------------------------------------------------------------------- 1 | 2 | field = GF(2**8, name='a', modulus=x^8+x^4+x^3+x^2+1, repr='int') 3 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_add.sage: -------------------------------------------------------------------------------- 1 | from common import field 2 | 3 | for i in sorted(field): 4 | for j in sorted(field): 5 | print("{} + {} = {}".format(i, j, i + j)) 6 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_add.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpinResearch/RustySecrets/38f98ff87eb42c55056c89578f89a0ef97f32c20/tests/fixtures/gf256/gf256_add.txt.gz -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_div.sage: -------------------------------------------------------------------------------- 1 | from common import field 2 | 3 | for i in sorted(field): 4 | for j in sorted(field)[1:]: 5 | print("{} / {} = {}".format(i, j, i / j)) 6 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_div.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpinResearch/RustySecrets/38f98ff87eb42c55056c89578f89a0ef97f32c20/tests/fixtures/gf256/gf256_div.txt.gz -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_mul.sage: -------------------------------------------------------------------------------- 1 | from common import field 2 | 3 | for i in sorted(field): 4 | for j in sorted(field): 5 | print("{} * {} = {}".format(i, j, i * j)) 6 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_mul.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpinResearch/RustySecrets/38f98ff87eb42c55056c89578f89a0ef97f32c20/tests/fixtures/gf256/gf256_mul.txt.gz -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_pow.sage: -------------------------------------------------------------------------------- 1 | from common import field 2 | 3 | for i in sorted(field): 4 | for j in range(0, 256): 5 | print("{} ^ {} = {}".format(i, j, i ^ j)) 6 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_pow.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpinResearch/RustySecrets/38f98ff87eb42c55056c89578f89a0ef97f32c20/tests/fixtures/gf256/gf256_pow.txt.gz -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_sub.sage: -------------------------------------------------------------------------------- 1 | from common import field 2 | 3 | for i in sorted(field): 4 | for j in sorted(field): 5 | print("{} - {} = {}".format(i, j, i - j)) 6 | -------------------------------------------------------------------------------- /tests/fixtures/gf256/gf256_sub.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpinResearch/RustySecrets/38f98ff87eb42c55056c89578f89a0ef97f32c20/tests/fixtures/gf256/gf256_sub.txt.gz -------------------------------------------------------------------------------- /tests/generation_errors.rs: -------------------------------------------------------------------------------- 1 | extern crate rusty_secrets; 2 | 3 | use rusty_secrets::sss; 4 | 5 | #[test] 6 | #[should_panic(expected = "ThresholdTooBig")] 7 | fn test_generate_invalid_k() { 8 | let share1 = "2-1-1YAYwmOHqZ69jA".to_string().into_bytes(); 9 | 10 | sss::split_secret(10, 5, share1.as_slice(), true).unwrap(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/randomized_tests.rs: -------------------------------------------------------------------------------- 1 | extern crate rusty_secrets; 2 | 3 | use rusty_secrets::wrapped_secrets; 4 | 5 | #[ignore] 6 | #[test] 7 | fn test_reasonable_splits() { 8 | let max_shares = 25; 9 | let secret = "I grew up with the understanding that the world I lived in was one where people \ 10 | enjoyed a sort of freedom to communicate with each other in privacy, without it \ 11 | being monitored, without it being measured or analyzed or sort of judged by \ 12 | these shadowy figures or systems, any time they mention anything that travels \ 13 | across public lines." 14 | .to_string() 15 | .into_bytes(); 16 | 17 | let mime_type = "image/jpeg".to_string(); 18 | 19 | for is_signing in &[true, false] { 20 | for k in 1..max_shares { 21 | for n in k..max_shares { 22 | let shares = wrapped_secrets::split_secret( 23 | k, 24 | n, 25 | &secret, 26 | Some(mime_type.clone()), 27 | *is_signing, 28 | ).unwrap(); 29 | println!("Testing {} out-of- {}", k, n); 30 | 31 | let s = wrapped_secrets::recover_secret(&shares, *is_signing).unwrap(); 32 | assert_eq!(s.get_secret().to_owned(), secret); 33 | assert_eq!(mime_type, s.get_mime_type()); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/recovery_errors.rs: -------------------------------------------------------------------------------- 1 | extern crate rusty_secrets; 2 | 3 | use rusty_secrets::sss::{recover_secret, split_secret}; 4 | 5 | #[test] 6 | #[should_panic(expected = "EmptyShares")] 7 | fn test_recover_no_shares() { 8 | for signed in &[true, false] { 9 | let shares = vec![]; 10 | recover_secret(&shares, *signed).unwrap(); 11 | } 12 | } 13 | 14 | #[test] 15 | #[should_panic(expected = "ShareParsingErrorEmptyShare")] 16 | fn test_share_parsing_error_empty_share() { 17 | let shares = vec!["2-1-".to_string()]; 18 | recover_secret(&shares, false).unwrap(); 19 | } 20 | 21 | #[test] 22 | #[should_panic(expected = "ShareParsingError")] 23 | fn test_recover_2_parts_share() { 24 | let share1 = "2-1-CgmKQZHMO+5n5pU".to_string(); 25 | let share2 = "2-2".to_string(); 26 | 27 | let shares = vec![share1, share2]; 28 | 29 | recover_secret(&shares, false).unwrap(); 30 | } 31 | 32 | #[test] 33 | #[should_panic(expected = "IntegerParsingError")] 34 | fn test_recover_incorrect_share_num() { 35 | let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); 36 | let share2 = "2-DEFINITLY_NAN-CgkAnUgP3lfwjyM".to_string(); 37 | 38 | let shares = vec![share1, share2]; 39 | 40 | recover_secret(&shares, false).unwrap(); 41 | } 42 | 43 | #[test] 44 | #[should_panic(expected = "ShareParsingInvalidShareId")] 45 | fn test_recover_0_share_num() { 46 | let shares = vec!["2-0-1YAYwmOHqZ69jA".to_string()]; 47 | recover_secret(&shares, false).unwrap(); 48 | } 49 | 50 | #[test] 51 | #[should_panic(expected = "ShareParsingError")] 52 | fn test_recover_invalid_b64() { 53 | let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); 54 | let share2 = "2-2-YJZQDG((((m22Y)))77Gw".to_string(); 55 | 56 | let shares = vec![share1, share2]; 57 | 58 | recover_secret(&shares, false).unwrap(); 59 | } 60 | 61 | #[test] 62 | #[should_panic(expected = "DuplicateShareId")] 63 | fn test_recover_duplicate_shares_number() { 64 | let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); 65 | let share2 = "2-1-CgkAnUgP3lfwjyM".to_string(); 66 | 67 | let shares = vec![share1, share2]; 68 | 69 | recover_secret(&shares, false).unwrap(); 70 | } 71 | 72 | #[test] 73 | #[should_panic(expected = "InconsistentSecretLengths")] 74 | fn test_recover_inconsistent_secret_lengths() { 75 | let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); 76 | let share2 = "2-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string(); 77 | 78 | let shares = vec![share1, share2]; 79 | 80 | recover_secret(&shares, false).unwrap(); 81 | } 82 | 83 | #[test] 84 | #[should_panic(expected = "InconsistentThresholds")] 85 | fn test_inconsistent_thresholds() { 86 | let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); 87 | let share2 = "3-2-CgkAnUgP3lfwjyM".to_string(); 88 | 89 | let shares = vec![share1, share2]; 90 | 91 | recover_secret(&shares, false).unwrap(); 92 | } 93 | 94 | #[test] 95 | #[should_panic(expected = "MissingShares")] 96 | fn test_recover_too_few_shares() { 97 | let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string(); 98 | let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string(); 99 | 100 | let shares = vec![share1, share2]; 101 | 102 | recover_secret(&shares, false).unwrap(); 103 | } 104 | 105 | #[test] 106 | #[should_panic(expected = "ShareParsingInvalidShareThreshold")] 107 | fn test_recover_invalid_share_threshold() { 108 | let share1 = "1-1-CgnlCxRNtnkzENE".to_string(); 109 | let share2 = "1-1-CgkAnUgP3lfwjyM".to_string(); 110 | 111 | let shares = vec![share1, share2]; 112 | 113 | recover_secret(&shares, false).unwrap(); 114 | } 115 | 116 | // See https://github.com/SpinResearch/RustySecrets/issues/43 117 | #[test] 118 | fn test_recover_too_few_shares_bug() { 119 | let original = b"Test for issue #43".to_vec(); 120 | let shares = split_secret(4, 5, &original, false).unwrap(); 121 | let mut share_1 = shares[0].clone().into_bytes(); 122 | let mut share_2 = shares[3].clone().into_bytes(); 123 | 124 | share_1[0] = '2' as u8; 125 | share_2[0] = '2' as u8; 126 | 127 | let sub_shares = vec![ 128 | String::from_utf8_lossy(&share_1).into_owned(), 129 | String::from_utf8_lossy(&share_2).into_owned(), 130 | ]; 131 | 132 | match recover_secret(&sub_shares, false) { 133 | Err(_) => assert!(true), 134 | Ok(recovered) => assert_ne!(original, recovered), 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tests/ss1_recovery_errors.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "dss")] 2 | 3 | extern crate rusty_secrets; 4 | use rusty_secrets::dss::ss1::{recover_secret, split_secret, Reproducibility, Share}; 5 | 6 | const TEST_THRESHOLD: u8 = 2; 7 | const TEST_SHARES_COUNT: u8 = 2; 8 | const TEST_REPRODUCIBILITY: Reproducibility = Reproducibility::Reproducible; 9 | const TEST_SECRET: &[u8] = 10 | b"These programs were never about terrorism: they're about economic spying, \ 11 | social control, and diplomatic manipulation. They're about power."; 12 | 13 | fn get_test_hash() -> Vec { 14 | let good_shares = split_secret( 15 | TEST_THRESHOLD, 16 | TEST_SHARES_COUNT, 17 | TEST_SECRET, 18 | TEST_REPRODUCIBILITY, 19 | &None, 20 | ).unwrap(); 21 | 22 | good_shares[0].hash.clone() 23 | } 24 | 25 | #[test] 26 | #[should_panic(expected = "EmptyShares")] 27 | fn test_recover_no_shares() { 28 | let shares = vec![]; 29 | recover_secret(&shares).unwrap(); 30 | } 31 | 32 | #[test] 33 | #[should_panic(expected = "ShareParsingErrorEmptyShare")] 34 | fn test_recover_2_parts_share() { 35 | let hash = get_test_hash(); 36 | 37 | let share1 = Share { 38 | id: 1, 39 | threshold: TEST_THRESHOLD, 40 | shares_count: TEST_SHARES_COUNT, 41 | data: "CgmKQZHMO+5n5pU".to_string().into_bytes(), 42 | hash: hash.clone(), 43 | metadata: None, 44 | }; 45 | let share2 = Share { 46 | id: 2, 47 | threshold: TEST_THRESHOLD, 48 | shares_count: TEST_SHARES_COUNT, 49 | data: "".to_string().into_bytes(), 50 | hash: hash.clone(), 51 | metadata: None, 52 | }; 53 | 54 | let shares = vec![share1, share2]; 55 | 56 | recover_secret(&shares).unwrap(); 57 | } 58 | 59 | #[test] 60 | #[should_panic(expected = "ShareParsingInvalidShareId")] 61 | fn test_recover_0_share_num() { 62 | let hash = get_test_hash(); 63 | 64 | let share1 = Share { 65 | id: 0, 66 | threshold: TEST_THRESHOLD, 67 | shares_count: TEST_SHARES_COUNT, 68 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 69 | hash: hash.clone(), 70 | metadata: None, 71 | }; 72 | let share2 = Share { 73 | id: 1, 74 | threshold: TEST_THRESHOLD, 75 | shares_count: TEST_SHARES_COUNT, 76 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 77 | hash: hash.clone(), 78 | metadata: None, 79 | }; 80 | 81 | let shares = vec![share1, share2]; 82 | 83 | recover_secret(&shares).unwrap(); 84 | } 85 | 86 | // --- 87 | // TODO: will be implemented when serialization is done for ss1 shares 88 | // --- 89 | // #[test] 90 | // #[should_panic(expected = "ShareParsingError")] 91 | // fn test_recover_invalid_b64() { 92 | // let share1 = Share { 93 | // id: 1, 94 | // threshold: 2, 95 | // shares_count: 2, 96 | // data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 97 | // metadata: None 98 | // }; 99 | // let share2 = Share { 100 | // id: 2, 101 | // threshold: 2, 102 | // shares_count: 2, 103 | // data: "YJZQDG((((m22Y)))77Gw".to_string().into_bytes(), 104 | // metadata: None 105 | // }; 106 | // 107 | // let shares = vec![share1, share2]; 108 | // 109 | // recover_secret(&shares).unwrap(); 110 | // } 111 | 112 | #[test] 113 | #[should_panic(expected = "DuplicateShareId")] 114 | fn test_recover_duplicate_shares_number() { 115 | let hash = get_test_hash(); 116 | let share1 = Share { 117 | id: 1, 118 | threshold: TEST_THRESHOLD, 119 | shares_count: TEST_SHARES_COUNT, 120 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 121 | hash: hash.clone(), 122 | metadata: None, 123 | }; 124 | let share2 = Share { 125 | id: 1, 126 | threshold: TEST_THRESHOLD, 127 | shares_count: TEST_SHARES_COUNT, 128 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 129 | hash: hash.clone(), 130 | metadata: None, 131 | }; 132 | 133 | let shares = vec![share1, share2]; 134 | 135 | recover_secret(&shares).unwrap(); 136 | } 137 | 138 | #[test] 139 | #[should_panic(expected = "MissingShares")] 140 | fn test_recover_too_few_shares() { 141 | let hash = get_test_hash(); 142 | let share1 = Share { 143 | id: 1, 144 | threshold: TEST_THRESHOLD + 1, 145 | shares_count: TEST_SHARES_COUNT + 1, 146 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 147 | hash: hash.clone(), 148 | metadata: None, 149 | }; 150 | let share2 = Share { 151 | id: 2, 152 | threshold: TEST_THRESHOLD + 1, 153 | shares_count: TEST_SHARES_COUNT + 1, 154 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 155 | hash: hash.clone(), 156 | metadata: None, 157 | }; 158 | 159 | let shares = vec![share1, share2]; 160 | 161 | recover_secret(&shares).unwrap(); 162 | } 163 | -------------------------------------------------------------------------------- /tests/test_vectors.rs: -------------------------------------------------------------------------------- 1 | extern crate base64; 2 | extern crate protobuf; 3 | extern crate rusty_secrets; 4 | 5 | use protobuf::Message; 6 | 7 | use rusty_secrets::proto::wrapped::ShareProto; 8 | use rusty_secrets::sss::recover_secret; 9 | 10 | const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; 11 | 12 | pub fn wrap_from_sellibitze(share: &str) -> String { 13 | let parts: Vec<_> = share.trim().split('-').collect(); 14 | let share_data = base64::decode_config(parts[2], BASE64_CONFIG).unwrap(); 15 | 16 | let mut share_protobuf = ShareProto::new(); 17 | share_protobuf.set_shamir_data(share_data); 18 | 19 | let b64_share = base64::encode_config(&share_protobuf.write_to_bytes().unwrap(), BASE64_CONFIG); 20 | 21 | format!("{}-{}-{}", parts[0], parts[1], b64_share) 22 | } 23 | 24 | #[test] 25 | fn test_recover_sellibitze() { 26 | let share1 = "2-1-1YAYwmOHqZ69jA"; 27 | let share2 = "2-4-F7rAjX3UOa53KA"; 28 | 29 | let shares = vec![share1, share2] 30 | .iter() 31 | .map(|x| wrap_from_sellibitze(x)) 32 | .collect::>(); 33 | 34 | let mut secret = "My secret".to_string().into_bytes(); 35 | secret.push(10); 36 | assert_eq!(recover_secret(&shares, false).unwrap(), secret); 37 | } 38 | 39 | // Generated with code on master branch on the 6th of April. 40 | #[test] 41 | fn test_recover_es_test_vectors() { 42 | let share1 = 43 | "5-1-DbuicpLQiCf7bVWiAz8eCpQGpdZmYQ7z2j2+g351tWFLOQPTZkXY8BYfwGGGjkOoz1g9x0ScmLFcWk+2tign"; 44 | let share2 = 45 | "5-2-nShdfkY5+SlfybMyqjHXCZ01bq5N/0Lkf0nQZw5x3bnHIEVfa0RA4YcJ4SjG/UdpgO/gOcyLRkSp2Dwf8bvw"; 46 | let share3 = 47 | "5-3-qEhJ3IVEdbDkiRoy+jOJ/KuGE9jWyGeOYEcDwPfEV8E9rfD1Bc17BQAbJ51Xd8oexS2M1qMvNgJHZUQZbUgQ"; 48 | let share4 = 49 | "5-6-yyVPUeaYPPiWK0wIV5OQ/t61V0lSEO+7X++EWeHRlIq3sRBNwUpKNfx/C+Vc9xTzUftrqBKvkWDZQal7nyi2"; 50 | let share5 = 51 | "5-7-i8iL6bVf272B3qIjp0QqSny6AIm+DkP7oQjkVVLvx9EMhlvd4HJOxPpmtNF/RjA/zz21d7DY/B//saOPpBQa"; 52 | 53 | let shares = vec![share1, share2, share3, share4, share5] 54 | .iter() 55 | .map(|x| wrap_from_sellibitze(x)) 56 | .collect::>(); 57 | 58 | let secret = "The immoral cannot be made moral through the use of secret law." 59 | .to_string() 60 | .into_bytes(); 61 | assert_eq!(recover_secret(&shares, false).unwrap(), secret); 62 | } 63 | 64 | #[test] 65 | fn test_recover_sellibitze_more_than_threshold_shars() { 66 | let share1 = "2-1-1YAYwmOHqZ69jA"; 67 | let share2 = "2-4-F7rAjX3UOa53KA"; 68 | let share3 = "2-2-YJZQDGm22Y77Gw"; 69 | let share4 = "2-5-j0P4PHsw4lW+rg"; 70 | 71 | let shares = vec![share1, share2, share3, share4] 72 | .iter() 73 | .map(|x| wrap_from_sellibitze(x)) 74 | .collect::>(); 75 | 76 | let mut secret = "My secret".to_string().into_bytes(); 77 | secret.push(10); 78 | assert_eq!(recover_secret(&shares, false).unwrap(), secret); 79 | } 80 | -------------------------------------------------------------------------------- /tests/thss_generation_errors.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "dss")] 2 | 3 | extern crate rusty_secrets; 4 | 5 | use rusty_secrets::dss::thss; 6 | 7 | #[test] 8 | #[should_panic(expected = "ThresholdTooBig")] 9 | fn test_generate_invalid_k() { 10 | let secret = b"These programs were never about terrorism: they're about economic spying, \ 11 | social control, and diplomatic manipulation. They're about power."; 12 | 13 | thss::split_secret(10, 7, secret, &None).unwrap(); 14 | } 15 | -------------------------------------------------------------------------------- /tests/thss_recovery_errors.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "dss")] 2 | 3 | extern crate rusty_secrets; 4 | 5 | use rusty_secrets::dss::thss::{recover_secret, Share}; 6 | 7 | #[test] 8 | #[should_panic(expected = "EmptyShares")] 9 | fn test_recover_no_shares() { 10 | let shares = vec![]; 11 | recover_secret(&shares).unwrap(); 12 | } 13 | 14 | #[test] 15 | #[should_panic(expected = "ShareParsingErrorEmptyShare")] 16 | fn test_recover_2_parts_share() { 17 | let share1 = Share { 18 | id: 1, 19 | threshold: 2, 20 | shares_count: 2, 21 | data: "CgmKQZHMO+5n5pU".to_string().into_bytes(), 22 | metadata: None, 23 | }; 24 | let share2 = Share { 25 | id: 2, 26 | threshold: 2, 27 | shares_count: 2, 28 | data: "".to_string().into_bytes(), 29 | metadata: None, 30 | }; 31 | 32 | let shares = vec![share1, share2]; 33 | 34 | recover_secret(&shares).unwrap(); 35 | } 36 | 37 | #[test] 38 | #[should_panic(expected = "ShareParsingInvalidShareId")] 39 | fn test_recover_0_share_num() { 40 | let share1 = Share { 41 | id: 0, 42 | threshold: 2, 43 | shares_count: 2, 44 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 45 | metadata: None, 46 | }; 47 | let share2 = Share { 48 | id: 1, 49 | threshold: 2, 50 | shares_count: 2, 51 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 52 | metadata: None, 53 | }; 54 | 55 | let shares = vec![share1, share2]; 56 | 57 | recover_secret(&shares).unwrap(); 58 | } 59 | 60 | // --- 61 | // TODO: will be implemented when serialization is done for thss shares 62 | // --- 63 | // #[test] 64 | // #[should_panic(expected = "ShareParsingError")] 65 | // fn test_recover_invalid_b64() { 66 | // let share1 = Share { 67 | // id: 1, 68 | // threshold: 2, 69 | // shares_count: 2, 70 | // data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 71 | // metadata: None 72 | // }; 73 | // let share2 = Share { 74 | // id: 2, 75 | // threshold: 2, 76 | // shares_count: 2, 77 | // data: "YJZQDG((((m22Y)))77Gw".to_string().into_bytes(), 78 | // metadata: None 79 | // }; 80 | // 81 | // let shares = vec![share1, share2]; 82 | // 83 | // recover_secret(&shares).unwrap(); 84 | // } 85 | 86 | #[test] 87 | #[should_panic(expected = "DuplicateShareId")] 88 | fn test_recover_duplicate_shares_number() { 89 | let share1 = Share { 90 | id: 1, 91 | threshold: 2, 92 | shares_count: 2, 93 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 94 | metadata: None, 95 | }; 96 | let share2 = Share { 97 | id: 1, 98 | threshold: 2, 99 | shares_count: 2, 100 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 101 | metadata: None, 102 | }; 103 | 104 | let shares = vec![share1, share2]; 105 | 106 | recover_secret(&shares).unwrap(); 107 | } 108 | 109 | #[test] 110 | #[should_panic(expected = "MissingShares")] 111 | fn test_recover_too_few_shares() { 112 | let share1 = Share { 113 | id: 1, 114 | threshold: 3, 115 | shares_count: 3, 116 | data: "1YAYwmOHqZ69jA".to_string().into_bytes(), 117 | metadata: None, 118 | }; 119 | let share2 = Share { 120 | id: 2, 121 | threshold: 3, 122 | shares_count: 3, 123 | data: "YJZQDGm22Y77Gw".to_string().into_bytes(), 124 | metadata: None, 125 | }; 126 | 127 | let shares = vec![share1, share2]; 128 | 129 | recover_secret(&shares).unwrap(); 130 | } 131 | --------------------------------------------------------------------------------