diff --git a/Cargo.lock b/Cargo.lock index ff555ea..ea5658f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,20 +2,20 @@ name = "rusty_secrets" version = "0.0.3" 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)", "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)", - "rustc-serialize 0.3.21 (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.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lamport_sigs" -version = "0.1.1" -source = "git+https://github.com/SpinResearch/lamport.rs#4ddf030e1514383d13dc86b75c4c239a4935dc48" +version = "1.0.0" +source = "git+https://github.com/SpinResearch/lamport.rs#9f9fdb749fc62b20404aa4430369e473212c6147" dependencies = [ "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]] @@ -25,26 +25,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "merkle" -version = "0.1.0" -source = "git+https://github.com/SpinResearch/merkle.rs#450325872473884e73790ebd6cf50fa9ce0b8aa8" +version = "1.0.0" +source = "git+https://github.com/SpinResearch/merkle.rs#249234cacaf2891ee4371846b6a32bfae0743ab9" dependencies = [ "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]] name = "merkle_sigs" -version = "0.1.0" -source = "git+https://github.com/SpinResearch/merkle_sigs.rs#ae2e85ab6d694eaed4c5488964af64ffce7bd0f7" +version = "1.0.0" +source = "git+https://github.com/SpinResearch/merkle_sigs.rs#c9125872e759405e55cdf0609f5c32fece181793" dependencies = [ - "lamport_sigs 0.1.1 (git+https://github.com/SpinResearch/lamport.rs)", - "merkle 0.1.0 (git+https://github.com/SpinResearch/merkle.rs)", - "ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)", + "lamport_sigs 1.0.0 (git+https://github.com/SpinResearch/lamport.rs)", + "merkle 1.0.0 (git+https://github.com/SpinResearch/merkle.rs)", + "ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -57,12 +57,12 @@ name = "rand" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "ring" -version = "0.6.0-alpha" +version = "0.6.0-alpha1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -71,7 +71,7 @@ dependencies = [ [[package]] name = "rustc-serialize" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -80,13 +80,13 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum lamport_sigs 0.1.1 (git+https://github.com/SpinResearch/lamport.rs)" = "" +"checksum lamport_sigs 1.0.0 (git+https://github.com/SpinResearch/lamport.rs)" = "" "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 merkle 0.1.0 (git+https://github.com/SpinResearch/merkle.rs)" = "" -"checksum merkle_sigs 0.1.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)" = "" +"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70" +"checksum merkle 1.0.0 (git+https://github.com/SpinResearch/merkle.rs)" = "" +"checksum merkle_sigs 1.0.0 (git+https://github.com/SpinResearch/merkle_sigs.rs)" = "" "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 ring 0.6.0-alpha (registry+https://github.com/rust-lang/crates.io-index)" = "756e9bcca47cd772b23f9958ea0952a18a5a3e294e4ab3b7d019e6c06955f191" -"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818" +"checksum ring 0.6.0-alpha1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c9d14fdd6779c80311183b64598d57e640993fd1732119ce2cedb3234217532" +"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" diff --git a/src/custom_error.rs b/src/custom_error.rs index 9151d68..bca80a1 100644 --- a/src/custom_error.rs +++ b/src/custom_error.rs @@ -1,27 +1,100 @@ 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, + share_num: Option, + share_groups: Option>> } -impl Error { +pub enum RustyErrorTypes { + DuplicateShareNum(u8), + DuplicateShareData(u8), + EmptyShares, + IncompatibleSets(Vec>), + InvalidSignature(u8, String), + MissingShares(u8, usize), + MissingSignature(u8), + ShareParsingError(u8, String) +} + +impl RustyError { /// Initializes a new error with a description and optional detail string. - pub fn new(descr: &'static str, detail: Option) -> Error { - Error { + fn new(descr: &'static str, detail: Option, share_num: Option, share_groups: Option>>) -> RustyError { + RustyError { descr: descr, 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 { + self.share_num + } + + pub fn share_groups(&self) -> Option>> { + 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 { + 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>>{ + match error_type { + RustyErrorTypes::IncompatibleSets(groups) => Some(groups), + _ => None + } + } + + fn share_num_for_type(error_type: &RustyErrorTypes) -> Option { + 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), @@ -30,7 +103,7 @@ impl fmt::Display for Error { } } -impl error::Error for Error { +impl error::Error for RustyError { fn description(&self) -> &str { self.descr } @@ -39,33 +112,42 @@ impl error::Error for Error { } } -impl From for io::Error { - fn from(me: Error) -> io::Error { +impl From 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 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) -> io::Error { - convert::From::from(Error::new(descr, detail)) +pub fn other_io_err(descr: &'static str, detail: Option, + share_num: Option, share_groups: Option>>) -> 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) { @@ -73,7 +155,7 @@ mod tests_custom_err { 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); } } @@ -81,12 +163,12 @@ mod tests_custom_err { #[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::().map_err(pie2io) { + match nan.parse::().map_err(pie2error) { Ok(_) => assert!(false), Err(x) => assert_eq!("Integer parsing error", x.description()), } diff --git a/src/lib.rs b/src/lib.rs index 237b7ad..5e0c066 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ -#![deny( - missing_docs, - missing_debug_implementations, missing_copy_implementations, - trivial_casts, trivial_numeric_casts, - unsafe_code, unstable_features, - unused_import_braces, unused_qualifications -)] +// #![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 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::recover_secret; +pub use custom_error::RustyError; #[cfg(test)] mod tests; diff --git a/src/share_format.rs b/src/share_format.rs index e634a26..e070f8b 100644 --- a/src/share_format.rs +++ b/src/share_format.rs @@ -1,22 +1,22 @@ -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, Option<(Vec>, Proof)>), RustyError>; fn base64_config() -> serialize::base64::Config { base64::Config { pad: false, ..base64::STANDARD } } -pub fn share_string_from(share: Vec, - threshold: u8, - share_num: u8, - signature_pair: Option<(Vec>, Proof)>) +pub fn share_string_from(share: Vec, threshold: u8, share_num: u8, + signature_pair: Option<(Vec>, Proof)>) -> String { let mut share_protobuf = ShareData::new(); share_protobuf.set_shamir_data(share); @@ -33,44 +33,45 @@ pub fn share_string_from(share: Vec, pub fn share_from_string (s: &str, + index: u8, is_signed: bool) - -> io::Result<(Vec, u8, u8, Option<(Vec>, Proof)>)> { + -> 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::().map_err(pie2io)); - let n = try!(iter.next().unwrap().parse::().map_err(pie2io)); + let k = try!(iter.next().unwrap().parse::().map_err(pie2error)); + let n = try!(iter.next().unwrap().parse::().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::(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(); diff --git a/src/sss.rs b/src/sss.rs index ceabe06..073de64 100644 --- a/src/sss.rs +++ b/src/sss.rs @@ -1,4 +1,4 @@ -use custom_error::other_io_err; +use custom_error::{RustyError, other_io_err}; use digest; use interpolation::{encode, lagrange_interpolate}; use merkle_sigs::sign_data_vec; @@ -31,7 +31,7 @@ fn new_vec(n: usize, x: T) -> Vec { /// ``` pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Result> { 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)); @@ -66,7 +66,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) -> io::Result>> { +pub 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)); @@ -108,7 +108,7 @@ pub fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result>> { /// } /// } /// ``` -pub fn recover_secret(shares: Vec, verify_signatures: bool) -> io::Result> { +pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result, RustyError> { let (k, shares) = try!(process_and_validate_shares(shares, verify_signatures)); let slen = shares[0].1.len(); diff --git a/src/validation.rs b/src/validation.rs index 5191e15..065d6e2 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -1,69 +1,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)>), 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, verify_signatures: bool) - -> io::Result<(u8, Vec<(u8, Vec)>)> { - let mut opt_k: Option = None; - let mut opt_root_hash: Option> = None; - + -> ProcessedShares { let mut shares: Vec<(u8, Vec)> = 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))) + } } diff --git a/tests/randomized_tests.rs b/tests/randomized_tests.rs index d52088e..08d3a74 100644 --- a/tests/randomized_tests.rs +++ b/tests/randomized_tests.rs @@ -13,12 +13,12 @@ fn test_reasonable_splits() { across public lines." .to_string() .into_bytes(); - for is_signing in vec![true, false] { - for k in 2..max_shares { + 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 = generate_shares(k, n, &secret, *is_signing).unwrap(); println!("Testing {} out-of- {}", k, n); - assert_eq!(secret, recover_secret(shares, is_signing).unwrap()); + assert_eq!(secret, recover_secret(shares, *is_signing).unwrap()); } } } diff --git a/tests/recovery_errors.rs b/tests/recovery_errors.rs index 45d4d47..98abfb9 100644 --- a/tests/recovery_errors.rs +++ b/tests/recovery_errors.rs @@ -3,14 +3,21 @@ extern crate rusty_secrets; use rusty_secrets::recover_secret; #[test] -#[should_panic(expected = "Not enough shares provided!")] -fn test_recover_sellibitze_no_shares() { +#[should_panic(expected = "No shares were provided.")] +fn test_recover_no_shares() { let shares = vec![]; recover_secret(shares, false).unwrap(); } #[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() { let share1 = "2-1-CgmKQZHMO+5n5pU".to_string(); let share2 = "2-2".to_string(); @@ -32,7 +39,7 @@ fn test_recover_incorrect_share_num() { } #[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() { let share1 = "2-0-1YAYwmOHqZ69jA".to_string(); let share2 = "2-1-YJZQDGm22Y77Gw".to_string(); @@ -43,7 +50,7 @@ fn test_recover_0_share_num() { } #[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() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-1-YJZQDG((((m22Y)))77Gw".to_string(); @@ -54,7 +61,7 @@ fn test_recover_invalid_b64() { } #[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() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-1-CgkAnUgP3lfwjyM".to_string(); @@ -65,7 +72,7 @@ fn test_recover_duplicate_shares_number() { } #[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() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-2-CgnlCxRNtnkzENE".to_string(); @@ -76,7 +83,7 @@ fn test_recover_duplicate_shares_data() { } #[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() { let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string(); let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();