Browse Source

API for correct user/updater interface

ckomlo 5 years ago
parent
commit
86656669cb
1 changed files with 103 additions and 62 deletions
  1. 103 62
      src/vss.rs

+ 103 - 62
src/vss.rs

@@ -59,7 +59,7 @@ pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result
 }
 
 /// 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 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;
     }
 
-    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)]
@@ -218,7 +222,7 @@ mod tests {
         let (com, shares) = res.unwrap();
 
         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.unwrap());
         }
@@ -239,7 +243,7 @@ mod tests {
 
         for share in shares1 {
             // 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_ne!(is_valid.unwrap(), true);
         }
@@ -253,40 +257,40 @@ mod tests {
         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();
-
-        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
-        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.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]
@@ -297,16 +301,53 @@ mod tests {
         assert!(res.is_ok());
         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);
     }
 }