|  | @@ -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);
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  }
 |  |  }
 |