mirror of
https://github.com/mii443/RustySecrets.git
synced 2025-08-22 16:25:32 +00:00
Adding share_num field to errors.
This commit is contained in:
48
Cargo.lock
generated
48
Cargo.lock
generated
@ -2,20 +2,20 @@
|
|||||||
name = "rusty_secrets"
|
name = "rusty_secrets"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"merkle_sigs 0.1.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)",
|
"merkle_sigs 1.0.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)",
|
||||||
"protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)",
|
"ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lamport_sigs"
|
name = "lamport_sigs"
|
||||||
version = "0.1.1"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/SpinResearch/lamport.rs#4ddf030e1514383d13dc86b75c4c239a4935dc48"
|
source = "git+https://github.com/SpinResearch/lamport.rs#9f9fdb749fc62b20404aa4430369e473212c6147"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)",
|
"ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -25,26 +25,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.17"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "merkle"
|
name = "merkle"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/SpinResearch/merkle.rs#450325872473884e73790ebd6cf50fa9ce0b8aa8"
|
source = "git+https://github.com/SpinResearch/merkle.rs#249234cacaf2891ee4371846b6a32bfae0743ab9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)",
|
"ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "merkle_sigs"
|
name = "merkle_sigs"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/SpinResearch/merkle_sigs.rs#ae2e85ab6d694eaed4c5488964af64ffce7bd0f7"
|
source = "git+https://github.com/SpinResearch/merkle_sigs.rs#c9125872e759405e55cdf0609f5c32fece181793"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lamport_sigs 0.1.1 (git+https://github.com/SpinResearch/lamport.rs)",
|
"lamport_sigs 1.0.0 (git+https://github.com/SpinResearch/lamport.rs)",
|
||||||
"merkle 0.1.0 (git+https://github.com/SpinResearch/merkle.rs)",
|
"merkle 1.0.0 (git+https://github.com/SpinResearch/merkle.rs)",
|
||||||
"ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)",
|
"ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -57,12 +57,12 @@ name = "rand"
|
|||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.6.0-alpha"
|
version = "0.6.0-alpha1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -71,7 +71,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.21"
|
version = "0.3.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -80,13 +80,13 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum lamport_sigs 0.1.1 (git+https://github.com/SpinResearch/lamport.rs)" = "<none>"
|
"checksum lamport_sigs 1.0.0 (git+https://github.com/SpinResearch/lamport.rs)" = "<none>"
|
||||||
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
||||||
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
|
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
|
||||||
"checksum merkle 0.1.0 (git+https://github.com/SpinResearch/merkle.rs)" = "<none>"
|
"checksum merkle 1.0.0 (git+https://github.com/SpinResearch/merkle.rs)" = "<none>"
|
||||||
"checksum merkle_sigs 0.1.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)" = "<none>"
|
"checksum merkle_sigs 1.0.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)" = "<none>"
|
||||||
"checksum protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec4c2fe04370298218a09ab53a534febf54c160c5554e4de987b6d73c916d5d"
|
"checksum protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec4c2fe04370298218a09ab53a534febf54c160c5554e4de987b6d73c916d5d"
|
||||||
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
||||||
"checksum ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)" = "756e9bcca47cd772b23f9958ea0952a18a5a3e294e4ab3b7d019e6c06955f191"
|
"checksum ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c9d14fdd6779c80311183b64598d57e640993fd1732119ce2cedb3234217532"
|
||||||
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
|
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
|
||||||
"checksum untrusted 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193df64312e3515fd983ded55ad5bcaa7647a035804828ed757e832ce6029ef3"
|
"checksum untrusted 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193df64312e3515fd983ded55ad5bcaa7647a035804828ed757e832ce6029ef3"
|
||||||
|
@ -1,27 +1,100 @@
|
|||||||
use std::convert;
|
use std::convert;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
/// Error struct used for generating an `io::Error` from a generic description.
|
/// Error struct used for generating an `io::Error` from a generic description.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct RustyError {
|
||||||
descr: &'static str,
|
descr: &'static str,
|
||||||
detail: Option<String>,
|
detail: Option<String>,
|
||||||
|
share_num: Option<u8>,
|
||||||
|
share_groups: Option<Vec<Vec<u8>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
pub enum RustyErrorTypes {
|
||||||
|
DuplicateShareNum(u8),
|
||||||
|
DuplicateShareData(u8),
|
||||||
|
EmptyShares,
|
||||||
|
IncompatibleSets(Vec<Vec<u8>>),
|
||||||
|
InvalidSignature(u8, String),
|
||||||
|
MissingShares(u8, usize),
|
||||||
|
MissingSignature(u8),
|
||||||
|
ShareParsingError(u8, String)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RustyError {
|
||||||
/// Initializes a new error with a description and optional detail string.
|
/// Initializes a new error with a description and optional detail string.
|
||||||
pub fn new(descr: &'static str, detail: Option<String>) -> Error {
|
fn new(descr: &'static str, detail: Option<String>, share_num: Option<u8>, share_groups: Option<Vec<Vec<u8>>>) -> RustyError {
|
||||||
Error {
|
RustyError {
|
||||||
descr: descr,
|
descr: descr,
|
||||||
detail: detail,
|
detail: detail,
|
||||||
|
share_num: share_num,
|
||||||
|
share_groups: share_groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_groups: RustyError::share_groups_for_type(error_type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn share_num(&self) -> Option<u8> {
|
||||||
|
self.share_num
|
||||||
|
}
|
||||||
|
|
||||||
|
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::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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.detail {
|
match self.detail {
|
||||||
None => write!(f, "{}", self.descr),
|
None => write!(f, "{}", self.descr),
|
||||||
@ -30,7 +103,7 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {
|
impl error::Error for RustyError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
self.descr
|
self.descr
|
||||||
}
|
}
|
||||||
@ -39,33 +112,42 @@ impl error::Error for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for io::Error {
|
impl From<io::Error> for RustyError {
|
||||||
fn from(me: Error) -> io::Error {
|
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)
|
io::Error::new(io::ErrorKind::Other, me)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an `io::Error` from description string and optional detail string.
|
/// Returns an `io::Error` from description string and optional detail string.
|
||||||
/// Particularly useful in `Result` expressions.
|
/// Particularly useful in `Result` expressions.
|
||||||
pub fn other_io_err(descr: &'static str, detail: Option<String>) -> io::Error {
|
pub fn other_io_err(descr: &'static str, detail: Option<String>,
|
||||||
convert::From::from(Error::new(descr, detail))
|
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`
|
/// maps a `ParseIntError` to an `Error`
|
||||||
pub fn pie2io(p: num::ParseIntError) -> io::Error {
|
pub fn pie2error(p: num::ParseIntError) -> RustyError {
|
||||||
convert::From::from(Error::new("Integer parsing error", Some(p.to_string())))
|
RustyError::new("Integer parsing error", Some(p.to_string()), None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests_custom_err {
|
mod tests_custom_err {
|
||||||
use std::error;
|
use std::error;
|
||||||
use custom_error;
|
use custom_error::RustyError;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_custom_error() {
|
fn test_custom_error() {
|
||||||
let desc = "Boring error description";
|
let desc = "Boring error description";
|
||||||
let detail = "More of it";
|
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);
|
assert_eq!(error::Error::description(&ewd), desc);
|
||||||
match error::Error::cause(&ewd) {
|
match error::Error::cause(&ewd) {
|
||||||
@ -73,7 +155,7 @@ mod tests_custom_err {
|
|||||||
None => assert!(true),
|
None => assert!(true),
|
||||||
}
|
}
|
||||||
let _formated_err = format!("{}", ewd);
|
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);
|
let _formated_err = format!("{}", ewod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,12 +163,12 @@ mod tests_custom_err {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests_std_err {
|
mod tests_std_err {
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use custom_error::pie2io;
|
use custom_error::pie2error;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_errors() {
|
fn test_parse_errors() {
|
||||||
let nan = "2a".to_string();
|
let nan = "2a".to_string();
|
||||||
match nan.parse::<u8>().map_err(pie2io) {
|
match nan.parse::<u8>().map_err(pie2error) {
|
||||||
Ok(_) => assert!(false),
|
Ok(_) => assert!(false),
|
||||||
Err(x) => assert_eq!("Integer parsing error", x.description()),
|
Err(x) => assert_eq!("Integer parsing error", x.description()),
|
||||||
}
|
}
|
||||||
|
15
src/lib.rs
15
src/lib.rs
@ -1,10 +1,10 @@
|
|||||||
#![deny(
|
// #![deny(
|
||||||
missing_docs,
|
// missing_docs,
|
||||||
missing_debug_implementations, missing_copy_implementations,
|
// missing_debug_implementations, missing_copy_implementations,
|
||||||
trivial_casts, trivial_numeric_casts,
|
// trivial_casts, trivial_numeric_casts,
|
||||||
unsafe_code, unstable_features,
|
// unsafe_code, unstable_features,
|
||||||
unused_import_braces, unused_qualifications
|
// unused_import_braces, unused_qualifications
|
||||||
)]
|
// )]
|
||||||
|
|
||||||
//! `RustySecrets` implements Shamir 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.
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ mod validation;
|
|||||||
|
|
||||||
pub use sss::generate_shares;
|
pub use sss::generate_shares;
|
||||||
pub use sss::recover_secret;
|
pub use sss::recover_secret;
|
||||||
|
pub use custom_error::RustyError;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
use custom_error::{other_io_err, pie2io};
|
use custom_error::{RustyError, RustyErrorTypes};
|
||||||
|
use custom_error::pie2error;
|
||||||
use digest;
|
use digest;
|
||||||
use merkle_sigs::Proof;
|
use merkle_sigs::{MerklePublicKey, Proof, PublicKey};
|
||||||
use merkle_sigs::PublicKey;
|
|
||||||
use protobuf;
|
use protobuf;
|
||||||
use protobuf::{Message, RepeatedField};
|
use protobuf::{Message, RepeatedField};
|
||||||
use serialize;
|
use serialize;
|
||||||
use serialize::base64::{self, FromBase64, ToBase64};
|
use serialize::base64::{self, FromBase64, ToBase64};
|
||||||
use share_data::ShareData;
|
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 {
|
fn base64_config() -> serialize::base64::Config {
|
||||||
base64::Config { pad: false, ..base64::STANDARD }
|
base64::Config { pad: false, ..base64::STANDARD }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn share_string_from(share: Vec<u8>,
|
pub fn share_string_from(share: Vec<u8>, threshold: u8, share_num: u8,
|
||||||
threshold: u8,
|
signature_pair: Option<(Vec<Vec<u8>>, Proof<MerklePublicKey>)>)
|
||||||
share_num: u8,
|
|
||||||
signature_pair: Option<(Vec<Vec<u8>>, Proof<PublicKey>)>)
|
|
||||||
-> String {
|
-> String {
|
||||||
let mut share_protobuf = ShareData::new();
|
let mut share_protobuf = ShareData::new();
|
||||||
share_protobuf.set_shamir_data(share);
|
share_protobuf.set_shamir_data(share);
|
||||||
@ -33,44 +33,45 @@ pub fn share_string_from(share: Vec<u8>,
|
|||||||
|
|
||||||
pub fn share_from_string
|
pub fn share_from_string
|
||||||
(s: &str,
|
(s: &str,
|
||||||
|
index: u8,
|
||||||
is_signed: bool)
|
is_signed: bool)
|
||||||
-> io::Result<(Vec<u8>, u8, u8, Option<(Vec<Vec<u8>>, Proof<PublicKey>)>)> {
|
-> ParsedShare {
|
||||||
let parts: Vec<_> = s.trim().split('-').collect();
|
let parts: Vec<_> = s.trim().split('-').collect();
|
||||||
|
|
||||||
if parts.len() != 3 {
|
if parts.len() != 3 {
|
||||||
return Err(other_io_err("Share parse error: Expected 3 parts separated by a minus sign",
|
return Err(RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Expected 3 parts separated by a minus sign. Found {}.", s))));
|
||||||
None));
|
|
||||||
}
|
}
|
||||||
let (k, n, p3) = {
|
let (k, n, p3) = {
|
||||||
let mut iter = parts.into_iter();
|
let mut iter = parts.into_iter();
|
||||||
let k = 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(pie2io));
|
let n = try!(iter.next().unwrap().parse::<u8>().map_err(pie2error));
|
||||||
let p3 = iter.next().unwrap();
|
let p3 = iter.next().unwrap();
|
||||||
(k, n, p3)
|
(k, n, p3)
|
||||||
};
|
};
|
||||||
if k < 1 || n < 1 {
|
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(|_| {
|
let raw_data = try!(p3.from_base64().map_err(|_| {
|
||||||
other_io_err("Share parse error: Base64 decoding of data block failed",
|
RustyError::with_type(RustyErrorTypes::ShareParsingError(index, "Base64 decoding of data block failed".to_owned()))
|
||||||
None)
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let protobuf_data = try!(protobuf::parse_from_bytes::<ShareData>(raw_data.as_slice())
|
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());
|
let share = Vec::from(protobuf_data.get_shamir_data());
|
||||||
|
|
||||||
if is_signed {
|
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 {
|
let proof = Proof {
|
||||||
algorithm: digest,
|
algorithm: digest,
|
||||||
lemma: p.lemma,
|
lemma: p.lemma,
|
||||||
root_hash: p.root_hash,
|
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();
|
let signature = protobuf_data.get_signature();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use custom_error::other_io_err;
|
use custom_error::{RustyError, other_io_err};
|
||||||
use digest;
|
use digest;
|
||||||
use interpolation::{encode, lagrange_interpolate};
|
use interpolation::{encode, lagrange_interpolate};
|
||||||
use merkle_sigs::sign_data_vec;
|
use merkle_sigs::sign_data_vec;
|
||||||
@ -31,7 +31,7 @@ fn new_vec<T: Clone>(n: usize, x: T) -> Vec<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Result<Vec<String>> {
|
pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Result<Vec<String>> {
|
||||||
if k > n {
|
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));
|
||||||
@ -66,7 +66,7 @@ pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Re
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result<Vec<Vec<u8>>> {
|
pub fn secret_share(src: &[u8], k: u8, n: u8) -> Result<Vec<Vec<u8>>, RustyError> {
|
||||||
let mut result = Vec::with_capacity(n as usize);
|
let mut result = Vec::with_capacity(n as usize);
|
||||||
for _ in 0..(n as usize) {
|
for _ in 0..(n as usize) {
|
||||||
result.push(new_vec(src.len(), 0u8));
|
result.push(new_vec(src.len(), 0u8));
|
||||||
@ -108,7 +108,7 @@ pub fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result<Vec<Vec<u8>>> {
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
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 (k, shares) = try!(process_and_validate_shares(shares, verify_signatures));
|
||||||
|
|
||||||
let slen = shares[0].1.len();
|
let slen = shares[0].1.len();
|
||||||
|
@ -1,69 +1,109 @@
|
|||||||
use custom_error::other_io_err;
|
use custom_error::{RustyError, RustyErrorTypes};
|
||||||
use merkle_sigs::verify_data_vec_signature;
|
use merkle_sigs::verify_data_vec_signature;
|
||||||
use share_format;
|
use share_format;
|
||||||
use share_format::format_share_for_signing;
|
use share_format::format_share_for_signing;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
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>,
|
pub fn process_and_validate_shares(shares_strings: Vec<String>,
|
||||||
verify_signatures: bool)
|
verify_signatures: bool)
|
||||||
-> io::Result<(u8, Vec<(u8, Vec<u8>)>)> {
|
-> ProcessedShares {
|
||||||
let mut opt_k: Option<u8> = None;
|
|
||||||
let mut opt_root_hash: Option<Vec<u8>> = None;
|
|
||||||
|
|
||||||
let mut shares: Vec<(u8, Vec<u8>)> = Vec::new();
|
let mut shares: Vec<(u8, Vec<u8>)> = Vec::new();
|
||||||
|
|
||||||
for (counter, line) in shares_strings.iter().enumerate() {
|
let mut k_compatibility_sets = HashMap::new();
|
||||||
let (share_data, k, n, sig_pair) = try!(share_format::share_from_string(line,
|
let mut rh_compatibility_sets = HashMap::new();
|
||||||
verify_signatures));
|
|
||||||
|
|
||||||
|
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 verify_signatures {
|
||||||
if sig_pair.is_none() {
|
if sig_pair.is_none() {
|
||||||
return Err(other_io_err("Signature is missing while shares are required to be \
|
return Err(RustyError::with_type(RustyErrorTypes::MissingSignature(share_index)));
|
||||||
signed.",
|
|
||||||
None));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (signature, p) = sig_pair.unwrap();
|
let (signature, p) = sig_pair.unwrap();
|
||||||
let root_hash = p.root_hash.clone();
|
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,
|
try!(verify_data_vec_signature(format_share_for_signing(k,
|
||||||
n,
|
n,
|
||||||
&share_data.as_slice()),
|
&share_data.as_slice()),
|
||||||
&(signature.to_vec(), p),
|
&(signature.to_vec(), p),
|
||||||
&root_hash)
|
&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 {
|
k_compatibility_sets.entry(k).or_insert_with(Vec::new);
|
||||||
if k != k_global {
|
let vec = k_compatibility_sets.get_mut(&k).unwrap();
|
||||||
return Err(other_io_err("Incompatible shares", None));
|
vec.push(share_index);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opt_k = Some(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
if shares.iter().any(|s| s.0 == n) {
|
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) {
|
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));
|
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)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,12 @@ fn test_reasonable_splits() {
|
|||||||
across public lines."
|
across public lines."
|
||||||
.to_string()
|
.to_string()
|
||||||
.into_bytes();
|
.into_bytes();
|
||||||
for is_signing in vec![true, false] {
|
for is_signing in &[true, false] {
|
||||||
for k in 2..max_shares {
|
for k in 1..max_shares {
|
||||||
for n in k..max_shares {
|
for n in k..max_shares {
|
||||||
let shares = generate_shares(k, n, &secret, is_signing).unwrap();
|
let shares = generate_shares(k, n, &secret, *is_signing).unwrap();
|
||||||
println!("Testing {} out-of- {}", k, n);
|
println!("Testing {} out-of- {}", k, n);
|
||||||
assert_eq!(secret, recover_secret(shares, is_signing).unwrap());
|
assert_eq!(secret, recover_secret(shares, *is_signing).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,21 @@ extern crate rusty_secrets;
|
|||||||
use rusty_secrets::recover_secret;
|
use rusty_secrets::recover_secret;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Not enough shares provided!")]
|
#[should_panic(expected = "No shares were provided.")]
|
||||||
fn test_recover_sellibitze_no_shares() {
|
fn test_recover_no_shares() {
|
||||||
let shares = vec![];
|
let shares = vec![];
|
||||||
recover_secret(shares, false).unwrap();
|
recover_secret(shares, false).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Share parse error: Expected 3 parts separated by a minus sign")]
|
#[should_panic(expected = "No shares were provided.")]
|
||||||
|
fn test_recover_no_shares_signed() {
|
||||||
|
let shares = vec![];
|
||||||
|
recover_secret(shares, true).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "This share is incorrectly formatted.")]
|
||||||
fn test_recover_2_parts_share() {
|
fn test_recover_2_parts_share() {
|
||||||
let share1 = "2-1-CgmKQZHMO+5n5pU".to_string();
|
let share1 = "2-1-CgmKQZHMO+5n5pU".to_string();
|
||||||
let share2 = "2-2".to_string();
|
let share2 = "2-2".to_string();
|
||||||
@ -32,7 +39,7 @@ fn test_recover_incorrect_share_num() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Share parse error: Illegal K,N parameters")]
|
#[should_panic(expected = "This share is incorrectly formatted.")]
|
||||||
fn test_recover_0_share_num() {
|
fn test_recover_0_share_num() {
|
||||||
let share1 = "2-0-1YAYwmOHqZ69jA".to_string();
|
let share1 = "2-0-1YAYwmOHqZ69jA".to_string();
|
||||||
let share2 = "2-1-YJZQDGm22Y77Gw".to_string();
|
let share2 = "2-1-YJZQDGm22Y77Gw".to_string();
|
||||||
@ -43,7 +50,7 @@ fn test_recover_0_share_num() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Share parse error: Base64 decoding of data block failed")]
|
#[should_panic(expected = "This share is incorrectly formatted.")]
|
||||||
fn test_recover_invalid_b64() {
|
fn test_recover_invalid_b64() {
|
||||||
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
||||||
let share2 = "2-1-YJZQDG((((m22Y)))77Gw".to_string();
|
let share2 = "2-1-YJZQDG((((m22Y)))77Gw".to_string();
|
||||||
@ -54,7 +61,7 @@ fn test_recover_invalid_b64() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Duplicate Share Number")]
|
#[should_panic(expected = "This share number has already been used by a previous share.")]
|
||||||
fn test_recover_duplicate_shares_number() {
|
fn test_recover_duplicate_shares_number() {
|
||||||
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
||||||
let share2 = "2-1-CgkAnUgP3lfwjyM".to_string();
|
let share2 = "2-1-CgkAnUgP3lfwjyM".to_string();
|
||||||
@ -65,7 +72,7 @@ fn test_recover_duplicate_shares_number() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Duplicate Share Data")]
|
#[should_panic(expected = "The data encoded in this share is the same as the one found in a previous share.")]
|
||||||
fn test_recover_duplicate_shares_data() {
|
fn test_recover_duplicate_shares_data() {
|
||||||
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
|
||||||
let share2 = "2-2-CgnlCxRNtnkzENE".to_string();
|
let share2 = "2-2-CgnlCxRNtnkzENE".to_string();
|
||||||
@ -76,7 +83,7 @@ fn test_recover_duplicate_shares_data() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Not enough shares provided!")]
|
#[should_panic(expected = "The number of shares provided is insufficient to recover the secret.")]
|
||||||
fn test_recover_too_few_shares() {
|
fn test_recover_too_few_shares() {
|
||||||
let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string();
|
let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string();
|
||||||
let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();
|
let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();
|
||||||
|
Reference in New Issue
Block a user