|
@@ -59,7 +59,7 @@ 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> {
|
|
|
|
|
|
+pub fn verify_share(share: &Share, commitment: &Commitment) -> Result<bool, &'static str> {
|
|
let f_result = ED25519_BASEPOINT_POINT * share.value;
|
|
let f_result = ED25519_BASEPOINT_POINT * share.value;
|
|
|
|
|
|
let x = Scalar::from(share.index);
|
|
let x = Scalar::from(share.index);
|
|
@@ -101,38 +101,42 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
secret += lagrange_coeffs[i] * shares[i].value;
|
|
secret += lagrange_coeffs[i] * shares[i].value;
|
|
}
|
|
}
|
|
|
|
|
|
- return Ok(secret)
|
|
|
|
|
|
+ Ok(secret)
|
|
}
|
|
}
|
|
|
|
|
|
-/// Create and apply a proactive update to a master commitment.
|
|
|
|
-pub fn update_shares(old_commitment: &Commitment, old_shares: &Vec<Share>) -> Result<(Commitment, Vec<Share>), &'static str> {
|
|
|
|
- let num_shares = old_shares.len() as u32;
|
|
|
|
- let threshold = old_commitment.coms.len() as u32;
|
|
|
|
- let res = generate_shares(Scalar::zero(), num_shares, threshold);
|
|
|
|
|
|
+/// Create a proactive update.
|
|
|
|
+pub fn create_update(num_shares: u32, threshold: u32) -> Result<(Commitment, Vec<Share>), &'static str> {
|
|
|
|
+ generate_shares(Scalar::zero(), num_shares, threshold)
|
|
|
|
+}
|
|
|
|
|
|
- if !res.is_ok() {
|
|
|
|
- return res;
|
|
|
|
|
|
+/// Apply the commitment for the update to the master commitment.
|
|
|
|
+pub fn apply_commitment_update(old_commitment: &Commitment, update: &Commitment) -> Result<Commitment, &'static str> {
|
|
|
|
+ let mut new_commitments: Commitment = Commitment { coms: Vec::with_capacity(old_commitment.coms.len()) };
|
|
|
|
+ for i in 0..old_commitment.coms.len() {
|
|
|
|
+ let new_commitment = old_commitment.coms[i] + update.coms[i];
|
|
|
|
+ new_commitments.coms.push(new_commitment);
|
|
}
|
|
}
|
|
|
|
|
|
- let (update_commitments, update_shares) = res.unwrap();
|
|
|
|
|
|
+ Ok(new_commitments)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Apply the share update to an existing share
|
|
|
|
+pub fn apply_share_update(old_share: &Share, update: &Share, updated_commitment: &Commitment) -> Result<Share, &'static str> {
|
|
|
|
+ let updated_share = Share{
|
|
|
|
+ index: old_share.index,
|
|
|
|
+ value: old_share.value + update.value,
|
|
|
|
+ };
|
|
|
|
|
|
- let mut new_shares: Vec<Share> = Vec::with_capacity(num_shares as usize);
|
|
|
|
- for old_share in old_shares {
|
|
|
|
- let update_share = update_shares[(old_share.index-1) as usize];
|
|
|
|
- let new_share = Share{
|
|
|
|
- index: old_share.index,
|
|
|
|
- value: old_share.value + update_share.value,
|
|
|
|
- };
|
|
|
|
- new_shares.push(new_share);
|
|
|
|
- }
|
|
|
|
|
|
+ let share_is_valid = match verify_share(&updated_share, updated_commitment) {
|
|
|
|
+ Ok(n) => n,
|
|
|
|
+ Err(_) => return Err("Error when validating share"),
|
|
|
|
+ };
|
|
|
|
|
|
- let mut new_commitments: Commitment = Commitment { coms: Vec::with_capacity(threshold as usize) };
|
|
|
|
- for i in 0..old_commitment.coms.len() {
|
|
|
|
- let new_commitment = old_commitment.coms[i] + update_commitments.coms[i];
|
|
|
|
- new_commitments.coms.push(new_commitment);
|
|
|
|
|
|
+ if !share_is_valid {
|
|
|
|
+ return Err("Share is invalid");
|
|
}
|
|
}
|
|
|
|
|
|
- Ok((new_commitments, new_shares))
|
|
|
|
|
|
+ Ok(updated_share)
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
@@ -218,7 +222,7 @@ mod tests {
|
|
let (com, shares) = res.unwrap();
|
|
let (com, shares) = res.unwrap();
|
|
|
|
|
|
for share in shares {
|
|
for share in shares {
|
|
- let is_valid = verify_share(share, &com);
|
|
|
|
|
|
+ let is_valid = verify_share(&share, &com);
|
|
assert!(is_valid.is_ok());
|
|
assert!(is_valid.is_ok());
|
|
assert!(is_valid.unwrap());
|
|
assert!(is_valid.unwrap());
|
|
}
|
|
}
|
|
@@ -239,7 +243,7 @@ mod tests {
|
|
|
|
|
|
for share in shares1 {
|
|
for share in shares1 {
|
|
// test that commitments to a different set of shares fails
|
|
// test that commitments to a different set of shares fails
|
|
- let is_valid = verify_share(share, &com2);
|
|
|
|
|
|
+ let is_valid = verify_share(&share, &com2);
|
|
assert!(is_valid.is_ok());
|
|
assert!(is_valid.is_ok());
|
|
assert_ne!(is_valid.unwrap(), true);
|
|
assert_ne!(is_valid.unwrap(), true);
|
|
}
|
|
}
|
|
@@ -253,40 +257,40 @@ mod tests {
|
|
assert!(res.is_ok());
|
|
assert!(res.is_ok());
|
|
let (com, shares) = res.unwrap();
|
|
let (com, shares) = res.unwrap();
|
|
|
|
|
|
- let update_res = update_shares(&com, &shares);
|
|
|
|
- assert!(update_res.is_ok());
|
|
|
|
- let (update_com, update_shares) = update_res.unwrap();
|
|
|
|
-
|
|
|
|
- for share in update_shares {
|
|
|
|
- let is_valid = verify_share(share, &update_com);
|
|
|
|
- assert!(is_valid.is_ok());
|
|
|
|
- assert!(is_valid.unwrap());
|
|
|
|
|
|
+ // Create a new update
|
|
|
|
+ let update_comm_res = create_update(5, 2);
|
|
|
|
+ assert!(update_comm_res.is_ok());
|
|
|
|
+ let (com_update, shares_update) = update_comm_res.unwrap();
|
|
|
|
+
|
|
|
|
+ // Apply the update to previously-created committment
|
|
|
|
+ let updated_commitment_res = apply_commitment_update(&com, &com_update);
|
|
|
|
+ assert!(updated_commitment_res.is_ok());
|
|
|
|
+ let updated_commitment = updated_commitment_res.unwrap();
|
|
|
|
+
|
|
|
|
+ // Distribute the update to all owners of shares
|
|
|
|
+ // Verify and apply the update
|
|
|
|
+ // Collect updated shares to test secret reconstruction after
|
|
|
|
+ let mut updates_to_shares = shares_update.iter();
|
|
|
|
+ let mut updated_shares: Vec<Share> = Vec::with_capacity(5);
|
|
|
|
+ for share in &shares {
|
|
|
|
+ let share_update = updates_to_shares.next().unwrap();
|
|
|
|
+ let update_share_res = apply_share_update(&share, &share_update, &updated_commitment);
|
|
|
|
+ assert!(update_share_res.is_ok());
|
|
|
|
+ let updated_share = update_share_res.unwrap();
|
|
|
|
+ updated_shares.push(updated_share);
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- #[test]
|
|
|
|
- fn share_update_invalid() {
|
|
|
|
- let s = Secret::from(42u32);
|
|
|
|
-
|
|
|
|
- let res = generate_shares(s, 5, 2);
|
|
|
|
- assert!(res.is_ok());
|
|
|
|
- let (com, shares) = res.unwrap();
|
|
|
|
|
|
|
|
- let update_res = update_shares(&com, &shares);
|
|
|
|
- assert!(update_res.is_ok());
|
|
|
|
- let (update_com, update_shares) = update_res.unwrap();
|
|
|
|
|
|
+ // assert that we can recover the original secret using the updated shares
|
|
|
|
+ let recres = reconstruct_secret(&updated_shares);
|
|
|
|
+ assert!(recres.is_ok());
|
|
|
|
+ assert_eq!(recres.unwrap(), s);
|
|
|
|
|
|
// test that the old shares are not valid with the updated commitment
|
|
// test that the old shares are not valid with the updated commitment
|
|
- for share in shares {
|
|
|
|
- let is_valid = verify_share(share, &update_com);
|
|
|
|
|
|
+ for share in &shares {
|
|
|
|
+ let is_valid = verify_share(&share, &updated_commitment);
|
|
assert!(is_valid.is_ok());
|
|
assert!(is_valid.is_ok());
|
|
assert!(!is_valid.unwrap());
|
|
assert!(!is_valid.unwrap());
|
|
}
|
|
}
|
|
-
|
|
|
|
- // assert that we can recover the original secret using the updated shares
|
|
|
|
- let recres = reconstruct_secret(&update_shares);
|
|
|
|
- assert!(recres.is_ok());
|
|
|
|
- assert_eq!(recres.unwrap(), s);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
@@ -297,16 +301,53 @@ mod tests {
|
|
assert!(res.is_ok());
|
|
assert!(res.is_ok());
|
|
let (com, shares) = res.unwrap();
|
|
let (com, shares) = res.unwrap();
|
|
|
|
|
|
- for _ in 0..5 {
|
|
|
|
- let update_res = update_shares(&com, &shares);
|
|
|
|
- assert!(update_res.is_ok());
|
|
|
|
- let (update_com, update_shares) = update_res.unwrap();
|
|
|
|
-
|
|
|
|
- for share in update_shares {
|
|
|
|
- let is_valid = verify_share(share, &update_com);
|
|
|
|
- assert!(is_valid.is_ok());
|
|
|
|
- assert!(is_valid.unwrap());
|
|
|
|
|
|
+ // final shares to test at the end
|
|
|
|
+ let mut updated_shares: Vec<Share> = Vec::with_capacity(5);
|
|
|
|
+
|
|
|
|
+ // override these each time in the loop
|
|
|
|
+ let mut next_shares = shares;
|
|
|
|
+ let mut next_com = com;
|
|
|
|
+
|
|
|
|
+ for i in 0..5 {
|
|
|
|
+ print!("{:?} \n", i);
|
|
|
|
+
|
|
|
|
+ // Create a new update
|
|
|
|
+ let update_comm_res = create_update(5, 2);
|
|
|
|
+ assert!(update_comm_res.is_ok());
|
|
|
|
+ let (com_update, shares_update) = update_comm_res.unwrap();
|
|
|
|
+
|
|
|
|
+ // Apply the update to previously-created committment
|
|
|
|
+ let updated_commitment_res = apply_commitment_update(&next_com, &com_update);
|
|
|
|
+ assert!(updated_commitment_res.is_ok());
|
|
|
|
+ let updated_commitment = updated_commitment_res.unwrap();
|
|
|
|
+
|
|
|
|
+ let mut iterim_shares: Vec<Share> = Vec::with_capacity(5);
|
|
|
|
+ let mut updates_to_shares = shares_update.iter();
|
|
|
|
+ for share in &next_shares {
|
|
|
|
+ let share_update = updates_to_shares.next().unwrap();
|
|
|
|
+ let update_share_res = apply_share_update(&share, &share_update, &updated_commitment);
|
|
|
|
+ if !update_share_res.is_ok() {
|
|
|
|
+ print!("Error when updating share: {:?} \n", update_share_res.err());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ assert!(update_share_res.is_ok());
|
|
|
|
+ let updated_share = update_share_res.unwrap();
|
|
|
|
+
|
|
|
|
+ // only collect the last round of updated shares
|
|
|
|
+ if i == 4 {
|
|
|
|
+ print!("here {:?} \n", i);
|
|
|
|
+ updated_shares.push(updated_share);
|
|
|
|
+ print!("len {:?} \n", updated_shares.len());
|
|
|
|
+ }
|
|
|
|
+ iterim_shares.push(updated_share);
|
|
}
|
|
}
|
|
|
|
+ next_shares = iterim_shares;
|
|
|
|
+ next_com = updated_commitment;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // assert that we can recover the original secret using the updated shares
|
|
|
|
+ let recres = reconstruct_secret(&updated_shares);
|
|
|
|
+ assert!(recres.is_ok());
|
|
|
|
+ assert_eq!(recres.unwrap(), s);
|
|
}
|
|
}
|
|
}
|
|
}
|