Validate shares have the same data length

This commit is contained in:
Noah Vesely
2018-03-27 15:22:21 -06:00
committed by Romain Ruetschi
parent df091b07c1
commit a6046dde48
3 changed files with 43 additions and 4 deletions

View File

@ -64,6 +64,11 @@ error_chain! {
display("The shares are incompatible with each other because they do not all have the same threshold.") display("The shares are incompatible with each other because they do not all have the same threshold.")
} }
IncompatibleDataLengths(sets: Vec<HashSet<u8>>) {
description("The shares are incompatible with each other because they do not all have the same share data length.")
display("The shares are incompatible with each other because they do not all have the same share data length.")
}
MissingShares(provided: usize, required: u8) { MissingShares(provided: usize, required: u8) {
description("The number of shares provided is insufficient to recover the secret.") description("The number of shares provided is insufficient to recover the secret.")
display("{} shares are required to recover the secret, found only {}.", required, provided) display("{} shares are required to recover the secret, found only {}.", required, provided)

View File

@ -33,14 +33,17 @@ pub(crate) fn validate_shares<S: IsShare>(shares: Vec<S>) -> Result<(u8, Vec<S>)
let mut result: Vec<S> = Vec::with_capacity(shares_count); let mut result: Vec<S> = Vec::with_capacity(shares_count);
let mut k_compatibility_sets = HashMap::new(); let mut k_compatibility_sets = HashMap::new();
let mut data_len_compatibility_sets = HashMap::new();
for share in shares { for share in shares {
let (id, threshold) = (share.get_id(), share.get_threshold()); let (id, threshold, data_len) = (share.get_id(), share.get_threshold(), share.get_data().len());
if id < 1 { if id < 1 {
bail!(ErrorKind::ShareParsingInvalidShareId(id)) bail!(ErrorKind::ShareParsingInvalidShareId(id))
} else if threshold < 2 { } else if threshold < 2 {
bail!(ErrorKind::ShareParsingInvalidShareThreshold(threshold, id)) bail!(ErrorKind::ShareParsingInvalidShareThreshold(threshold, id))
} else if data_len < 1 {
bail!(ErrorKind::ShareParsingErrorEmptyShare(id))
} }
k_compatibility_sets k_compatibility_sets
@ -53,9 +56,12 @@ pub(crate) fn validate_shares<S: IsShare>(shares: Vec<S>) -> Result<(u8, Vec<S>)
bail!(ErrorKind::DuplicateShareId(id)); bail!(ErrorKind::DuplicateShareId(id));
} }
if share.get_data().is_empty() { data_len_compatibility_sets
bail!(ErrorKind::ShareParsingErrorEmptyShare(id)) .entry(data_len)
} .or_insert_with(HashSet::new);
let data_len_set = data_len_compatibility_sets.get_mut(&data_len).unwrap();
data_len_set.insert(id);
result.push(share); result.push(share);
} }
@ -84,6 +90,23 @@ pub(crate) fn validate_shares<S: IsShare>(shares: Vec<S>) -> Result<(u8, Vec<S>)
bail!(ErrorKind::MissingShares(shares_count, threshold)); bail!(ErrorKind::MissingShares(shares_count, threshold));
} }
// Validate share length consistency
let data_len_sets = data_len_compatibility_sets.keys().count();
match data_len_sets {
1 => {} // All shares have the same `data` field len
_ => {
bail! {
ErrorKind::IncompatibleDataLengths(
data_len_compatibility_sets
.values()
.map(|x| x.to_owned())
.collect(),
)
}
}
}
Ok((threshold, result)) Ok((threshold, result))
} }

View File

@ -66,6 +66,17 @@ fn test_recover_duplicate_shares_number() {
recover_secret(&shares, false).unwrap(); recover_secret(&shares, false).unwrap();
} }
#[test]
#[should_panic(expected = "IncompatibleDataLengths")]
fn test_recover_incompatible_data_lengths() {
let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
let share2 = "2-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();
let shares = vec![share1, share2];
recover_secret(&shares, false).unwrap();
}
#[test] #[test]
#[should_panic(expected = "MissingShares")] #[should_panic(expected = "MissingShares")]
fn test_recover_too_few_shares() { fn test_recover_too_few_shares() {