Browse Source

initial commit

Chelsea H. Komlo 4 years ago
commit
720a16f144
4 changed files with 617 additions and 0 deletions
  1. 256 0
      Cargo.lock
  2. 10 0
      Cargo.toml
  3. 4 0
      src/lib.rs
  4. 347 0
      src/vss.rs

+ 256 - 0
Cargo.lock

@@ -0,0 +1,256 @@
+[[package]]
+name = "autocfg"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cc"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clear_on_drop"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "digest"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fuchsia-zircon"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fuchsia-zircon-sys"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "generic-array"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand_hc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_os"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "subtle"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "typenum"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vss"
+version = "0.1.0"
+dependencies = [
+ "curve25519-dalek 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727"
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
+"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
+"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+"checksum curve25519-dalek 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "78c944d9a3cb6cdbe1289fa187c747de2a552d3fb9d8f0007cf77bee20a61369"
+"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
+"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
+"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
+"checksum rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3906503e80ac6cbcacb2c2973fa8e473f24d7e2747c8c92bb230c2441cad96b5"
+"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
+"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+"checksum rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46fbd5550acf75b0c2730f5dd1873751daf9beb8f11b44027778fae50d7feca"
+"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
+"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926"
+"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
+"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 10 - 0
Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "vss"
+version = "0.1.0"
+authors = ["Ian Goldberg <iang@uwaterloo.ca>", "Chelsea H. Komlo <ckomlo@uwaterloo.ca>"]
+edition = "2018"
+
+[dependencies]
+
+curve25519-dalek = "1"
+rand = "0.6"

+ 4 - 0
src/lib.rs

@@ -0,0 +1,4 @@
+extern crate curve25519_dalek;
+extern crate rand;
+
+pub mod vss;

+ 347 - 0
src/vss.rs

@@ -0,0 +1,347 @@
+use curve25519_dalek::edwards::EdwardsPoint;
+use curve25519_dalek::traits::Identity;
+use curve25519_dalek::scalar::Scalar;
+use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
+use rand::rngs::ThreadRng;
+
+pub type Secret = Scalar;
+
+#[derive(Copy, Clone)]
+pub struct Share {
+    index: u32,
+    value: Scalar,
+}
+
+pub struct Commitment {
+    coms: Vec<EdwardsPoint>,
+}
+
+/// Create secret shares for a given secret.
+pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result<(Commitment, Vec<Share>), &'static str> {
+    if threshold < 1 { return Err("Threshold cannot be 0") }
+    if numshares < 1 { return Err("Number of shares cannot be 0") }
+    if threshold > numshares { return Err("Threshold cannot exceed numshares") }
+
+    let numcoeffs = (threshold-1) as usize;
+
+    let mut coeffs: Vec<Scalar> = Vec::with_capacity(numcoeffs);
+
+    let mut rng: ThreadRng = rand::thread_rng();
+
+    let mut shares: Vec<Share> = Vec::with_capacity(numshares as usize);
+
+    let mut comm: Commitment = Commitment { coms: Vec::with_capacity(threshold as usize) };
+
+    for _ in 0..numcoeffs {
+        coeffs.push(Scalar::random(&mut rng));
+    }
+
+    for share_index in 1..numshares+1 {
+        // Evaluate the polynomial with `secret` as the constant term
+        // and `coeffs` as the other coefficients at the point x=share_index
+        // using Horner's method
+        let scalar_index = Scalar::from(share_index);
+        let mut value = Scalar::zero();
+        for i in (0..numcoeffs).rev() {
+            value += coeffs[i];
+            value *= scalar_index;
+        }
+        value += secret;
+        shares.push(Share{ index: share_index, value: value });
+    }
+
+    comm.coms.push(ED25519_BASEPOINT_POINT * secret);
+    for c in coeffs {
+        comm.coms.push(ED25519_BASEPOINT_POINT * c);
+    }
+
+    Ok((comm, shares))
+}
+
+/// Verify that a share is consistent with a commitment.
+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);
+
+    let (_, result) = commitment.coms.iter().fold(
+        (Scalar::one(), EdwardsPoint::identity()),
+            |(x_to_the_i, sum_so_far), comm_i|
+            (x_to_the_i * x, sum_so_far + x_to_the_i * comm_i));
+
+    let is_valid = f_result == result;
+    Ok(is_valid)
+}
+
+/// Reconstruct the secret from enough (at least the threshold) already-verified shares.
+pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
+    let numshares = shares.len();
+
+    if numshares < 1 { return Err("No shares provided"); }
+
+    let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares);
+
+    for i in 0..numshares {
+        let mut num = Scalar::one();
+        let mut den = Scalar::one();
+        for j in 0..numshares {
+            if j==i { continue; }
+            num *= Scalar::from(shares[j].index);
+            den *= Scalar::from(shares[j].index) - Scalar::from(shares[i].index);
+        }
+        if den == Scalar::zero() {
+            return Err("Duplicate shares provided");
+        }
+        lagrange_coeffs.push(num * den.invert());
+    }
+
+    let mut secret = Scalar::zero();
+
+    for i in 0..numshares {
+        secret += lagrange_coeffs[i] * shares[i].value;
+    }
+
+    Ok(secret)
+}
+
+/// 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)
+}
+
+/// 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);
+    }
+
+    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 share_is_valid = match verify_share(&updated_share, updated_commitment) {
+        Ok(n) => n,
+        Err(_) => return Err("Error when validating share"),
+    };
+
+    if !share_is_valid {
+        return Err("Share is invalid");
+    }
+
+    Ok(updated_share)
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::vss::*;
+
+    #[test]
+    fn share_simple() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 5, 2);
+        assert!(res.is_ok());
+        let (com, shares) = res.unwrap();
+        assert!(shares.len() == 5);
+        assert!(com.coms.len() == 2);
+
+        let mut recshares: Vec<Share> = Vec::new();
+        recshares.push(shares[1]);
+        recshares.push(shares[3]);
+        let recres = reconstruct_secret(&recshares);
+        assert!(recres.is_ok());
+        assert_eq!(recres.unwrap(), s);
+    }
+
+    #[test]
+    fn share_not_enough() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 5, 2);
+        assert!(res.is_ok());
+        let (_, shares) = res.unwrap();
+
+        let mut recshares: Vec<Share> = Vec::new();
+        recshares.push(shares[1]);
+        let recres = reconstruct_secret(&recshares);
+        assert!(recres.is_ok());
+        assert_ne!(recres.unwrap(), s);
+    }
+
+    #[test]
+    fn share_dup() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 5, 2);
+        assert!(res.is_ok());
+        let (_, shares) = res.unwrap();
+
+        let mut recshares: Vec<Share> = Vec::new();
+        recshares.push(shares[1]);
+        recshares.push(shares[1]);
+        let recres = reconstruct_secret(&recshares);
+        assert!(recres.is_err());
+        assert_eq!(recres.err(), Some("Duplicate shares provided"));
+    }
+
+    #[test]
+    fn share_badparams() {
+        let s = Secret::from(42u32);
+
+        {
+            let res = generate_shares(s, 5, 0);
+            assert!(res.is_err());
+            assert_eq!(res.err(), Some("Threshold cannot be 0"));
+        }
+        {
+            let res = generate_shares(s, 0, 3);
+            assert!(res.is_err());
+            assert_eq!(res.err(), Some("Number of shares cannot be 0"));
+        }
+        {
+            let res = generate_shares(s, 1, 3);
+            assert!(res.is_err());
+            assert_eq!(res.err(), Some("Threshold cannot exceed numshares"));
+        }
+    }
+
+    #[test]
+    fn share_commitment_valid() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 8, 3);
+        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(42u32);
+
+        let res1 = generate_shares(s1, 8, 3);
+        assert!(res1.is_ok());
+        let (_, shares1) = res1.unwrap();
+
+        let res2 = generate_shares(s2, 8, 3);
+        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);
+        }
+    }
+
+    #[test]
+    fn share_update_valid() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 5, 2);
+        assert!(res.is_ok());
+        let (com, shares) = res.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);
+        }
+
+        // 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, &updated_commitment);
+            assert!(is_valid.is_ok());
+            assert!(!is_valid.unwrap());
+        }
+    }
+
+    #[test]
+    fn share_update_valid_multiple_updates() {
+        let s = Secret::from(42u32);
+
+        let res = generate_shares(s, 5, 2);
+        assert!(res.is_ok());
+        let (com, shares) = res.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 {
+
+            // 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);
+
+                assert!(update_share_res.is_ok());
+                let updated_share = update_share_res.unwrap();
+
+                // only collect the last round of updated shares
+                if i == 4 {
+                    updated_shares.push(updated_share);
+                }
+                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);
+    }
+}