|
@@ -5,6 +5,7 @@ use rand::rngs::ThreadRng;
|
|
|
|
|
|
pub type Secret = Scalar;
|
|
pub type Secret = Scalar;
|
|
|
|
|
|
|
|
+#[derive(Copy, Clone)]
|
|
pub struct Share {
|
|
pub struct Share {
|
|
index: u32,
|
|
index: u32,
|
|
value: Scalar,
|
|
value: Scalar,
|
|
@@ -30,17 +31,17 @@ pub fn generate_shares(secret: Secret, numshares: u32, threshold: u32) -> Result
|
|
|
|
|
|
let mut comm: Commitment = Commitment { coms: Vec::with_capacity(threshold as usize) };
|
|
let mut comm: Commitment = Commitment { coms: Vec::with_capacity(threshold as usize) };
|
|
|
|
|
|
- for _ in 1..numcoeffs {
|
|
|
|
|
|
+ for _ in 0..numcoeffs {
|
|
coeffs.push(Scalar::random(&mut rng));
|
|
coeffs.push(Scalar::random(&mut rng));
|
|
}
|
|
}
|
|
|
|
|
|
- for share_index in 1..numshares {
|
|
|
|
|
|
+ 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
|
|
let scalar_index = Scalar::from(share_index);
|
|
let scalar_index = Scalar::from(share_index);
|
|
let mut value = Scalar::zero();
|
|
let mut value = Scalar::zero();
|
|
- for i in (0..numcoeffs-1).rev() {
|
|
|
|
|
|
+ for i in (0..numcoeffs).rev() {
|
|
value += coeffs[i];
|
|
value += coeffs[i];
|
|
value *= scalar_index;
|
|
value *= scalar_index;
|
|
}
|
|
}
|
|
@@ -69,13 +70,13 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
|
|
|
|
let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares);
|
|
let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares);
|
|
|
|
|
|
- for i in 0..numshares-1 {
|
|
|
|
|
|
+ for i in 0..numshares {
|
|
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-1 {
|
|
|
|
|
|
+ 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 - shares[i].index);
|
|
|
|
|
|
+ den *= (Scalar::from(shares[j].index) - Scalar::from(shares[i].index));
|
|
}
|
|
}
|
|
if den == Scalar::zero() {
|
|
if den == Scalar::zero() {
|
|
return Err("Duplicate shares provided");
|
|
return Err("Duplicate shares provided");
|
|
@@ -85,7 +86,7 @@ pub fn reconstruct_secret(shares: &Vec<Share>) -> Result<Secret, &'static str> {
|
|
|
|
|
|
let mut secret = Scalar::zero();
|
|
let mut secret = Scalar::zero();
|
|
|
|
|
|
- for i in 0..numshares-1 {
|
|
|
|
|
|
+ for i in 0..numshares {
|
|
secret += lagrange_coeffs[i] * shares[i].value;
|
|
secret += lagrange_coeffs[i] * shares[i].value;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -106,3 +107,76 @@ pub fn apply_commitment_update(oldcommitment: &Commitment, update: &Commitment)
|
|
pub fn apply_share_update(oldshare: &Share, update: &Share) -> Result<Share, &'static str> {
|
|
pub fn apply_share_update(oldshare: &Share, update: &Share) -> Result<Share, &'static str> {
|
|
unimplemented!("Not yet implemented")
|
|
unimplemented!("Not yet implemented")
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+#[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();
|
|
|
|
+
|
|
|
|
+ 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 (com, 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 (com, 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"));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|