extern crate rusty_secrets;
use errors::IndyCryptoError;
use utils::json::{JsonEncodable, JsonDecodable};
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
pub struct Share {
value: String
}
impl ToString for Share {
fn to_string(&self) -> String {
format!("{}", self.value)
}
}
impl JsonEncodable for Share {}
impl<'a> JsonDecodable<'a> for Share {}
pub fn shard_secret(m: usize, n: usize, secret: &Vec<u8>, sign_shares: bool) -> Result<Vec<Share>, IndyCryptoError> {
match rusty_secrets::sss::split_secret(m as u8, n as u8, &secret.as_slice(), sign_shares) {
Ok(shares) => Ok(shares.into_iter().map(|share| Share { value: share }).collect()),
Err(msg) => Err(IndyCryptoError::InvalidStructure(format!("Unable to create shares: {:?}", msg)))
}
}
pub fn recover_secret(shares: Vec<Share>, verify_signature: bool) -> Result<Vec<u8>, IndyCryptoError> {
let string_shares: Vec<String> = shares.into_iter().map(|share| share.value).collect();
match rusty_secrets::sss::recover_secret(&string_shares, verify_signature) {
Ok(secret) => Ok(secret.to_vec()),
Err(msg) => Err(IndyCryptoError::InvalidStructure(format!("Unable to recreate secret: {:?}", msg)))
}
}
pub fn get_shard_by_no(shares: &Vec<Share>, number: usize) -> Result<Share, IndyCryptoError> {
if shares.len() < number {
return Err(IndyCryptoError::InvalidParam2(format!("number cannot be greater than count of shares")));
}
let string_shares = shares.into_iter().map(|share| share.value.clone()).collect::<Vec<String>>();
for share in &string_shares[..] {
let split = share.split("-").collect::<Vec<&str>>();
if split[1].parse::<usize>().unwrap() == number {
return Ok(Share { value: share.clone() });
}
}
return Err(IndyCryptoError::InvalidStructure(format!("No share found with number {}", number)))
}
#[cfg(test)]
mod tests {
use super::*;
use std::str;
pub const SECRET: &'static str = "this is a really big test string";
fn check_secret(secret: &str, mut shares: Vec<Share>, p: usize){
let recovered_secret = recover_secret(shares.split_at_mut(p).0.to_vec(), false).unwrap();
let recovered_secret_as_str = str::from_utf8(&recovered_secret).unwrap();
println!("recovered secret={:?}; from {} shares", &recovered_secret_as_str, p);
assert_eq!(secret, recovered_secret_as_str);
}
#[test]
fn test_create_shards() {
let shares = shard_secret(3, 5, &SECRET.as_bytes().to_vec(), false).unwrap();
println!("shares={:?}", shares);
assert_eq!(shares.len(), 5);
}
#[test]
fn test_recover_secret() {
let mut shares = shard_secret(3, 5, &SECRET.as_bytes().to_vec(), false).unwrap();
check_secret(&SECRET, shares.clone(), 3);
check_secret(&SECRET, shares.clone(), 4);
assert!(recover_secret(shares.split_at_mut(2).0.to_vec(), false).is_err());
}
#[test]
fn test_get_shard_by_number() {
let shards = shard_secret(3, 5, &SECRET.as_bytes().to_vec(), false).unwrap();
let s = get_shard_by_no(&shards, 2).unwrap();
println!("{:?}", &s);
assert_eq!(&s, &shards[1]);
assert!(get_shard_by_no(&shards, 7).is_err());
}
}