|
@@ -58,8 +58,25 @@ pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result
|
|
}
|
|
}
|
|
|
|
|
|
/// Verify that a share is consistent with a commitment.
|
|
/// Verify that a share is consistent with a commitment.
|
|
-pub fn verify_share(share: Share, commitment: Commitment) -> Result<bool, &'static str> {
|
|
|
|
- unimplemented!("Not yet implemented")
|
|
|
|
|
|
+pub fn verify_share(share: Share, commitment: &Commitment) -> Result<bool, &'static str> {
|
|
|
|
+ let f_result = ED25519_BASEPOINT_POINT * share.value;
|
|
|
|
+
|
|
|
|
+ // always calculate at least the first share
|
|
|
|
+ let mut result = commitment.coms[0];
|
|
|
|
+
|
|
|
|
+ for i in 1..share.index+1 {
|
|
|
|
+ // check in case of the last share
|
|
|
|
+ if (i as usize) >= commitment.coms.len() {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let next_comm = commitment.coms[i as usize];
|
|
|
|
+ let x_raised_to_threshold = share.index.pow(i as u32);
|
|
|
|
+ result += next_comm * Scalar::from(x_raised_to_threshold);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let is_valid = f_result == result;
|
|
|
|
+ Ok(is_valid)
|
|
}
|
|
}
|
|
|
|
|
|
/// Reconstruct the secret from enough (at least the threshold) already-verified shares.
|
|
/// Reconstruct the secret from enough (at least the threshold) already-verified shares.
|
|
@@ -76,7 +93,7 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
for j in 0..numshares {
|
|
for j in 0..numshares {
|
|
if j==i { continue; }
|
|
if j==i { continue; }
|
|
num *= Scalar::from(shares[j].index);
|
|
num *= Scalar::from(shares[j].index);
|
|
- den *= (Scalar::from(shares[j].index) - Scalar::from(shares[i].index));
|
|
|
|
|
|
+ den *= Scalar::from(shares[j].index) - Scalar::from(shares[i].index);
|
|
}
|
|
}
|
|
if den == Scalar::zero() {
|
|
if den == Scalar::zero() {
|
|
return Err("Duplicate shares provided");
|
|
return Err("Duplicate shares provided");
|
|
@@ -119,6 +136,7 @@ mod tests {
|
|
let res = generate_shares(s, 5, 2);
|
|
let res = generate_shares(s, 5, 2);
|
|
assert!(res.is_ok());
|
|
assert!(res.is_ok());
|
|
let (com, shares) = res.unwrap();
|
|
let (com, shares) = res.unwrap();
|
|
|
|
+ assert!(shares.len() == 5);
|
|
|
|
|
|
let mut recshares: Vec<Share> = Vec::new();
|
|
let mut recshares: Vec<Share> = Vec::new();
|
|
recshares.push(shares[1]);
|
|
recshares.push(shares[1]);
|
|
@@ -179,4 +197,40 @@ mod tests {
|
|
assert_eq!(res.err(), Some("Threshold cannot exceed numshares"));
|
|
assert_eq!(res.err(), Some("Threshold cannot exceed numshares"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn share_commitment_valid() {
|
|
|
|
+ let s = Secret::from(42u32);
|
|
|
|
+
|
|
|
|
+ let res = generate_shares(s, 5, 2);
|
|
|
|
+ assert!(res.is_ok());
|
|
|
|
+ let (com, shares) = res.unwrap();
|
|
|
|
+
|
|
|
|
+ for share in shares {
|
|
|
|
+ let is_valid = verify_share(share, &com);
|
|
|
|
+ assert!(is_valid.is_ok());
|
|
|
|
+ assert!(is_valid.unwrap());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn share_commitment_invalid() {
|
|
|
|
+ let s1 = Secret::from(42u32);
|
|
|
|
+ let s2 = Secret::from(43u32);
|
|
|
|
+
|
|
|
|
+ let res1 = generate_shares(s1, 5, 2);
|
|
|
|
+ assert!(res1.is_ok());
|
|
|
|
+ let (_, shares1) = res1.unwrap();
|
|
|
|
+
|
|
|
|
+ let res2 = generate_shares(s2, 5, 2);
|
|
|
|
+ assert!(res2.is_ok());
|
|
|
|
+ let (com2, _) = res2.unwrap();
|
|
|
|
+
|
|
|
|
+ for share in shares1 {
|
|
|
|
+ // test that commitments to a different set of shares fails
|
|
|
|
+ let is_valid = verify_share(share, &com2);
|
|
|
|
+ assert!(is_valid.is_ok());
|
|
|
|
+ assert_ne!(is_valid.unwrap(), true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|