diff --git a/Cargo.toml b/Cargo.toml index 740d778..8cd1e48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rusty_secrets" version = "0.0.3" authors = ["Frederic Jacobs ", "sellibitze"] -description = "Implementation of threshold Shamir secret sharing in the Rust programming language." +description = "Implementation of threshold Shamir's secret sharing in the Rust programming language." homepage = "https://github.com/freedomofpress/RustySecrets" license = "BSD-3-Clause" readme = "README.md" diff --git a/docs/implementors/core/convert/trait.From.js b/docs/implementors/core/convert/trait.From.js index 8fa02a8..f5ad3af 100644 --- a/docs/implementors/core/convert/trait.From.js +++ b/docs/implementors/core/convert/trait.From.js @@ -1,5 +1,5 @@ (function() {var implementors = {}; -implementors["rusty_secrets"] = ["impl From<Error> for Error",]; +implementors["rusty_secrets"] = ["impl From<Error> for RustyError","impl From<RustyError> for Error",]; if (window.register_implementors) { window.register_implementors(implementors); diff --git a/docs/implementors/core/fmt/trait.Debug.js b/docs/implementors/core/fmt/trait.Debug.js new file mode 100644 index 0000000..b50ee50 --- /dev/null +++ b/docs/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,10 @@ +(function() {var implementors = {}; +implementors["rusty_secrets"] = ["impl Debug for RustyError",]; + + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } + +})() diff --git a/docs/implementors/core/fmt/trait.Display.js b/docs/implementors/core/fmt/trait.Display.js new file mode 100644 index 0000000..a91e319 --- /dev/null +++ b/docs/implementors/core/fmt/trait.Display.js @@ -0,0 +1,10 @@ +(function() {var implementors = {}; +implementors["rusty_secrets"] = ["impl Display for RustyError",]; + + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } + +})() diff --git a/docs/implementors/std/error/trait.Error.js b/docs/implementors/std/error/trait.Error.js new file mode 100644 index 0000000..06bd7e7 --- /dev/null +++ b/docs/implementors/std/error/trait.Error.js @@ -0,0 +1,10 @@ +(function() {var implementors = {}; +implementors["rusty_secrets"] = ["impl Error for RustyError",]; + + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } + +})() diff --git a/docs/playpen.js b/docs/playpen.js deleted file mode 100644 index cad97c0..0000000 --- a/docs/playpen.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*jslint browser: true, es5: true */ -/*globals $: true, rootPath: true */ - -document.addEventListener('DOMContentLoaded', function() { - 'use strict'; - - if (!window.playgroundUrl) { - return; - } - - var featureRegexp = new RegExp('^\s*#!\\[feature\\(\.*?\\)\\]'); - var elements = document.querySelectorAll('pre.rust-example-rendered'); - - Array.prototype.forEach.call(elements, function(el) { - el.onmouseover = function(e) { - if (el.contains(e.relatedTarget)) { - return; - } - - var a = el.querySelectorAll('a.test-arrow')[0]; - - var code = el.previousElementSibling.textContent; - - var channel = ''; - if (featureRegexp.test(code)) { - channel = '&version=nightly'; - } - - a.setAttribute('href', window.playgroundUrl + '?code=' + - encodeURIComponent(code) + channel); - }; - }); -}); diff --git a/docs/rustdoc.css b/docs/rustdoc.css index cad5fae..f49b855 100644 --- a/docs/rustdoc.css +++ b/docs/rustdoc.css @@ -570,8 +570,11 @@ pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } pre.rust .lifetime { color: #B76514; } +pre.rust .question-mark { + color: #ff9011; + font-weight: bold; +} -.rusttest { display: none; } pre.rust { position: relative; } a.test-arrow { background-color: rgba(78, 139, 202, 0.2); @@ -585,6 +588,7 @@ a.test-arrow { } a.test-arrow:hover{ background-color: #4e8bca; + text-decoration: none; } .section-header:hover a:after { diff --git a/docs/rusty_secrets/RustyError.t.html b/docs/rusty_secrets/RustyError.t.html new file mode 100644 index 0000000..5a05371 --- /dev/null +++ b/docs/rusty_secrets/RustyError.t.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to struct.RustyError.html...

+ + + \ No newline at end of file diff --git a/docs/rusty_secrets/custom_error/RustyError.t.html b/docs/rusty_secrets/custom_error/RustyError.t.html new file mode 100644 index 0000000..5a05371 --- /dev/null +++ b/docs/rusty_secrets/custom_error/RustyError.t.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to struct.RustyError.html...

+ + + \ No newline at end of file diff --git a/docs/rusty_secrets/custom_error/struct.RustyError.html b/docs/rusty_secrets/custom_error/struct.RustyError.html new file mode 100644 index 0000000..5defab4 --- /dev/null +++ b/docs/rusty_secrets/custom_error/struct.RustyError.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../rusty_secrets/struct.RustyError.html...

+ + + \ No newline at end of file diff --git a/docs/rusty_secrets/index.html b/docs/rusty_secrets/index.html index e029e69..2a7d305 100644 --- a/docs/rusty_secrets/index.html +++ b/docs/rusty_secrets/index.html @@ -47,22 +47,30 @@ [] - [src] -

RustySecrets implements Shamir Secret Sharing in Rust. It provides the possibility to sign shares.

-

Functions

+ [src] +

RustySecrets implements Shamir's secret sharing in Rust. It provides the possibility to sign shares.

+

Modules

- + - + +
generate_sharessss -

Performs threshold k-out-of-n Shamir secret sharing.

+

SSS provides Shamir's secret sharing with raw data.

recover_secretwrapped_secrets -

Recovers the secret from a k-out-of-n Shamir secret sharing.

+

(Beta) wrapped_secrets provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data.

+

Structs

+ + + +
RustyError +

Error struct used for generating an io::Error from a generic description.

@@ -120,11 +128,9 @@ - \ No newline at end of file diff --git a/docs/rusty_secrets/sidebar-items.js b/docs/rusty_secrets/sidebar-items.js index a91218c..9ccf832 100644 --- a/docs/rusty_secrets/sidebar-items.js +++ b/docs/rusty_secrets/sidebar-items.js @@ -1 +1 @@ -initSidebarItems({"fn":[["generate_shares","Performs threshold k-out-of-n Shamir secret sharing."],["recover_secret","Recovers the secret from a k-out-of-n Shamir secret sharing."]]}); \ No newline at end of file +initSidebarItems({"mod":[["sss","SSS provides Shamir's secret sharing with raw data."],["wrapped_secrets","(Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data."]],"struct":[["RustyError","Error struct used for generating an `io::Error` from a generic description."]]}); \ No newline at end of file diff --git a/docs/rusty_secrets/sss/fn.generate_shares.html b/docs/rusty_secrets/sss/fn.generate_shares.html index ff05935..9e6fce9 100644 --- a/docs/rusty_secrets/sss/fn.generate_shares.html +++ b/docs/rusty_secrets/sss/fn.generate_shares.html @@ -1,10 +1,126 @@ - + + + + + + + rusty_secrets::sss::generate_shares - Rust + + + + + + + - -

Redirecting to ../../rusty_secrets/fn.generate_shares.html...

- + + + + + + + + + +
+

Function rusty_secrets::sss::generate_shares + + [] + + [src]

+
pub fn generate_shares(k: u8,
                       n: u8,
                       secret: &[u8],
                       sign_shares: bool)
                       -> Result<Vec<String>>

Performs threshold k-out-of-n Shamir's secret sharing.

+ +

Examples

+
+use rusty_secrets::sss::generate_shares;
+let secret = "These programs were never about terrorism: they’re about economic spying,
+              social control, and diplomatic manipulation. They’re about power.".to_string();
+
+match generate_shares(7, 10, &secret.into_bytes(), true){
+    Ok(shares) => {
+        // Do something with the shares
+    },
+    Err(_) => {}// Deal with error}
+}
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/rusty_secrets/sss/fn.recover_secret.html b/docs/rusty_secrets/sss/fn.recover_secret.html index 582baaa..0700e91 100644 --- a/docs/rusty_secrets/sss/fn.recover_secret.html +++ b/docs/rusty_secrets/sss/fn.recover_secret.html @@ -1,10 +1,131 @@ - + + + + + + + rusty_secrets::sss::recover_secret - Rust + + + + + + + - -

Redirecting to ../../rusty_secrets/fn.recover_secret.html...

- + + + + + + + + + +
+

Function rusty_secrets::sss::recover_secret + + [] + + [src]

+
pub fn recover_secret(shares: Vec<String>,
                      verify_signatures: bool)
                      -> Result<Vec<u8>, RustyError>

Recovers the secret from a k-out-of-n Shamir's secret sharing.

+ +

At least k distinct shares need to be provided to recover the share.

+ +

Examples

+
+use rusty_secrets::sss::recover_secret;
+let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string();
+let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string();
+let shares = vec![share1, share2];
+
+match recover_secret(shares, false) {
+    Ok(secret) => {
+        // Do something with the secret
+    },
+    Err(e) => {
+        // Deal with the error
+    }
+}
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/rusty_secrets/sss/index.html b/docs/rusty_secrets/sss/index.html new file mode 100644 index 0000000..f233ee5 --- /dev/null +++ b/docs/rusty_secrets/sss/index.html @@ -0,0 +1,128 @@ + + + + + + + + + + rusty_secrets::sss - Rust + + + + + + + + + + + + + + + + + +
+

Module rusty_secrets::sss + + [] + + [src]

+

SSS provides Shamir's secret sharing with raw data.

+

Functions

+ + + + + + + + +
generate_shares +

Performs threshold k-out-of-n Shamir's secret sharing.

+
recover_secret +

Recovers the secret from a k-out-of-n Shamir's secret sharing.

+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/rusty_secrets/sss/sidebar-items.js b/docs/rusty_secrets/sss/sidebar-items.js new file mode 100644 index 0000000..d8f4902 --- /dev/null +++ b/docs/rusty_secrets/sss/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["generate_shares","Performs threshold k-out-of-n Shamir's secret sharing."],["recover_secret","Recovers the secret from a k-out-of-n Shamir's secret sharing."]]}); \ No newline at end of file diff --git a/docs/rusty_secrets/struct.RustyError.html b/docs/rusty_secrets/struct.RustyError.html new file mode 100644 index 0000000..b785d23 --- /dev/null +++ b/docs/rusty_secrets/struct.RustyError.html @@ -0,0 +1,135 @@ + + + + + + + + + + rusty_secrets::RustyError - Rust + + + + + + + + + + + + + + + + + +
+

Struct rusty_secrets::RustyError + + [] + + [src]

+
pub struct RustyError { /* fields omitted */ }

Error struct used for generating an io::Error from a generic description.

+

Methods

impl RustyError
[src]

+

+

Returns a RustyError with a given RustyErrorType.

+

+

Returns the index of the share that raised the error, if any.

+

+

Returns the group of shares that were generated during the same secret share. +It can be used to provide a debug message to the user telling him what shares are incompatible.

+

Trait Implementations

impl Debug for RustyError
[src]

+

+

Formats the value using the given formatter.

+

impl Display for RustyError
[src]

+

+

Formats the value using the given formatter.

+

impl Error for RustyError
[src]

+

+

A short description of the error. Read more

+

+

The lower-level cause of this error, if any. Read more

+

impl From<Error> for RustyError
[src]

+

+

Performs the conversion.

+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/rusty_secrets/fn.generate_shares.html b/docs/rusty_secrets/wrapped_secrets/fn.generate_shares.html similarity index 57% rename from docs/rusty_secrets/fn.generate_shares.html rename to docs/rusty_secrets/wrapped_secrets/fn.generate_shares.html index cbae85d..0da94c1 100644 --- a/docs/rusty_secrets/fn.generate_shares.html +++ b/docs/rusty_secrets/wrapped_secrets/fn.generate_shares.html @@ -7,10 +7,10 @@ - rusty_secrets::generate_shares - Rust + rusty_secrets::wrapped_secrets::generate_shares - Rust - - + + @@ -28,7 +28,7 @@
-

Function rusty_secrets::generate_shares +

Function rusty_secrets::wrapped_secrets::generate_shares [] - [src]

-
pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> Result<Vec<String>>

Performs threshold k-out-of-n Shamir secret sharing.

+ [src]

+
pub fn generate_shares(k: u8,
                       n: u8,
                       secret: &[u8],
                       mime_type: &str,
                       sign_shares: bool)
                       -> Result<Vec<String>>

Performs threshold k-out-of-n Shamir's secret sharing.

Examples

-use rusty_secrets::generate_shares;
+use rusty_secrets::wrapped_secrets::generate_shares;
 let secret = "These programs were never about terrorism: they’re about economic spying,
               social control, and diplomatic manipulation. They’re about power.".to_string();
 
-match generate_shares(7, 10, &secret.into_bytes(), true){
+match generate_shares(7, 10, &secret.into_bytes(), "text/html", true){
     Ok(shares) => {
         // Do something with the shares
     },
     Err(_) => {}// Deal with error}
-}Run
+}
@@ -116,13 +116,11 @@ - - - - + + + \ No newline at end of file diff --git a/docs/rusty_secrets/fn.recover_secret.html b/docs/rusty_secrets/wrapped_secrets/fn.recover_secret.html similarity index 71% rename from docs/rusty_secrets/fn.recover_secret.html rename to docs/rusty_secrets/wrapped_secrets/fn.recover_secret.html index e8746f4..25d918f 100644 --- a/docs/rusty_secrets/fn.recover_secret.html +++ b/docs/rusty_secrets/wrapped_secrets/fn.recover_secret.html @@ -7,10 +7,10 @@ - rusty_secrets::recover_secret - Rust + rusty_secrets::wrapped_secrets::recover_secret - Rust - - + + @@ -28,7 +28,7 @@
-

Function rusty_secrets::recover_secret +

Function rusty_secrets::wrapped_secrets::recover_secret [] - [src]

-
pub fn recover_secret(shares: Vec<String>, verify_signatures: bool) -> Result<Vec<u8>>

Recovers the secret from a k-out-of-n Shamir secret sharing.

+ [src]

+
pub fn recover_secret(shares: Vec<String>,
                      verify_signatures: bool)
                      -> Result<RustySecret, RustyError>

Recovers the secret from a k-out-of-n Shamir's secret sharing.

At least k distinct shares need to be provided to recover the share.

Examples

-use rusty_secrets::recover_secret;
+use rusty_secrets::wrapped_secrets::recover_secret;
 let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string();
 let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string();
 let shares = vec![share1, share2];
@@ -66,7 +66,7 @@
     Err(e) => {
         // Deal with the error
     }
-}Run
+}
@@ -121,13 +121,11 @@ - - - - + + + \ No newline at end of file diff --git a/docs/rusty_secrets/generate_shares.v.html b/docs/rusty_secrets/wrapped_secrets/generate_shares.v.html similarity index 100% rename from docs/rusty_secrets/generate_shares.v.html rename to docs/rusty_secrets/wrapped_secrets/generate_shares.v.html diff --git a/docs/rusty_secrets/wrapped_secrets/index.html b/docs/rusty_secrets/wrapped_secrets/index.html new file mode 100644 index 0000000..8d83beb --- /dev/null +++ b/docs/rusty_secrets/wrapped_secrets/index.html @@ -0,0 +1,128 @@ + + + + + + + + + + rusty_secrets::wrapped_secrets - Rust + + + + + + + + + + + + + + + + + +
+

Module rusty_secrets::wrapped_secrets + + [] + + [src]

+

(Beta) wrapped_secrets provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data.

+

Functions

+ + + + + + + + +
generate_shares +

Performs threshold k-out-of-n Shamir's secret sharing.

+
recover_secret +

Recovers the secret from a k-out-of-n Shamir's secret sharing.

+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/rusty_secrets/recover_secret.v.html b/docs/rusty_secrets/wrapped_secrets/recover_secret.v.html similarity index 100% rename from docs/rusty_secrets/recover_secret.v.html rename to docs/rusty_secrets/wrapped_secrets/recover_secret.v.html diff --git a/docs/rusty_secrets/wrapped_secrets/sidebar-items.js b/docs/rusty_secrets/wrapped_secrets/sidebar-items.js new file mode 100644 index 0000000..d8f4902 --- /dev/null +++ b/docs/rusty_secrets/wrapped_secrets/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["generate_shares","Performs threshold k-out-of-n Shamir's secret sharing."],["recover_secret","Recovers the secret from a k-out-of-n Shamir's secret sharing."]]}); \ No newline at end of file diff --git a/docs/search-index.js b/docs/search-index.js index 15c0114..d5b7059 100644 --- a/docs/search-index.js +++ b/docs/search-index.js @@ -1,3 +1,3 @@ var searchIndex = {}; -searchIndex["rusty_secrets"] = {"doc":"`RustySecrets` implements Shamir Secret Sharing in Rust. It provides the possibility to sign shares.","items":[[5,"generate_shares","rusty_secrets","Performs threshold k-out-of-n Shamir secret sharing.",null,null],[5,"recover_secret","","Recovers the secret from a k-out-of-n Shamir secret sharing.",null,{"inputs":[{"name":"vec"},{"name":"bool"}],"output":{"name":"result"}}]],"paths":[]}; +searchIndex["rusty_secrets"] = {"doc":"`RustySecrets` implements Shamir's secret sharing in Rust. It provides the possibility to sign shares.","items":[[3,"RustyError","rusty_secrets","Error struct used for generating an `io::Error` from a generic description.",null,null],[11,"fmt","","",0,null],[11,"with_type","","Returns a `RustyError` with a given `RustyErrorType`.",0,{"inputs":[{"name":"rustyerrortypes"}],"output":{"name":"rustyerror"}}],[11,"share_index","","Returns the index of the share that raised the error, if any.",0,null],[11,"share_groups","","Returns the group of shares that were generated during the same secret share.\nIt can be used to provide a debug message to the user telling him what shares are incompatible.",0,null],[11,"fmt","","",0,null],[11,"description","","",0,null],[11,"cause","","",0,null],[11,"from","","",0,{"inputs":[{"name":"error"}],"output":{"name":"rustyerror"}}],[0,"sss","","SSS provides Shamir's secret sharing with raw data.",null,null],[5,"generate_shares","rusty_secrets::sss","Performs threshold k-out-of-n Shamir's secret sharing.",null,null],[5,"recover_secret","","Recovers the secret from a k-out-of-n Shamir's secret sharing.",null,{"inputs":[{"name":"vec"},{"name":"bool"}],"output":{"name":"result"}}],[0,"wrapped_secrets","rusty_secrets","(Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data.",null,null],[5,"generate_shares","rusty_secrets::wrapped_secrets","Performs threshold k-out-of-n Shamir's secret sharing.",null,null],[5,"recover_secret","","Recovers the secret from a k-out-of-n Shamir's secret sharing.",null,{"inputs":[{"name":"vec"},{"name":"bool"}],"output":{"name":"result"}}]],"paths":[[3,"RustyError"]]}; initSearch(searchIndex); diff --git a/docs/src/rusty_secrets/src/custom_error.rs.html b/docs/src/rusty_secrets/src/custom_error.rs.html index b0a71fa..81f49b2 100644 --- a/docs/src/rusty_secrets/src/custom_error.rs.html +++ b/docs/src/rusty_secrets/src/custom_error.rs.html @@ -42,125 +42,294 @@ -
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70
-71
-72
-73
-74
-75
-76
-77
-78
-79
-80
-81
-82
-83
-84
-85
-86
-87
-88
-89
-90
-91
-92
-93
-94
+    
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
 
 use std::convert;
-use std::error;
+use std::error::Error;
 use std::fmt;
 use std::io;
 use std::num;
 
 /// Error struct used for generating an `io::Error` from a generic description.
 #[derive(Debug)]
-pub struct Error {
+pub struct RustyError {
     descr: &'static str,
     detail: Option<String>,
+    share_index: Option<u8>,
+    share_groups: Option<Vec<Vec<u8>>>
 }
 
-impl Error {
+#[derive(Debug)]
+pub enum RustyErrorTypes {
+    DuplicateShareNum(u8),
+    DuplicateShareData(u8),
+    EmptyShares,
+    IncompatibleSets(Vec<Vec<u8>>),
+    InvalidSignature(u8, String),
+    MissingShares(u8, usize),
+    MissingSignature(u8),
+    SecretDeserializationIssue,
+    ShareParsingError(u8, String)
+}
+
+impl RustyError {
     /// Initializes a new error with a description and optional detail string.
-    pub fn new(descr: &'static str, detail: Option<String>) -> Error {
-        Error {
+    fn new(descr: &'static str, detail: Option<String>, share_index: Option<u8>, share_groups: Option<Vec<Vec<u8>>>) -> RustyError {
+        RustyError {
             descr: descr,
             detail: detail,
+            share_index: share_index,
+            share_groups: share_groups
+        }
+    }
+
+    /// Returns a `RustyError` with a given `RustyErrorType`.
+    pub fn with_type(error_type: RustyErrorTypes) -> RustyError {
+        RustyError {
+            descr: RustyError::descr_for_type(&error_type),
+            detail: RustyError::detail_for_type(&error_type),
+            share_index: RustyError::share_num_for_type(&error_type),
+            share_groups: RustyError::share_groups_for_type(error_type),
+        }
+    }
+
+    /// Returns the index of the share that raised the error, if any.
+    pub fn share_index(&self) -> Option<u8> {
+        self.share_index
+    }
+
+    /// Returns the group of shares that were generated during the same secret share.
+    /// It can be used to provide a debug message to the user telling him what shares are incompatible.
+    pub fn share_groups(&self) -> Option<Vec<Vec<u8>>> {
+        self.share_groups.clone()
+    }
+
+    fn descr_for_type(error_type: &RustyErrorTypes) -> &'static str {
+        match *error_type {
+            RustyErrorTypes::EmptyShares => "No shares were provided.",
+            RustyErrorTypes::IncompatibleSets(_) => "The shares are incompatible with each other.",
+            RustyErrorTypes::InvalidSignature(_, _) => "The signature of this share is not valid.",
+            RustyErrorTypes::MissingShares(_, _) => "The number of shares provided is insufficient to recover the secret.",
+            RustyErrorTypes::MissingSignature(_) => "Signature is missing while shares are required to be signed.",
+            RustyErrorTypes::SecretDeserializationIssue => "An issue was encountered deserializing the secret.
+            Updating to the latest version of RustySecrets might help fix this.",
+            RustyErrorTypes::ShareParsingError(_, _) => "This share is incorrectly formatted.",
+            RustyErrorTypes::DuplicateShareNum(_) => "This share number has already been used by a previous share.",
+            RustyErrorTypes::DuplicateShareData(_) => "The data encoded in this share is the same as the one found in a previous share."
+        }
+    }
+
+    fn detail_for_type(error_type: &RustyErrorTypes) -> Option<String> {
+        match *error_type {
+            RustyErrorTypes::MissingShares(required, found) => Some(format!("{} shares are required to recover the secret,
+                                                                   found only {}.", required, found)),
+            RustyErrorTypes::ShareParsingError(_, ref description) => Some(description.clone()),
+            _ => None
+        }
+    }
+
+    fn share_groups_for_type(error_type: RustyErrorTypes) -> Option<Vec<Vec<u8>>>{
+        match error_type {
+            RustyErrorTypes::IncompatibleSets(groups) => Some(groups),
+            _ => None
+        }
+    }
+
+    fn share_num_for_type(error_type: &RustyErrorTypes) -> Option<u8> {
+        match *error_type {
+            RustyErrorTypes::InvalidSignature(share_num, _)
+            | RustyErrorTypes::MissingSignature(share_num)
+            | RustyErrorTypes::ShareParsingError(share_num, _)
+            | RustyErrorTypes::DuplicateShareNum(share_num)
+            | RustyErrorTypes::DuplicateShareData(share_num) => Some(share_num),
+            _ => None
         }
     }
 }
 
-impl fmt::Display for Error {
+impl fmt::Display for RustyError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.detail {
             None => write!(f, "{}", self.descr),
@@ -169,42 +338,51 @@
     }
 }
 
-impl error::Error for Error {
+impl Error for RustyError {
     fn description(&self) -> &str {
         self.descr
     }
-    fn cause(&self) -> Option<&error::Error> {
+    fn cause(&self) -> Option<&Error> {
         None
     }
 }
 
-impl From<Error> for io::Error {
-    fn from(me: Error) -> io::Error {
+impl From<io::Error> for RustyError {
+    fn from(err: io::Error) -> RustyError {
+        let descr = err.description().to_owned();
+
+        RustyError::new("from io:Error", Some(descr), None, None)
+    }
+}
+
+impl From<RustyError> for io::Error {
+    fn from(me: RustyError) -> io::Error {
         io::Error::new(io::ErrorKind::Other, me)
     }
 }
 
 /// Returns an `io::Error` from description string and optional detail string.
 /// Particularly useful in `Result` expressions.
-pub fn other_io_err(descr: &'static str, detail: Option<String>) -> io::Error {
-    convert::From::from(Error::new(descr, detail))
+pub fn other_io_err(descr: &'static str, detail: Option<String>,
+                    share_num: Option<u8>, share_groups: Option<Vec<Vec<u8>>>) -> io::Error {
+    convert::From::from(RustyError::new(descr, detail, share_num, share_groups))
 }
 
-/// maps a `ParseIntError` to an `io::Error`
-pub fn pie2io(p: num::ParseIntError) -> io::Error {
-    convert::From::from(Error::new("Integer parsing error", Some(p.to_string())))
+/// maps a `ParseIntError` to an `Error`
+pub fn pie2error(p: num::ParseIntError) -> RustyError {
+    RustyError::new("Integer parsing error", Some(p.to_string()), None, None)
 }
 
 #[cfg(test)]
 mod tests_custom_err {
     use std::error;
-    use custom_error;
+    use custom_error::RustyError;
 
     #[test]
     fn test_custom_error() {
         let desc = "Boring error description";
         let detail = "More of it";
-        let ewd = custom_error::Error::new(desc, Some(detail.to_string()));
+        let ewd = RustyError::new(desc, Some(detail.to_string()), None, None);
 
         assert_eq!(error::Error::description(&ewd), desc);
         match error::Error::cause(&ewd) {
@@ -212,7 +390,7 @@
             None => assert!(true),
         }
         let _formated_err = format!("{}", ewd);
-        let ewod = custom_error::Error::new(desc, None);
+        let ewod = RustyError::new(desc, None, None, None);
         let _formated_err = format!("{}", ewod);
     }
 }
@@ -220,12 +398,12 @@
 #[cfg(test)]
 mod tests_std_err {
     use std::error::Error;
-    use custom_error::pie2io;
+    use custom_error::pie2error;
 
     #[test]
     fn test_parse_errors() {
         let nan = "2a".to_string();
-        match nan.parse::<u8>().map_err(pie2io) {
+        match nan.parse::<u8>().map_err(pie2error) {
             Ok(_) => assert!(false),
             Err(x) => assert_eq!("Integer parsing error", x.description()),
         }
@@ -288,11 +466,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/gf256.rs.html b/docs/src/rusty_secrets/src/gf256.rs.html
index 70b9627..9f775dc 100644
--- a/docs/src/rusty_secrets/src/gf256.rs.html
+++ b/docs/src/rusty_secrets/src/gf256.rs.html
@@ -280,11 +280,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/interpolation.rs.html b/docs/src/rusty_secrets/src/interpolation.rs.html
index 5ca9070..897abb2 100644
--- a/docs/src/rusty_secrets/src/interpolation.rs.html
+++ b/docs/src/rusty_secrets/src/interpolation.rs.html
@@ -180,11 +180,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/lib.rs.html b/docs/src/rusty_secrets/src/lib.rs.html
index 4c827ce..c78bd87 100644
--- a/docs/src/rusty_secrets/src/lib.rs.html
+++ b/docs/src/rusty_secrets/src/lib.rs.html
@@ -75,7 +75,11 @@
 31
 32
 33
+34
+35
 
+//! `RustySecrets` implements Shamir's secret sharing in Rust. It provides the possibility to sign shares.
+
 #![deny(
     missing_docs,
     missing_debug_implementations, missing_copy_implementations,
@@ -84,8 +88,6 @@
     unused_import_braces, unused_qualifications
 )]
 
-//! `RustySecrets` implements Shamir Secret Sharing in Rust. It provides the possibility to sign shares.
-
 extern crate protobuf;
 extern crate rustc_serialize as serialize;
 extern crate rand;
@@ -99,13 +101,15 @@
 mod custom_error;
 mod gf256;
 mod interpolation;
+mod secret;
 mod share_data;
 mod share_format;
-mod sss;
 mod validation;
 
-pub use sss::generate_shares;
-pub use sss::recover_secret;
+pub use custom_error::RustyError;
+
+pub mod sss;
+pub mod wrapped_secrets;
 
 #[cfg(test)]
 mod tests;
@@ -166,11 +170,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/secret.rs.html b/docs/src/rusty_secrets/src/secret.rs.html
new file mode 100644
index 0000000..a1d3bd5
--- /dev/null
+++ b/docs/src/rusty_secrets/src/secret.rs.html
@@ -0,0 +1,890 @@
+
+
+
+    
+    
+    
+    
+    
+
+    secret.rs.html -- source
+
+    
+    
+    
+
+    
+    
+
+
+    
+
+    
+
+    
+
+    
+
+    
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+
+// This file is generated. Do not edit
+// @generated
+
+// https://github.com/Manishearth/rust-clippy/issues/702
+#![allow(unknown_lints)]
+#![allow(clippy)]
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#![allow(box_pointers)]
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+#![allow(trivial_casts)]
+#![allow(unsafe_code)]
+#![allow(unused_imports)]
+#![allow(unused_results)]
+
+use protobuf::Message as Message_imported_for_functions;
+use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions;
+
+#[derive(Clone,Default)]
+pub struct RustySecret {
+    // message fields
+    version: ::std::option::Option<RustySecretsVersions>,
+    secret: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    mime_type: ::protobuf::SingularField<::std::string::String>,
+    // special fields
+    unknown_fields: ::protobuf::UnknownFields,
+    cached_size: ::std::cell::Cell<u32>,
+}
+
+// see codegen.rs for the explanation why impl Sync explicitly
+unsafe impl ::std::marker::Sync for RustySecret {}
+
+impl RustySecret {
+    pub fn new() -> RustySecret {
+        ::std::default::Default::default()
+    }
+
+    pub fn default_instance() -> &'static RustySecret {
+        static mut instance: ::protobuf::lazy::Lazy<RustySecret> = ::protobuf::lazy::Lazy {
+            lock: ::protobuf::lazy::ONCE_INIT,
+            ptr: 0 as *const RustySecret,
+        };
+        unsafe {
+            instance.get(|| {
+                RustySecret {
+                    version: ::std::option::Option::None,
+                    secret: ::protobuf::SingularField::none(),
+                    mime_type: ::protobuf::SingularField::none(),
+                    unknown_fields: ::protobuf::UnknownFields::new(),
+                    cached_size: ::std::cell::Cell::new(0),
+                }
+            })
+        }
+    }
+
+    // optional .RustySecretsVersions version = 1;
+
+    pub fn clear_version(&mut self) {
+        self.version = ::std::option::Option::None;
+    }
+
+    pub fn has_version(&self) -> bool {
+        self.version.is_some()
+    }
+
+    // Param is passed by value, moved
+    pub fn set_version(&mut self, v: RustySecretsVersions) {
+        self.version = ::std::option::Option::Some(v);
+    }
+
+    pub fn get_version(&self) -> RustySecretsVersions {
+        self.version.unwrap_or(RustySecretsVersions::INITIAL_RELEASE)
+    }
+
+    // optional bytes secret = 2;
+
+    pub fn clear_secret(&mut self) {
+        self.secret.clear();
+    }
+
+    pub fn has_secret(&self) -> bool {
+        self.secret.is_some()
+    }
+
+    // Param is passed by value, moved
+    pub fn set_secret(&mut self, v: ::std::vec::Vec<u8>) {
+        self.secret = ::protobuf::SingularField::some(v);
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec<u8> {
+        if self.secret.is_none() {
+            self.secret.set_default();
+        };
+        self.secret.as_mut().unwrap()
+    }
+
+    // Take field
+    pub fn take_secret(&mut self) -> ::std::vec::Vec<u8> {
+        self.secret.take().unwrap_or_else(|| ::std::vec::Vec::new())
+    }
+
+    pub fn get_secret(&self) -> &[u8] {
+        match self.secret.as_ref() {
+            Some(v) => &v,
+            None => &[],
+        }
+    }
+
+    // optional string mime_type = 3;
+
+    pub fn clear_mime_type(&mut self) {
+        self.mime_type.clear();
+    }
+
+    pub fn has_mime_type(&self) -> bool {
+        self.mime_type.is_some()
+    }
+
+    // Param is passed by value, moved
+    pub fn set_mime_type(&mut self, v: ::std::string::String) {
+        self.mime_type = ::protobuf::SingularField::some(v);
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_mime_type(&mut self) -> &mut ::std::string::String {
+        if self.mime_type.is_none() {
+            self.mime_type.set_default();
+        };
+        self.mime_type.as_mut().unwrap()
+    }
+
+    // Take field
+    pub fn take_mime_type(&mut self) -> ::std::string::String {
+        self.mime_type.take().unwrap_or_else(|| ::std::string::String::new())
+    }
+
+    pub fn get_mime_type(&self) -> &str {
+        match self.mime_type.as_ref() {
+            Some(v) => &v,
+            None => "",
+        }
+    }
+}
+
+impl ::protobuf::Message for RustySecret {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> {
+        while !try!(is.eof()) {
+            let (field_number, wire_type) = try!(is.read_tag_unpack());
+            match field_number {
+                1 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    };
+                    let tmp = try!(is.read_enum());
+                    self.version = ::std::option::Option::Some(tmp);
+                },
+                2 => {
+                    try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.secret));
+                },
+                3 => {
+                    try!(::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.mime_type));
+                },
+                _ => {
+                    try!(::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields()));
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        for value in &self.version {
+            my_size += ::protobuf::rt::enum_size(1, *value);
+        };
+        for value in &self.secret {
+            my_size += ::protobuf::rt::bytes_size(2, &value);
+        };
+        for value in &self.mime_type {
+            my_size += ::protobuf::rt::string_size(3, &value);
+        };
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> {
+        if let Some(v) = self.version {
+            try!(os.write_enum(1, v.value()));
+        };
+        if let Some(v) = self.secret.as_ref() {
+            try!(os.write_bytes(2, &v));
+        };
+        if let Some(v) = self.mime_type.as_ref() {
+            try!(os.write_string(3, &v));
+        };
+        try!(os.write_unknown_fields(self.get_unknown_fields()));
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn type_id(&self) -> ::std::any::TypeId {
+        ::std::any::TypeId::of::<RustySecret>()
+    }
+
+    fn as_any(&self) -> &::std::any::Any {
+        self as &::std::any::Any
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        ::protobuf::MessageStatic::descriptor_static(None::<Self>)
+    }
+}
+
+impl ::protobuf::MessageStatic for RustySecret {
+    fn new() -> RustySecret {
+        RustySecret::new()
+    }
+
+    fn descriptor_static(_: ::std::option::Option<RustySecret>) -> &'static ::protobuf::reflect::MessageDescriptor {
+        static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy {
+            lock: ::protobuf::lazy::ONCE_INIT,
+            ptr: 0 as *const ::protobuf::reflect::MessageDescriptor,
+        };
+        unsafe {
+            descriptor.get(|| {
+                let mut fields = ::std::vec::Vec::new();
+                fields.push(::protobuf::reflect::accessor::make_singular_enum_accessor(
+                    "version",
+                    RustySecret::has_version,
+                    RustySecret::get_version,
+                ));
+                fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor(
+                    "secret",
+                    RustySecret::has_secret,
+                    RustySecret::get_secret,
+                ));
+                fields.push(::protobuf::reflect::accessor::make_singular_string_accessor(
+                    "mime_type",
+                    RustySecret::has_mime_type,
+                    RustySecret::get_mime_type,
+                ));
+                ::protobuf::reflect::MessageDescriptor::new::<RustySecret>(
+                    "RustySecret",
+                    fields,
+                    file_descriptor_proto()
+                )
+            })
+        }
+    }
+}
+
+impl ::protobuf::Clear for RustySecret {
+    fn clear(&mut self) {
+        self.clear_version();
+        self.clear_secret();
+        self.clear_mime_type();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::cmp::PartialEq for RustySecret {
+    fn eq(&self, other: &RustySecret) -> bool {
+        self.version == other.version &&
+        self.secret == other.secret &&
+        self.mime_type == other.mime_type &&
+        self.unknown_fields == other.unknown_fields
+    }
+}
+
+impl ::std::fmt::Debug for RustySecret {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum RustySecretsVersions {
+    INITIAL_RELEASE = 0,
+}
+
+impl ::protobuf::ProtobufEnum for RustySecretsVersions {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<RustySecretsVersions> {
+        match value {
+            0 => ::std::option::Option::Some(RustySecretsVersions::INITIAL_RELEASE),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [RustySecretsVersions] = &[
+            RustySecretsVersions::INITIAL_RELEASE,
+        ];
+        values
+    }
+
+    fn enum_descriptor_static(_: Option<RustySecretsVersions>) -> &'static ::protobuf::reflect::EnumDescriptor {
+        static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy {
+            lock: ::protobuf::lazy::ONCE_INIT,
+            ptr: 0 as *const ::protobuf::reflect::EnumDescriptor,
+        };
+        unsafe {
+            descriptor.get(|| {
+                ::protobuf::reflect::EnumDescriptor::new("RustySecretsVersions", file_descriptor_proto())
+            })
+        }
+    }
+}
+
+impl ::std::marker::Copy for RustySecretsVersions {
+}
+
+static file_descriptor_proto_data: &'static [u8] = &[
+    0x0a, 0x0c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73,
+    0x0a, 0x0b, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x2f, 0x0a,
+    0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15,
+    0x2e, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x56, 0x65, 0x72,
+    0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16,
+    0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06,
+    0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74,
+    0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54,
+    0x79, 0x70, 0x65, 0x2a, 0x2b, 0x0a, 0x14, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72,
+    0x65, 0x74, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x13, 0x0a, 0x0f, 0x49,
+    0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x00,
+    0x4a, 0xbd, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x0a, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c,
+    0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x0a, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x02, 0x00, 0x04,
+    0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x02, 0x05, 0x19, 0x0a, 0x0b, 0x0a,
+    0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x03, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00,
+    0x02, 0x00, 0x01, 0x12, 0x03, 0x03, 0x08, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00,
+    0x02, 0x12, 0x03, 0x03, 0x1a, 0x1b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x06, 0x00,
+    0x0a, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x06, 0x08, 0x13, 0x0a, 0x0b,
+    0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x07, 0x08, 0x29, 0x0a, 0x0d, 0x0a, 0x05, 0x04,
+    0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0x07, 0x08, 0x06, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00,
+    0x02, 0x00, 0x06, 0x12, 0x03, 0x07, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00,
+    0x01, 0x12, 0x03, 0x07, 0x1d, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12,
+    0x03, 0x07, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x08, 0x08,
+    0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0x08, 0x08, 0x07, 0x29,
+    0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x08, 0x08, 0x0d, 0x0a, 0x0c,
+    0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08, 0x0e, 0x14, 0x0a, 0x0c, 0x0a, 0x05,
+    0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x17, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00,
+    0x02, 0x02, 0x12, 0x03, 0x09, 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x04,
+    0x12, 0x04, 0x09, 0x08, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12,
+    0x03, 0x09, 0x08, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x09,
+    0x0f, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x09, 0x1b, 0x1c,
+    0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+];
+
+static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy {
+    lock: ::protobuf::lazy::ONCE_INIT,
+    ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto,
+};
+
+fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
+    ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap()
+}
+
+pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
+    unsafe {
+        file_descriptor_proto_lazy.get(|| {
+            parse_descriptor_proto()
+        })
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/rusty_secrets/src/share_data.rs.html b/docs/src/rusty_secrets/src/share_data.rs.html index d85e4f4..edd4ca1 100644 --- a/docs/src/rusty_secrets/src/share_data.rs.html +++ b/docs/src/rusty_secrets/src/share_data.rs.html @@ -790,11 +790,9 @@ - \ No newline at end of file diff --git a/docs/src/rusty_secrets/src/share_format.rs.html b/docs/src/rusty_secrets/src/share_format.rs.html index 129b895..7b6e86f 100644 --- a/docs/src/rusty_secrets/src/share_format.rs.html +++ b/docs/src/rusty_secrets/src/share_format.rs.html @@ -128,26 +128,27 @@ 84 85 86 +87
-use custom_error::{other_io_err, pie2io};
+use custom_error::{RustyError, RustyErrorTypes};
+use custom_error::pie2error;
 use digest;
-use merkle_sigs::Proof;
-use merkle_sigs::PublicKey;
+use merkle_sigs::{MerklePublicKey, Proof, PublicKey};
 use protobuf;
 use protobuf::{Message, RepeatedField};
 use serialize;
 use serialize::base64::{self, FromBase64, ToBase64};
 use share_data::ShareData;
-use std::io;
+use std::error::Error;
+
+type ParsedShare = Result<(Vec<u8>, u8, u8, Option<(Vec<Vec<u8>>, Proof<MerklePublicKey>)>), RustyError>;
 
 fn base64_config() -> serialize::base64::Config {
     base64::Config { pad: false, ..base64::STANDARD }
 }
 
-pub fn share_string_from(share: Vec<u8>,
-                         threshold: u8,
-                         share_num: u8,
-                         signature_pair: Option<(Vec<Vec<u8>>, Proof<PublicKey>)>)
+pub fn share_string_from(share: Vec<u8>, threshold: u8, share_num: u8,
+                         signature_pair: Option<(Vec<Vec<u8>>, Proof<MerklePublicKey>)>)
                          -> String {
     let mut share_protobuf = ShareData::new();
     share_protobuf.set_shamir_data(share);
@@ -164,44 +165,45 @@
 
 pub fn share_from_string
     (s: &str,
+     index: u8,
      is_signed: bool)
-     -> io::Result<(Vec<u8>, u8, u8, Option<(Vec<Vec<u8>>, Proof<PublicKey>)>)> {
+     ->  ParsedShare {
     let parts: Vec<_> = s.trim().split('-').collect();
 
     if parts.len() != 3 {
-        return Err(other_io_err("Share parse error: Expected 3 parts separated by a minus sign",
-                                None));
+        return Err(RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Expected 3 parts separated by a minus sign. Found {}.", s))));
     }
     let (k, n, p3) = {
         let mut iter = parts.into_iter();
-        let k = try!(iter.next().unwrap().parse::<u8>().map_err(pie2io));
-        let n = try!(iter.next().unwrap().parse::<u8>().map_err(pie2io));
+        let k = try!(iter.next().unwrap().parse::<u8>().map_err(pie2error));
+        let n = try!(iter.next().unwrap().parse::<u8>().map_err(pie2error));
         let p3 = iter.next().unwrap();
         (k, n, p3)
     };
     if k < 1 || n < 1 {
-        return Err(other_io_err("Share parse error: Illegal K,N parameters", None));
+        return Err(RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Found illegal parameters K: {} N: {}.", k, n))));
     }
 
     let raw_data = try!(p3.from_base64().map_err(|_| {
-        other_io_err("Share parse error: Base64 decoding of data block failed",
-                     None)
+        RustyError::with_type(RustyErrorTypes::ShareParsingError(index, "Base64 decoding of data block failed".to_owned()))
     }));
 
     let protobuf_data = try!(protobuf::parse_from_bytes::<ShareData>(raw_data.as_slice())
-        .map_err(|_| other_io_err("Share parse error: Protobuffer could not be decoded.", None)));
-
+        .map_err(|e| RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Protobuf decoding of data block failed with error: {} .", e.description())))));
 
     let share = Vec::from(protobuf_data.get_shamir_data());
 
     if is_signed {
-        let p = Proof::parse_from_bytes(protobuf_data.get_proof(), digest).unwrap().unwrap();
+        let p_result = Proof::parse_from_bytes(protobuf_data.get_proof(), digest);
+
+        let p_opt = p_result.unwrap();
+        let p = p_opt.unwrap();
 
         let proof = Proof {
             algorithm: digest,
             lemma: p.lemma,
             root_hash: p.root_hash,
-            value: PublicKey::from_vec(p.value, digest).unwrap(),
+            value: MerklePublicKey::new(PublicKey::from_vec(p.value, digest).unwrap()),
         };
 
         let signature = protobuf_data.get_signature();
@@ -272,11 +274,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/sss.rs.html b/docs/src/rusty_secrets/src/sss.rs.html
index 2ac2932..d6ae7ca 100644
--- a/docs/src/rusty_secrets/src/sss.rs.html
+++ b/docs/src/rusty_secrets/src/sss.rs.html
@@ -168,8 +168,12 @@
 124
 125
 126
+127
+128
 
-use custom_error::other_io_err;
+//! SSS provides Shamir's secret sharing with raw data.
+
+use custom_error::{RustyError, other_io_err};
 use digest;
 use interpolation::{encode, lagrange_interpolate};
 use merkle_sigs::sign_data_vec;
@@ -184,12 +188,12 @@
     repeat(x).take(n).collect()
 }
 
-/// Performs threshold k-out-of-n Shamir secret sharing.
+/// Performs threshold k-out-of-n Shamir's secret sharing.
 ///
 /// # Examples
 ///
 /// ```
-/// use rusty_secrets::generate_shares;
+/// use rusty_secrets::sss::generate_shares;
 /// let secret = "These programs were never about terrorism: they’re about economic spying,
 ///               social control, and diplomatic manipulation. They’re about power.".to_string();
 ///
@@ -202,10 +206,10 @@
 /// ```
 pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Result<Vec<String>> {
     if k > n {
-        return Err(other_io_err("Threshold K can not be larger than N", None));
+        return Err(other_io_err("Threshold K can not be larger than N", None, None, None));
     }
 
-    let shares = try!(secret_share(&*secret, k, n));
+    let shares = try!(secret_share(secret, k, n));
 
     let signatures = if sign_shares {
         let shares_to_sign = shares.iter()
@@ -237,7 +241,7 @@
     Ok(result)
 }
 
-pub fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result<Vec<Vec<u8>>> {
+fn secret_share(src: &[u8], k: u8, n: u8) -> Result<Vec<Vec<u8>>, RustyError> {
     let mut result = Vec::with_capacity(n as usize);
     for _ in 0..(n as usize) {
         result.push(new_vec(src.len(), 0u8));
@@ -258,14 +262,14 @@
 }
 
 
-/// Recovers the secret from a k-out-of-n Shamir secret sharing.
+/// Recovers the secret from a k-out-of-n Shamir's secret sharing.
 ///
 /// At least `k` distinct shares need to be provided to recover the share.
 ///
 /// # Examples
 ///
 /// ```
-/// use rusty_secrets::recover_secret;
+/// use rusty_secrets::sss::recover_secret;
 /// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string();
 /// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string();
 /// let shares = vec![share1, share2];
@@ -279,7 +283,7 @@
 /// 	}
 /// }
 /// ```
-pub fn recover_secret(shares: Vec<String>, verify_signatures: bool) -> io::Result<Vec<u8>> {
+pub fn recover_secret(shares: Vec<String>, verify_signatures: bool) -> Result<Vec<u8>, RustyError> {
     let (k, shares) = try!(process_and_validate_shares(shares, verify_signatures));
 
     let slen = shares[0].1.len();
@@ -352,11 +356,9 @@
     
     
     
-    
     
 
 
\ No newline at end of file
diff --git a/docs/src/rusty_secrets/src/validation.rs.html b/docs/src/rusty_secrets/src/validation.rs.html
index 8066232..d5255d7 100644
--- a/docs/src/rusty_secrets/src/validation.rs.html
+++ b/docs/src/rusty_secrets/src/validation.rs.html
@@ -42,144 +42,224 @@
         
     
 
-    
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
+    
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
 
-use custom_error::other_io_err;
+use custom_error::{RustyError, RustyErrorTypes};
 use merkle_sigs::verify_data_vec_signature;
 use share_format;
 use share_format::format_share_for_signing;
+use std::collections::HashMap;
 use std::error::Error;
-use std::io;
+
+type ProcessedShares = Result<(u8, Vec<(u8, Vec<u8>)>), RustyError>;
+
+// The order of validation that we think makes the most sense is the following:
+// 1) Validate shares individually
+// 2) Validate duplicate shares share num && data
+// 2) Validate group consistency
+// 3) Validate other properties, in no specific order
 
 pub fn process_and_validate_shares(shares_strings: Vec<String>,
                                    verify_signatures: bool)
-                                   -> io::Result<(u8, Vec<(u8, Vec<u8>)>)> {
-    let mut opt_k: Option<u8> = None;
-    let mut opt_root_hash: Option<Vec<u8>> = None;
-
+                                   -> ProcessedShares {
     let mut shares: Vec<(u8, Vec<u8>)> = Vec::new();
 
-    for (counter, line) in shares_strings.iter().enumerate() {
-        let (share_data, k, n, sig_pair) = try!(share_format::share_from_string(line,
-                                                                                verify_signatures));
+    let mut k_compatibility_sets  = HashMap::new();
+    let mut rh_compatibility_sets = HashMap::new();
 
+    for (counter, line) in shares_strings.iter().enumerate() {
+        if k_compatibility_sets.len() == 1 {
+            let k = k_compatibility_sets.keys().last().unwrap();
+            if *k == shares.len() as u8 {
+                break;
+            }
+        }
+
+        let share_index = counter as u8;
+        let (share_data, k, n, sig_pair) = try!(share_format::share_from_string(line,
+                                                                                counter as u8,
+                                                                                verify_signatures));
         if verify_signatures {
             if sig_pair.is_none() {
-                return Err(other_io_err("Signature is missing while shares are required to be \
-                                         signed.",
-                                        None));
+                return Err(RustyError::with_type(RustyErrorTypes::MissingSignature(share_index)));
             }
 
             let (signature, p) = sig_pair.unwrap();
             let root_hash = p.root_hash.clone();
 
-            if let Some(rh) = opt_root_hash.clone() {
-                if root_hash != rh {
-                    return Err(other_io_err("Root hash not matching", None));
-                }
-                p.validate(&rh);
-            } else {
-                opt_root_hash = Some(root_hash.clone());
-            }
-
             try!(verify_data_vec_signature(format_share_for_signing(k,
                                                                     n,
                                                                     &share_data.as_slice()),
                                                                     &(signature.to_vec(), p),
                                                                     &root_hash)
-				 .map_err(|e| other_io_err("Invalid signature", Some(String::from(e.description())))));
+		    .map_err(|e| RustyError::with_type(RustyErrorTypes::InvalidSignature(share_index, String::from(e.description())))));
+            rh_compatibility_sets.entry(root_hash.clone()).or_insert_with(Vec::new);
+            let vec = rh_compatibility_sets.get_mut(&root_hash).unwrap();
+            vec.push(share_index);
         }
 
-        if let Some(k_global) = opt_k {
-            if k != k_global {
-                return Err(other_io_err("Incompatible shares", None));
-            }
-        } else {
-            opt_k = Some(k);
-        }
+        k_compatibility_sets.entry(k).or_insert_with(Vec::new);
+        let vec = k_compatibility_sets.get_mut(&k).unwrap();
+        vec.push(share_index);
 
         if shares.iter().any(|s| s.0 == n) {
-            return Err(other_io_err("Duplicate Share Number", None));
+            return Err(RustyError::with_type(RustyErrorTypes::DuplicateShareNum(share_index)));
         };
 
         if shares.iter().any(|s| s.1 == share_data) {
-            return Err(other_io_err("Duplicate Share Data", None));
+            return Err(RustyError::with_type(RustyErrorTypes::DuplicateShareData(share_index)));
         };
 
         shares.push((n, share_data));
-        if counter + 1 == k as usize {
-            return Ok((k, shares));
+    }
+
+    // Validate k
+
+    let k_sets  = k_compatibility_sets.keys().count();
+    let rh_sets = rh_compatibility_sets.keys().count();
+
+    if verify_signatures {
+        match rh_sets {
+            0 => {
+                return Err(RustyError::with_type(RustyErrorTypes::EmptyShares))
+            }
+            1 => { } // All shares have the same roothash.
+            _ => {
+                return Err(RustyError::with_type(RustyErrorTypes::IncompatibleSets(rh_compatibility_sets.values()
+                                                                                   .map(|x| x.to_owned()).collect())))
+            }
         }
     }
-    Err(other_io_err("Not enough shares provided!", None))
+
+    match k_sets {
+        0 => {
+            return Err(RustyError::with_type(RustyErrorTypes::EmptyShares))
+        }
+        1 => { } // All shares have the same roothash.
+        _ => {
+            return Err(RustyError::with_type(RustyErrorTypes::IncompatibleSets(k_compatibility_sets.values()
+                                                                               .map(|x| x.to_owned()).collect())))
+        }
+    }
+
+    // It is safe to unwrap because k_sets == 1
+    let k = *k_compatibility_sets.keys().last().unwrap();
+    let shares_num = shares.len();
+
+    if shares_num >= k as usize  {
+        shares.truncate(k as usize);
+        Ok((k, shares))
+    } else {
+        Err(RustyError::with_type(RustyErrorTypes::MissingShares(k, shares_num)))
+    }
 }
 
@@ -238,11 +318,9 @@ - \ No newline at end of file diff --git a/docs/src/rusty_secrets/src/wrapped_secrets.rs.html b/docs/src/rusty_secrets/src/wrapped_secrets.rs.html new file mode 100644 index 0000000..00d833b --- /dev/null +++ b/docs/src/rusty_secrets/src/wrapped_secrets.rs.html @@ -0,0 +1,230 @@ + + + + + + + + + + wrapped_secrets.rs.html -- source + + + + + + + + + + + + + + + + + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+
+//! (Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data.
+
+use custom_error::{RustyError, RustyErrorTypes};
+use protobuf;
+use protobuf::Message;
+use secret::{RustySecret, RustySecretsVersions};
+use sss;
+use std::io;
+
+/// Performs threshold k-out-of-n Shamir's secret sharing.
+///
+/// # Examples
+///
+/// ```
+/// use rusty_secrets::wrapped_secrets::generate_shares;
+/// let secret = "These programs were never about terrorism: they’re about economic spying,
+///               social control, and diplomatic manipulation. They’re about power.".to_string();
+///
+/// match generate_shares(7, 10, &secret.into_bytes(), "text/html", true){
+/// 	Ok(shares) => {
+/// 		// Do something with the shares
+/// 	},
+/// 	Err(_) => {}// Deal with error}
+/// }
+/// ```
+pub fn generate_shares(k: u8, n: u8, secret: &[u8], mime_type: &str, sign_shares: bool) -> io::Result<Vec<String>> {
+    let mut rusty_secret = RustySecret::new();
+    rusty_secret.set_version(RustySecretsVersions::INITIAL_RELEASE);
+    rusty_secret.set_mime_type(mime_type.to_owned());
+    rusty_secret.set_secret(secret.to_owned());
+
+    sss::generate_shares(k, n, rusty_secret.write_to_bytes().unwrap().as_slice(), sign_shares)
+}
+
+/// Recovers the secret from a k-out-of-n Shamir's secret sharing.
+///
+/// At least `k` distinct shares need to be provided to recover the share.
+///
+/// # Examples
+///
+/// ```
+/// use rusty_secrets::wrapped_secrets::recover_secret;
+/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string();
+/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string();
+/// let shares = vec![share1, share2];
+///
+/// match recover_secret(shares, false) {
+/// 	Ok(secret) => {
+/// 		// Do something with the secret
+/// 	},
+/// 	Err(e) => {
+/// 		// Deal with the error
+/// 	}
+/// }
+/// ```
+pub fn recover_secret(shares: Vec<String>, verify_signatures: bool) -> Result<RustySecret, RustyError> {
+    let secret = try!(sss::recover_secret(shares, verify_signatures));
+
+    protobuf::parse_from_bytes::<RustySecret>(secret.as_slice())
+    .map_err(|_| RustyError::with_type(RustyErrorTypes::SecretDeserializationIssue))
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/protobuf/Secret.proto b/protobuf/Secret.proto new file mode 100644 index 0000000..935dca5 --- /dev/null +++ b/protobuf/Secret.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +enum RustySecretsVersions { + INITIAL_RELEASE = 0; +} + +message RustySecret { + RustySecretsVersions version = 1; + bytes secret = 2; + string mime_type = 3; +} diff --git a/src/custom_error.rs b/src/custom_error.rs index bca80a1..d108271 100644 --- a/src/custom_error.rs +++ b/src/custom_error.rs @@ -1,5 +1,4 @@ use std::convert; -use std::error; use std::error::Error; use std::fmt; use std::io; @@ -10,10 +9,11 @@ use std::num; pub struct RustyError { descr: &'static str, detail: Option, - share_num: Option, + share_index: Option, share_groups: Option>> } +#[derive(Debug)] pub enum RustyErrorTypes { DuplicateShareNum(u8), DuplicateShareData(u8), @@ -22,33 +22,38 @@ pub enum RustyErrorTypes { InvalidSignature(u8, String), MissingShares(u8, usize), MissingSignature(u8), + SecretDeserializationIssue, ShareParsingError(u8, String) } impl RustyError { /// Initializes a new error with a description and optional detail string. - fn new(descr: &'static str, detail: Option, share_num: Option, share_groups: Option>>) -> RustyError { + fn new(descr: &'static str, detail: Option, share_index: Option, share_groups: Option>>) -> RustyError { RustyError { descr: descr, detail: detail, - share_num: share_num, + share_index: share_index, share_groups: share_groups } } + /// Returns a `RustyError` with a given `RustyErrorType`. pub fn with_type(error_type: RustyErrorTypes) -> RustyError { RustyError { descr: RustyError::descr_for_type(&error_type), detail: RustyError::detail_for_type(&error_type), - share_num: RustyError::share_num_for_type(&error_type), + share_index: RustyError::share_num_for_type(&error_type), share_groups: RustyError::share_groups_for_type(error_type), } } - pub fn share_num(&self) -> Option { - self.share_num + /// Returns the index of the share that raised the error, if any. + pub fn share_index(&self) -> Option { + self.share_index } + /// Returns the group of shares that were generated during the same secret share. + /// It can be used to provide a debug message to the user telling him what shares are incompatible. pub fn share_groups(&self) -> Option>> { self.share_groups.clone() } @@ -60,6 +65,8 @@ impl RustyError { RustyErrorTypes::InvalidSignature(_, _) => "The signature of this share is not valid.", RustyErrorTypes::MissingShares(_, _) => "The number of shares provided is insufficient to recover the secret.", RustyErrorTypes::MissingSignature(_) => "Signature is missing while shares are required to be signed.", + RustyErrorTypes::SecretDeserializationIssue => "An issue was encountered deserializing the secret. + Updating to the latest version of RustySecrets might help fix this.", RustyErrorTypes::ShareParsingError(_, _) => "This share is incorrectly formatted.", RustyErrorTypes::DuplicateShareNum(_) => "This share number has already been used by a previous share.", RustyErrorTypes::DuplicateShareData(_) => "The data encoded in this share is the same as the one found in a previous share." @@ -103,11 +110,11 @@ impl fmt::Display for RustyError { } } -impl error::Error for RustyError { +impl Error for RustyError { fn description(&self) -> &str { self.descr } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&Error> { None } } diff --git a/src/lib.rs b/src/lib.rs index 5e0c066..42a2bf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,12 @@ -// #![deny( -// missing_docs, -// missing_debug_implementations, missing_copy_implementations, -// trivial_casts, trivial_numeric_casts, -// unsafe_code, unstable_features, -// unused_import_braces, unused_qualifications -// )] +//! `RustySecrets` implements Shamir's secret sharing in Rust. It provides the possibility to sign shares. -//! `RustySecrets` implements Shamir Secret Sharing in Rust. It provides the possibility to sign shares. +#![deny( + missing_docs, + missing_debug_implementations, missing_copy_implementations, + trivial_casts, trivial_numeric_casts, + unsafe_code, unstable_features, + unused_import_braces, unused_qualifications +)] extern crate protobuf; extern crate rustc_serialize as serialize; @@ -21,14 +21,17 @@ static digest: &'static Algorithm = &SHA512; mod custom_error; mod gf256; mod interpolation; +#[allow(unused_qualifications)] +mod secret; +#[allow(unused_qualifications)] mod share_data; mod share_format; -mod sss; mod validation; -pub use sss::generate_shares; -pub use sss::recover_secret; pub use custom_error::RustyError; +pub mod sss; +pub mod wrapped_secrets; + #[cfg(test)] mod tests; diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 0000000..53aa6f9 --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,391 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(Clone,Default)] +pub struct RustySecret { + // message fields + version: ::std::option::Option, + secret: ::protobuf::SingularField<::std::vec::Vec>, + mime_type: ::protobuf::SingularField<::std::string::String>, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::std::cell::Cell, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for RustySecret {} + +impl RustySecret { + pub fn new() -> RustySecret { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static RustySecret { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const RustySecret, + }; + unsafe { + instance.get(|| { + RustySecret { + version: ::std::option::Option::None, + secret: ::protobuf::SingularField::none(), + mime_type: ::protobuf::SingularField::none(), + unknown_fields: ::protobuf::UnknownFields::new(), + cached_size: ::std::cell::Cell::new(0), + } + }) + } + } + + // optional .RustySecretsVersions version = 1; + + pub fn clear_version(&mut self) { + self.version = ::std::option::Option::None; + } + + pub fn has_version(&self) -> bool { + self.version.is_some() + } + + // Param is passed by value, moved + pub fn set_version(&mut self, v: RustySecretsVersions) { + self.version = ::std::option::Option::Some(v); + } + + pub fn get_version(&self) -> RustySecretsVersions { + self.version.unwrap_or(RustySecretsVersions::INITIAL_RELEASE) + } + + // optional bytes secret = 2; + + pub fn clear_secret(&mut self) { + self.secret.clear(); + } + + pub fn has_secret(&self) -> bool { + self.secret.is_some() + } + + // Param is passed by value, moved + pub fn set_secret(&mut self, v: ::std::vec::Vec) { + self.secret = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { + if self.secret.is_none() { + self.secret.set_default(); + }; + self.secret.as_mut().unwrap() + } + + // Take field + pub fn take_secret(&mut self) -> ::std::vec::Vec { + self.secret.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + pub fn get_secret(&self) -> &[u8] { + match self.secret.as_ref() { + Some(v) => &v, + None => &[], + } + } + + // optional string mime_type = 3; + + pub fn clear_mime_type(&mut self) { + self.mime_type.clear(); + } + + pub fn has_mime_type(&self) -> bool { + self.mime_type.is_some() + } + + // Param is passed by value, moved + pub fn set_mime_type(&mut self, v: ::std::string::String) { + self.mime_type = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_mime_type(&mut self) -> &mut ::std::string::String { + if self.mime_type.is_none() { + self.mime_type.set_default(); + }; + self.mime_type.as_mut().unwrap() + } + + // Take field + pub fn take_mime_type(&mut self) -> ::std::string::String { + self.mime_type.take().unwrap_or_else(|| ::std::string::String::new()) + } + + pub fn get_mime_type(&self) -> &str { + match self.mime_type.as_ref() { + Some(v) => &v, + None => "", + } + } +} + +impl ::protobuf::Message for RustySecret { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !try!(is.eof()) { + let (field_number, wire_type) = try!(is.read_tag_unpack()); + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + }; + let tmp = try!(is.read_enum()); + self.version = ::std::option::Option::Some(tmp); + }, + 2 => { + try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.secret)); + }, + 3 => { + try!(::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.mime_type)); + }, + _ => { + try!(::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())); + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.version { + my_size += ::protobuf::rt::enum_size(1, *value); + }; + for value in &self.secret { + my_size += ::protobuf::rt::bytes_size(2, &value); + }; + for value in &self.mime_type { + my_size += ::protobuf::rt::string_size(3, &value); + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.version { + try!(os.write_enum(1, v.value())); + }; + if let Some(v) = self.secret.as_ref() { + try!(os.write_bytes(2, &v)); + }; + if let Some(v) = self.mime_type.as_ref() { + try!(os.write_string(3, &v)); + }; + try!(os.write_unknown_fields(self.get_unknown_fields())); + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn type_id(&self) -> ::std::any::TypeId { + ::std::any::TypeId::of::() + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for RustySecret { + fn new() -> RustySecret { + RustySecret::new() + } + + fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_enum_accessor( + "version", + RustySecret::has_version, + RustySecret::get_version, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( + "secret", + RustySecret::has_secret, + RustySecret::get_secret, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor( + "mime_type", + RustySecret::has_mime_type, + RustySecret::get_mime_type, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "RustySecret", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for RustySecret { + fn clear(&mut self) { + self.clear_version(); + self.clear_secret(); + self.clear_mime_type(); + self.unknown_fields.clear(); + } +} + +impl ::std::cmp::PartialEq for RustySecret { + fn eq(&self, other: &RustySecret) -> bool { + self.version == other.version && + self.secret == other.secret && + self.mime_type == other.mime_type && + self.unknown_fields == other.unknown_fields + } +} + +impl ::std::fmt::Debug for RustySecret { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum RustySecretsVersions { + INITIAL_RELEASE = 0, +} + +impl ::protobuf::ProtobufEnum for RustySecretsVersions { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(RustySecretsVersions::INITIAL_RELEASE), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [RustySecretsVersions] = &[ + RustySecretsVersions::INITIAL_RELEASE, + ]; + values + } + + fn enum_descriptor_static(_: Option) -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("RustySecretsVersions", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for RustySecretsVersions { +} + +static file_descriptor_proto_data: &'static [u8] = &[ + 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, + 0x0a, 0x0b, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x2f, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x2e, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x2a, 0x2b, 0x0a, 0x14, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x13, 0x0a, 0x0f, 0x49, + 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x00, + 0x4a, 0xbd, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x0a, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, + 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x0a, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x02, 0x00, 0x04, + 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x02, 0x05, 0x19, 0x0a, 0x0b, 0x0a, + 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x03, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x03, 0x08, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, + 0x02, 0x12, 0x03, 0x03, 0x1a, 0x1b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x06, 0x00, + 0x0a, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x06, 0x08, 0x13, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x07, 0x08, 0x29, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0x07, 0x08, 0x06, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x00, 0x06, 0x12, 0x03, 0x07, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x12, 0x03, 0x07, 0x1d, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x07, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x08, 0x08, + 0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0x08, 0x08, 0x07, 0x29, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x08, 0x08, 0x0d, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08, 0x0e, 0x14, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x17, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, + 0x02, 0x02, 0x12, 0x03, 0x09, 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x04, + 0x12, 0x04, 0x09, 0x08, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, + 0x03, 0x09, 0x08, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x09, + 0x0f, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x09, 0x1b, 0x1c, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +]; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/sss.rs b/src/sss.rs index 073de64..b6a8c5e 100644 --- a/src/sss.rs +++ b/src/sss.rs @@ -1,3 +1,5 @@ +//! SSS provides Shamir's secret sharing with raw data. + use custom_error::{RustyError, other_io_err}; use digest; use interpolation::{encode, lagrange_interpolate}; @@ -13,12 +15,12 @@ fn new_vec(n: usize, x: T) -> Vec { repeat(x).take(n).collect() } -/// Performs threshold k-out-of-n Shamir secret sharing. +/// Performs threshold k-out-of-n Shamir's secret sharing. /// /// # Examples /// /// ``` -/// use rusty_secrets::generate_shares; +/// use rusty_secrets::sss::generate_shares; /// let secret = "These programs were never about terrorism: they’re about economic spying, /// social control, and diplomatic manipulation. They’re about power.".to_string(); /// @@ -34,7 +36,7 @@ pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Re return Err(other_io_err("Threshold K can not be larger than N", None, None, None)); } - let shares = try!(secret_share(&*secret, k, n)); + let shares = try!(secret_share(secret, k, n)); let signatures = if sign_shares { let shares_to_sign = shares.iter() @@ -66,7 +68,7 @@ pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Re Ok(result) } -pub fn secret_share(src: &[u8], k: u8, n: u8) -> Result>, RustyError> { +fn secret_share(src: &[u8], k: u8, n: u8) -> Result>, RustyError> { let mut result = Vec::with_capacity(n as usize); for _ in 0..(n as usize) { result.push(new_vec(src.len(), 0u8)); @@ -87,14 +89,14 @@ pub fn secret_share(src: &[u8], k: u8, n: u8) -> Result>, RustyError } -/// Recovers the secret from a k-out-of-n Shamir secret sharing. +/// Recovers the secret from a k-out-of-n Shamir's secret sharing. /// /// At least `k` distinct shares need to be provided to recover the share. /// /// # Examples /// /// ``` -/// use rusty_secrets::recover_secret; +/// use rusty_secrets::sss::recover_secret; /// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); /// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); /// let shares = vec![share1, share2]; diff --git a/src/wrapped_secrets.rs b/src/wrapped_secrets.rs new file mode 100644 index 0000000..9defa78 --- /dev/null +++ b/src/wrapped_secrets.rs @@ -0,0 +1,61 @@ +//! (Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data. + +use custom_error::{RustyError, RustyErrorTypes}; +use protobuf; +use protobuf::Message; +use secret::{RustySecret, RustySecretsVersions}; +use sss; +use std::io; + +/// Performs threshold k-out-of-n Shamir's secret sharing. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::wrapped_secrets::generate_shares; +/// let secret = "These programs were never about terrorism: they’re about economic spying, +/// social control, and diplomatic manipulation. They’re about power.".to_string(); +/// +/// match generate_shares(7, 10, &secret.into_bytes(), "text/html", true){ +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => {}// Deal with error} +/// } +/// ``` +pub fn generate_shares(k: u8, n: u8, secret: &[u8], mime_type: &str, sign_shares: bool) -> io::Result> { + let mut rusty_secret = RustySecret::new(); + rusty_secret.set_version(RustySecretsVersions::INITIAL_RELEASE); + rusty_secret.set_mime_type(mime_type.to_owned()); + rusty_secret.set_secret(secret.to_owned()); + + sss::generate_shares(k, n, rusty_secret.write_to_bytes().unwrap().as_slice(), sign_shares) +} + +/// Recovers the secret from a k-out-of-n Shamir's secret sharing. +/// +/// At least `k` distinct shares need to be provided to recover the share. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::wrapped_secrets::recover_secret; +/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); +/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); +/// let shares = vec![share1, share2]; +/// +/// match recover_secret(shares, false) { +/// Ok(secret) => { +/// // Do something with the secret +/// }, +/// Err(e) => { +/// // Deal with the error +/// } +/// } +/// ``` +pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result { + let secret = try!(sss::recover_secret(shares, verify_signatures)); + + protobuf::parse_from_bytes::(secret.as_slice()) + .map_err(|_| RustyError::with_type(RustyErrorTypes::SecretDeserializationIssue)) +} diff --git a/tests/generation_errors.rs b/tests/generation_errors.rs index 9cc519a..2d4f156 100644 --- a/tests/generation_errors.rs +++ b/tests/generation_errors.rs @@ -1,6 +1,6 @@ extern crate rusty_secrets; -use rusty_secrets::generate_shares; +use rusty_secrets::sss::generate_shares; #[test] #[should_panic(expected = "Threshold K can not be larger than N")] diff --git a/tests/randomized_tests.rs b/tests/randomized_tests.rs index 08d3a74..94cd3a1 100644 --- a/tests/randomized_tests.rs +++ b/tests/randomized_tests.rs @@ -1,6 +1,6 @@ extern crate rusty_secrets; -use rusty_secrets::{generate_shares, recover_secret}; +use rusty_secrets::*; #[ignore] #[test] @@ -13,12 +13,18 @@ fn test_reasonable_splits() { across public lines." .to_string() .into_bytes(); + + let mime_type = "image/jpeg"; + for is_signing in &[true, false] { for k in 1..max_shares { for n in k..max_shares { - let shares = generate_shares(k, n, &secret, *is_signing).unwrap(); + let shares = wrapped_secrets::generate_shares(k, n, &secret, mime_type,*is_signing).unwrap(); println!("Testing {} out-of- {}", k, n); - assert_eq!(secret, recover_secret(shares, *is_signing).unwrap()); + + let s = wrapped_secrets::recover_secret(shares, *is_signing).unwrap(); + assert_eq!(s.get_secret().to_owned(), secret); + assert_eq!(mime_type, s.get_mime_type()); } } } diff --git a/tests/recovery_errors.rs b/tests/recovery_errors.rs index 98abfb9..a836083 100644 --- a/tests/recovery_errors.rs +++ b/tests/recovery_errors.rs @@ -1,6 +1,6 @@ extern crate rusty_secrets; -use rusty_secrets::recover_secret; +use rusty_secrets::sss::recover_secret; #[test] #[should_panic(expected = "No shares were provided.")]