|
@@ -1,7 +1,7 @@
|
|
|
|
+use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
|
use curve25519_dalek::edwards::EdwardsPoint;
|
|
use curve25519_dalek::edwards::EdwardsPoint;
|
|
-use curve25519_dalek::traits::Identity;
|
|
|
|
use curve25519_dalek::scalar::Scalar;
|
|
use curve25519_dalek::scalar::Scalar;
|
|
-use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
|
|
|
|
|
+use curve25519_dalek::traits::Identity;
|
|
use rand::rngs::ThreadRng;
|
|
use rand::rngs::ThreadRng;
|
|
|
|
|
|
pub type Secret = Scalar;
|
|
pub type Secret = Scalar;
|
|
@@ -12,17 +12,25 @@ pub struct Share {
|
|
value: Scalar,
|
|
value: Scalar,
|
|
}
|
|
}
|
|
|
|
|
|
-pub struct Commitment {
|
|
|
|
- coms: Vec<EdwardsPoint>,
|
|
|
|
-}
|
|
|
|
|
|
+type Commitment = Vec<EdwardsPoint>;
|
|
|
|
|
|
/// Create secret shares for a given secret.
|
|
/// 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") }
|
|
|
|
|
|
+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 numcoeffs = (threshold - 1) as usize;
|
|
|
|
|
|
let mut coeffs: Vec<Scalar> = Vec::with_capacity(numcoeffs);
|
|
let mut coeffs: Vec<Scalar> = Vec::with_capacity(numcoeffs);
|
|
|
|
|
|
@@ -30,13 +38,13 @@ pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result
|
|
|
|
|
|
let mut shares: Vec<Share> = Vec::with_capacity(numshares as usize);
|
|
let mut shares: Vec<Share> = Vec::with_capacity(numshares as usize);
|
|
|
|
|
|
- let mut comm: Commitment = Commitment { coms: Vec::with_capacity(threshold as usize) };
|
|
|
|
|
|
+ let mut commitment: Commitment = Vec::with_capacity(threshold as usize);
|
|
|
|
|
|
for _ in 0..numcoeffs {
|
|
for _ in 0..numcoeffs {
|
|
coeffs.push(Scalar::random(&mut rng));
|
|
coeffs.push(Scalar::random(&mut rng));
|
|
}
|
|
}
|
|
|
|
|
|
- for share_index in 1..numshares+1 {
|
|
|
|
|
|
+ for share_index in 1..numshares + 1 {
|
|
// Evaluate the polynomial with `secret` as the constant term
|
|
// Evaluate the polynomial with `secret` as the constant term
|
|
// and `coeffs` as the other coefficients at the point x=share_index
|
|
// and `coeffs` as the other coefficients at the point x=share_index
|
|
// using Horner's method
|
|
// using Horner's method
|
|
@@ -47,15 +55,18 @@ pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result
|
|
value *= scalar_index;
|
|
value *= scalar_index;
|
|
}
|
|
}
|
|
value += secret;
|
|
value += secret;
|
|
- shares.push(Share{ index: share_index, value: value });
|
|
|
|
|
|
+ shares.push(Share {
|
|
|
|
+ index: share_index,
|
|
|
|
+ value: value,
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
- comm.coms.push(ED25519_BASEPOINT_POINT * secret);
|
|
|
|
|
|
+ commitment.push(ED25519_BASEPOINT_POINT * secret);
|
|
for c in coeffs {
|
|
for c in coeffs {
|
|
- comm.coms.push(ED25519_BASEPOINT_POINT * c);
|
|
|
|
|
|
+ commitment.push(ED25519_BASEPOINT_POINT * c);
|
|
}
|
|
}
|
|
|
|
|
|
- Ok((comm, shares))
|
|
|
|
|
|
+ Ok((commitment, shares))
|
|
}
|
|
}
|
|
|
|
|
|
/// Verify that a share is consistent with a commitment.
|
|
/// Verify that a share is consistent with a commitment.
|
|
@@ -64,10 +75,10 @@ pub fn verify_share(share: &Share, commitment: &Commitment) -> Result<bool, &'st
|
|
|
|
|
|
let x = Scalar::from(share.index);
|
|
let x = Scalar::from(share.index);
|
|
|
|
|
|
- let (_, result) = commitment.coms.iter().fold(
|
|
|
|
|
|
+ let (_, result) = commitment.iter().fold(
|
|
(Scalar::one(), EdwardsPoint::identity()),
|
|
(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));
|
|
|
|
|
|
+ |(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;
|
|
let is_valid = f_result == result;
|
|
Ok(is_valid)
|
|
Ok(is_valid)
|
|
@@ -77,7 +88,9 @@ pub fn verify_share(share: &Share, commitment: &Commitment) -> Result<bool, &'st
|
|
pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
let numshares = shares.len();
|
|
let numshares = shares.len();
|
|
|
|
|
|
- if numshares < 1 { return Err("No shares provided"); }
|
|
|
|
|
|
+ if numshares < 1 {
|
|
|
|
+ return Err("No shares provided");
|
|
|
|
+ }
|
|
|
|
|
|
let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares);
|
|
let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares);
|
|
|
|
|
|
@@ -85,7 +98,9 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
let mut num = Scalar::one();
|
|
let mut num = Scalar::one();
|
|
let mut den = Scalar::one();
|
|
let mut den = Scalar::one();
|
|
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);
|
|
}
|
|
}
|
|
@@ -105,24 +120,34 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
}
|
|
}
|
|
|
|
|
|
/// Create a proactive update.
|
|
/// Create a proactive update.
|
|
-pub fn create_update(num_shares: u32, threshold: u32) -> Result<(Commitment, Vec<Share>), &'static str> {
|
|
|
|
|
|
+pub fn create_update(
|
|
|
|
+ num_shares: u32,
|
|
|
|
+ threshold: u32,
|
|
|
|
+) -> Result<(Commitment, Vec<Share>), &'static str> {
|
|
generate_shares(Scalar::zero(), num_shares, threshold)
|
|
generate_shares(Scalar::zero(), num_shares, threshold)
|
|
}
|
|
}
|
|
|
|
|
|
/// Apply the commitment for the update to the master commitment.
|
|
/// 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);
|
|
|
|
|
|
+pub fn apply_commitment_update(
|
|
|
|
+ old_commitment: &Commitment,
|
|
|
|
+ update: &Commitment,
|
|
|
|
+) -> Result<Commitment, &'static str> {
|
|
|
|
+ let mut new_commitments: Commitment = Vec::with_capacity(old_commitment.len());
|
|
|
|
+ for i in 0..old_commitment.len() {
|
|
|
|
+ let new_commitment = old_commitment[i] + update[i];
|
|
|
|
+ new_commitments.push(new_commitment);
|
|
}
|
|
}
|
|
|
|
|
|
Ok(new_commitments)
|
|
Ok(new_commitments)
|
|
}
|
|
}
|
|
|
|
|
|
/// Apply the share update to an existing share
|
|
/// 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{
|
|
|
|
|
|
+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,
|
|
index: old_share.index,
|
|
value: old_share.value + update.value,
|
|
value: old_share.value + update.value,
|
|
};
|
|
};
|
|
@@ -151,7 +176,7 @@ mod tests {
|
|
assert!(res.is_ok());
|
|
assert!(res.is_ok());
|
|
let (com, shares) = res.unwrap();
|
|
let (com, shares) = res.unwrap();
|
|
assert!(shares.len() == 5);
|
|
assert!(shares.len() == 5);
|
|
- assert!(com.coms.len() == 2);
|
|
|
|
|
|
+ assert!(com.len() == 2);
|
|
|
|
|
|
let mut recshares: Vec<Share> = Vec::new();
|
|
let mut recshares: Vec<Share> = Vec::new();
|
|
recshares.push(shares[1]);
|
|
recshares.push(shares[1]);
|
|
@@ -309,7 +334,6 @@ mod tests {
|
|
let mut next_com = com;
|
|
let mut next_com = com;
|
|
|
|
|
|
for i in 0..5 {
|
|
for i in 0..5 {
|
|
-
|
|
|
|
// Create a new update
|
|
// Create a new update
|
|
let update_comm_res = create_update(5, 2);
|
|
let update_comm_res = create_update(5, 2);
|
|
assert!(update_comm_res.is_ok());
|
|
assert!(update_comm_res.is_ok());
|
|
@@ -324,7 +348,8 @@ mod tests {
|
|
let mut updates_to_shares = shares_update.iter();
|
|
let mut updates_to_shares = shares_update.iter();
|
|
for share in &next_shares {
|
|
for share in &next_shares {
|
|
let share_update = updates_to_shares.next().unwrap();
|
|
let share_update = updates_to_shares.next().unwrap();
|
|
- let update_share_res = apply_share_update(&share, &share_update, &updated_commitment);
|
|
|
|
|
|
+ let update_share_res =
|
|
|
|
+ apply_share_update(&share, &share_update, &updated_commitment);
|
|
|
|
|
|
assert!(update_share_res.is_ok());
|
|
assert!(update_share_res.is_ok());
|
|
let updated_share = update_share_res.unwrap();
|
|
let updated_share = update_share_res.unwrap();
|