mirror of
https://github.com/mii443/RustySecrets.git
synced 2025-08-23 00:35:38 +00:00
Part 1 of #1. Refactoring to separate lib from command line.
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -1,8 +1,9 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "secretshare"
|
name = "rusty-secrets"
|
||||||
version = "0.1.6"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
16
Cargo.toml
16
Cargo.toml
@ -1,8 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "secretshare"
|
name = "rusty-secrets"
|
||||||
version = "0.1.6"
|
version = "0.0.1"
|
||||||
authors = ["Sebastian Gesemann <s.gesemann@gmail.com>"]
|
description = "Implementation of threshold Shamir secret sharing in the Rust programming language."
|
||||||
description = "This is an implementation of Shamir's secret sharing scheme."
|
|
||||||
license = "GPLv3"
|
license = "GPLv3"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
@ -10,3 +9,12 @@ readme = "README.md"
|
|||||||
getopts = "^0.2.14"
|
getopts = "^0.2.14"
|
||||||
rustc-serialize = "^0.3.18"
|
rustc-serialize = "^0.3.18"
|
||||||
rand = "^0.3.14"
|
rand = "^0.3.14"
|
||||||
|
libc = "^0.2.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "rusty_secrets_lib"
|
||||||
|
path = "src/lib/mod.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "rusty_secrets_bin"
|
||||||
|
path = "src/main.rs"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# secretshare
|
# Rusty Secrets
|
||||||
|
|
||||||
This program is an implementation of
|
This program is an implementation of
|
||||||
[Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing).
|
[Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing).
|
||||||
@ -107,3 +107,8 @@ field I used is the same as the one you can find in the RAID 6
|
|||||||
implementation of the Linux kernel or the Anubis block cipher:
|
implementation of the Linux kernel or the Anubis block cipher:
|
||||||
Gf(2^8) reduction polynomial is x^8 + x^4 + x^3 + x^2 + 1 or
|
Gf(2^8) reduction polynomial is x^8 + x^4 + x^3 + x^2 + 1 or
|
||||||
alternatively 11D in hex.
|
alternatively 11D in hex.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Rusty Secrets was forked off [sellibitze's secretshare.](https://github.com/sellibitze/secretshare)
|
||||||
|
|
||||||
|
44
src/lib/custom_error.rs
Normal file
44
src/lib/custom_error.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
pub use std::convert;
|
||||||
|
pub use std::io::prelude::*;
|
||||||
|
|
||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
descr: &'static str,
|
||||||
|
detail: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn new(descr: &'static str, detail: Option<String>) -> Error {
|
||||||
|
Error { descr: descr, detail: detail }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self.detail {
|
||||||
|
None => write!(f, "{}", self.descr),
|
||||||
|
Some(ref detail) => write!(f, "{} ({})", self.descr, detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn description(&self) -> &str { self.descr }
|
||||||
|
fn cause(&self) -> Option<&error::Error> { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl convert::From<Error> for io::Error {
|
||||||
|
fn from(me: Error) -> io::Error {
|
||||||
|
io::Error::new(io::ErrorKind::Other, me)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn other_io_err(descr: &'static str, detail: Option<String>) -> io::Error {
|
||||||
|
convert::From::from(
|
||||||
|
Error::new(descr, detail)
|
||||||
|
)
|
||||||
|
}
|
@ -140,4 +140,3 @@ impl Div<Gf256> for Gf256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
111
src/lib/mod.rs
Normal file
111
src/lib/mod.rs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
extern crate rustc_serialize as serialize;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
use self::rand::{ Rng, OsRng };
|
||||||
|
pub use self::serialize::base64::{ self, FromBase64, ToBase64 };
|
||||||
|
|
||||||
|
mod gf256;
|
||||||
|
use self::gf256::Gf256;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
pub use std::str;
|
||||||
|
use std::iter::repeat;
|
||||||
|
|
||||||
|
pub mod custom_error;
|
||||||
|
use self::custom_error::*;
|
||||||
|
|
||||||
|
fn new_vec<T: Clone>(n: usize, x: T) -> Vec<T> {
|
||||||
|
repeat(x).take(n).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive)
|
||||||
|
fn encode<W: Write>(src: &[u8], n: u8, w: &mut W) -> io::Result<()> {
|
||||||
|
for raw_x in 1 .. ((n as u16) + 1) {
|
||||||
|
let x = Gf256::from_byte(raw_x as u8);
|
||||||
|
let mut fac = Gf256::one();
|
||||||
|
let mut acc = Gf256::zero();
|
||||||
|
for &coeff in src.iter() {
|
||||||
|
acc = acc + fac * Gf256::from_byte(coeff);
|
||||||
|
fac = fac * x;
|
||||||
|
}
|
||||||
|
try!(w.write(&[acc.to_byte()]));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// evaluates an interpolated polynomial at `raw_x` where
|
||||||
|
/// the polynomial is determined using Lagrangian interpolation
|
||||||
|
/// based on the given x/y coordinates `src`.
|
||||||
|
fn lagrange_interpolate(src: &[(u8, u8)], raw_x: u8) -> u8 {
|
||||||
|
let x = Gf256::from_byte(raw_x);
|
||||||
|
let mut sum = Gf256::zero();
|
||||||
|
for (i, &(raw_xi, raw_yi)) in src.iter().enumerate() {
|
||||||
|
let xi = Gf256::from_byte(raw_xi);
|
||||||
|
let yi = Gf256::from_byte(raw_yi);
|
||||||
|
let mut lix = Gf256::one();
|
||||||
|
for (j, &(raw_xj, _)) in src.iter().enumerate() {
|
||||||
|
if i != j {
|
||||||
|
let xj = Gf256::from_byte(raw_xj);
|
||||||
|
let delta = xi - xj;
|
||||||
|
assert!(delta.poly !=0, "Duplicate shares");
|
||||||
|
lix = lix * (x - xj) / delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum = sum + lix * yi;
|
||||||
|
}
|
||||||
|
sum.to_byte()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result<Vec<Vec<u8>>> {
|
||||||
|
let mut result = Vec::with_capacity(n as usize);
|
||||||
|
for _ in 0 .. (n as usize) {
|
||||||
|
result.push(new_vec(src.len(), 0u8));
|
||||||
|
}
|
||||||
|
let mut col_in = new_vec(k as usize, 0u8);
|
||||||
|
let mut col_out = Vec::with_capacity(n as usize);
|
||||||
|
let mut osrng = try!(OsRng::new());
|
||||||
|
for (c, &s) in src.iter().enumerate() {
|
||||||
|
col_in[0] = s;
|
||||||
|
osrng.fill_bytes(&mut col_in[1..]);
|
||||||
|
col_out.clear();
|
||||||
|
try!(encode(&*col_in, n, &mut col_out));
|
||||||
|
for (&y, share) in col_out.iter().zip(result.iter_mut()) {
|
||||||
|
share[c] = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform_encode(k: u8, n: u8, secret: Vec<u8>) -> io::Result<Vec<Vec<u8>>> {
|
||||||
|
let shares = try!(secret_share(&*secret, k, n));
|
||||||
|
let config = base64::Config {
|
||||||
|
pad: false,
|
||||||
|
..base64::STANDARD
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = Vec::with_capacity(n as usize);
|
||||||
|
|
||||||
|
for (index, share) in shares.iter().enumerate() {
|
||||||
|
let salad = share.to_base64(config);
|
||||||
|
let string = format!("{}-{}-{}", k, index+1, salad).into_bytes();
|
||||||
|
result.push(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform_decode(k: u8, shares: Vec<(u8,Vec<u8>)>) -> io::Result<Vec<u8>> {
|
||||||
|
assert!(!shares.is_empty());
|
||||||
|
let slen = shares[0].1.len();
|
||||||
|
let mut col_in = Vec::with_capacity(k as usize);
|
||||||
|
let mut secret = Vec::with_capacity(slen);
|
||||||
|
for byteindex in 0 .. slen {
|
||||||
|
col_in.clear();
|
||||||
|
for s in shares.iter().take(k as usize) {
|
||||||
|
col_in.push((s.0, s.1[byteindex]));
|
||||||
|
}
|
||||||
|
secret.push(lagrange_interpolate(&*col_in, 0u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(secret) as io::Result<Vec<u8>>;
|
||||||
|
}
|
317
src/main.rs
317
src/main.rs
@ -1,58 +1,19 @@
|
|||||||
extern crate rustc_serialize as serialize;
|
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate rand;
|
|
||||||
|
|
||||||
use std::convert;
|
use getopts::Options;
|
||||||
use std::env;
|
|
||||||
use std::error;
|
use std::str;
|
||||||
use std::fmt;
|
use lib::custom_error::*;
|
||||||
|
use lib::serialize::base64::{ FromBase64 };
|
||||||
|
mod lib;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::env;
|
||||||
use std::iter::repeat;
|
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
use rand::{ Rng, OsRng };
|
enum Action {
|
||||||
use getopts::Options;
|
Encode(u8, u8), // k and n parameter
|
||||||
use serialize::base64::{ self, FromBase64, ToBase64 };
|
Decode
|
||||||
|
|
||||||
use gf256::Gf256;
|
|
||||||
|
|
||||||
mod gf256;
|
|
||||||
|
|
||||||
fn new_vec<T: Clone>(n: usize, x: T) -> Vec<T> {
|
|
||||||
repeat(x).take(n).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Error {
|
|
||||||
descr: &'static str,
|
|
||||||
detail: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
|
||||||
fn new(descr: &'static str, detail: Option<String>) -> Error {
|
|
||||||
Error { descr: descr, detail: detail }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self.detail {
|
|
||||||
None => write!(f, "{}", self.descr),
|
|
||||||
Some(ref detail) => write!(f, "{} ({})", self.descr, detail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &str { self.descr }
|
|
||||||
fn cause(&self) -> Option<&error::Error> { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl convert::From<Error> for io::Error {
|
|
||||||
fn from(me: Error) -> io::Error {
|
|
||||||
io::Error::new(io::ErrorKind::Other, me)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// a try!-like macro for Option<T> expressions that takes
|
// a try!-like macro for Option<T> expressions that takes
|
||||||
@ -67,94 +28,71 @@ macro_rules! otry {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// maps a ParseIntError to an io::Error
|
fn main() {
|
||||||
fn pie2io(p: num::ParseIntError) -> io::Error {
|
let mut stderr = io::stderr();
|
||||||
convert::From::from(
|
let args: Vec<String> = env::args().collect();
|
||||||
Error::new("Integer parsing error", Some(p.to_string()))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn other_io_err(descr: &'static str, detail: Option<String>) -> io::Error {
|
let mut opts = Options::new();
|
||||||
convert::From::from(
|
opts.optflag("h", "help", "print this help text");
|
||||||
Error::new(descr, detail)
|
opts.optflag("d", "decode", "for decoding");
|
||||||
)
|
opts.optopt("e", "encode", "for encoding, K is the required number of \
|
||||||
}
|
shares for decoding, N is the number of shares \
|
||||||
|
to generate. 1 <= K <= N <= 255", "K,N");
|
||||||
/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive)
|
let opt_matches = match opts.parse(&args[1..]) {
|
||||||
fn encode<W: Write>(src: &[u8], n: u8, w: &mut W) -> io::Result<()> {
|
Ok(m) => m,
|
||||||
for raw_x in 1 .. ((n as u16) + 1) {
|
Err(f) => {
|
||||||
let x = Gf256::from_byte(raw_x as u8);
|
drop(writeln!(&mut stderr, "Error: {}", f));
|
||||||
let mut fac = Gf256::one();
|
// env::set_exit_status(1); // FIXME: unstable feature
|
||||||
let mut acc = Gf256::zero();
|
return;
|
||||||
for &coeff in src.iter() {
|
|
||||||
acc = acc + fac * Gf256::from_byte(coeff);
|
|
||||||
fac = fac * x;
|
|
||||||
}
|
}
|
||||||
try!(w.write(&[acc.to_byte()]));
|
};
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// evaluates an interpolated polynomial at `raw_x` where
|
if args.len() < 2 || opt_matches.opt_present("h") {
|
||||||
/// the polynomial is determined using Lagrangian interpolation
|
println!(
|
||||||
/// based on the given x/y coordinates `src`.
|
"The program secretshare is an implementation of Shamir's secret sharing scheme.\n\
|
||||||
fn lagrange_interpolate(src: &[(u8, u8)], raw_x: u8) -> u8 {
|
It is applied byte-wise within a finite field for arbitrarily long secrets.\n");
|
||||||
let x = Gf256::from_byte(raw_x);
|
println!("{}", opts.usage("Usage: rustysecrets [options]"));
|
||||||
let mut sum = Gf256::zero();
|
println!("Input is read from STDIN and output is written to STDOUT.");
|
||||||
for (i, &(raw_xi, raw_yi)) in src.iter().enumerate() {
|
return;
|
||||||
let xi = Gf256::from_byte(raw_xi);
|
}
|
||||||
let yi = Gf256::from_byte(raw_yi);
|
|
||||||
let mut lix = Gf256::one();
|
let action: Result<_,_> =
|
||||||
for (j, &(raw_xj, _)) in src.iter().enumerate() {
|
match (opt_matches.opt_present("e"), opt_matches.opt_present("d")) {
|
||||||
if i != j {
|
(false, false) => Err("Nothing to do! Use -e or -d"),
|
||||||
let xj = Gf256::from_byte(raw_xj);
|
(true, true) => Err("Use either -e or -d and not both"),
|
||||||
let delta = xi - xj;
|
(false, true) => Ok(Action::Decode),
|
||||||
assert!(delta.poly !=0, "Duplicate shares");
|
(true, false) => {
|
||||||
lix = lix * (x - xj) / delta;
|
if let Some(param) = opt_matches.opt_str("e") {
|
||||||
|
if let Ok((k,n)) = parse_k_n(&*param) {
|
||||||
|
if 0 < k && k <= n {
|
||||||
|
Ok(Action::Encode(k,n))
|
||||||
|
} else {
|
||||||
|
Err("Invalid encoding parameters K,N")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("Could not parse K,N parameters")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("No parameter for -e or -d provided")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
sum = sum + lix * yi;
|
|
||||||
|
let result =
|
||||||
|
match action {
|
||||||
|
Ok(Action::Encode(k,n)) => perform_encode_from_io(k, n),
|
||||||
|
Ok(Action::Decode) => perform_decode_from_io(),
|
||||||
|
Err(e) => Err(other_io_err(e, None))
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
drop(writeln!(&mut stderr, "{}", e));
|
||||||
|
// env::set_exit_status(1); // FIXME: unstable feature
|
||||||
}
|
}
|
||||||
sum.to_byte()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secret_share(src: &[u8], k: u8, n: u8) -> io::Result<Vec<Vec<u8>>> {
|
fn perform_encode_from_io(k: u8, n: u8) -> io::Result<()> {
|
||||||
let mut result = Vec::with_capacity(n as usize);
|
let secret = {
|
||||||
for _ in 0 .. (n as usize) {
|
|
||||||
result.push(new_vec(src.len(), 0u8));
|
|
||||||
}
|
|
||||||
let mut col_in = new_vec(k as usize, 0u8);
|
|
||||||
let mut col_out = Vec::with_capacity(n as usize);
|
|
||||||
let mut osrng = try!(OsRng::new());
|
|
||||||
for (c, &s) in src.iter().enumerate() {
|
|
||||||
col_in[0] = s;
|
|
||||||
osrng.fill_bytes(&mut col_in[1..]);
|
|
||||||
col_out.clear();
|
|
||||||
try!(encode(&*col_in, n, &mut col_out));
|
|
||||||
for (&y, share) in col_out.iter().zip(result.iter_mut()) {
|
|
||||||
share[c] = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Action {
|
|
||||||
Encode(u8, u8), // k and n parameter
|
|
||||||
Decode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_k_n(s: &str) -> io::Result<(u8, u8)> {
|
|
||||||
let mut iter = s.split(',');
|
|
||||||
let msg = "K and N have to be separated with a comma";
|
|
||||||
let s1 = otry!(iter.next(), msg).trim();
|
|
||||||
let s2 = otry!(iter.next(), msg).trim();
|
|
||||||
let k = try!(s1.parse().map_err(pie2io));
|
|
||||||
let n = try!(s2.parse().map_err(pie2io));
|
|
||||||
Ok((k, n))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn perform_encode(k: u8, n: u8) -> io::Result<()> {
|
|
||||||
let secret = {
|
|
||||||
let limit: usize = 0x10000;
|
let limit: usize = 0x10000;
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut locked = stdin.lock();
|
let mut locked = stdin.lock();
|
||||||
@ -169,16 +107,14 @@ fn perform_encode(k: u8, n: u8) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
tmp
|
tmp
|
||||||
};
|
};
|
||||||
let shares = try!(secret_share(&*secret, k, n));
|
match lib::perform_encode(k, n, secret) {
|
||||||
let config = base64::Config {
|
Ok(shares) => {
|
||||||
pad: false,
|
for share in shares {println!("{:?}", str::from_utf8(&share).unwrap())};
|
||||||
..base64::STANDARD
|
}
|
||||||
};
|
Err(e) => { return Err(e) as io::Result<()>; }
|
||||||
for (index, share) in shares.iter().enumerate() {
|
|
||||||
let salad = share.to_base64(config);
|
|
||||||
println!("{}-{}-{}", k, index+1, salad);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
return Ok(()) as io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// reads shares from stdin and returns Ok(k, shares) on success
|
/// reads shares from stdin and returns Ok(k, shares) on success
|
||||||
@ -195,7 +131,7 @@ fn read_shares() -> io::Result<(u8, Vec<(u8,Vec<u8>)>)> {
|
|||||||
let parts: Vec<_> = line.trim().split('-').collect();
|
let parts: Vec<_> = line.trim().split('-').collect();
|
||||||
if parts.len() < 3 || parts.len() > 4 {
|
if parts.len() < 3 || parts.len() > 4 {
|
||||||
return Err(other_io_err("Share parse error: Expected 3 or 4 \
|
return Err(other_io_err("Share parse error: Expected 3 or 4 \
|
||||||
parts searated by a minus sign", None));
|
parts separated by a minus sign", None));
|
||||||
}
|
}
|
||||||
let (k, n, p3) = {
|
let (k, n, p3) = {
|
||||||
let mut iter = parts.into_iter();
|
let mut iter = parts.into_iter();
|
||||||
@ -229,83 +165,32 @@ fn read_shares() -> io::Result<(u8, Vec<(u8,Vec<u8>)>)> {
|
|||||||
Err(other_io_err("Not enough shares provided!", None))
|
Err(other_io_err("Not enough shares provided!", None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_decode() -> io::Result<()> {
|
fn perform_decode_from_io() -> io::Result<()> {
|
||||||
let (k, shares) = try!(read_shares());
|
let (k, shares) = try!(read_shares());
|
||||||
assert!(!shares.is_empty());
|
|
||||||
let slen = shares[0].1.len();
|
|
||||||
let mut col_in = Vec::with_capacity(k as usize);
|
|
||||||
let mut secret = Vec::with_capacity(slen);
|
|
||||||
for byteindex in 0 .. slen {
|
|
||||||
col_in.clear();
|
|
||||||
for s in shares.iter().take(k as usize) {
|
|
||||||
col_in.push((s.0, s.1[byteindex]));
|
|
||||||
}
|
|
||||||
secret.push(lagrange_interpolate(&*col_in, 0u8));
|
|
||||||
}
|
|
||||||
let mut out = io::stdout();
|
|
||||||
try!(out.write_all(&*secret));
|
|
||||||
out.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
return match lib::perform_decode(k, shares) {
|
||||||
let mut stderr = io::stderr();
|
Ok(secret) => {
|
||||||
let args: Vec<String> = env::args().collect();
|
let mut out = io::stdout();
|
||||||
|
try!(out.write_all(&*secret));
|
||||||
let mut opts = Options::new();
|
out.flush()
|
||||||
opts.optflag("h", "help", "print this help text");
|
|
||||||
opts.optflag("d", "decode", "for decoding");
|
|
||||||
opts.optopt("e", "encode", "for encoding, K is the required number of \
|
|
||||||
shares for decoding, N is the number of shares \
|
|
||||||
to generate. 1 <= K <= N <= 255", "K,N");
|
|
||||||
let opt_matches = match opts.parse(&args[1..]) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => {
|
|
||||||
drop(writeln!(&mut stderr, "Error: {}", f));
|
|
||||||
// env::set_exit_status(1); // FIXME: unstable feature
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
Err(e) => {Err(e) as io::Result<()>}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
if args.len() < 2 || opt_matches.opt_present("h") {
|
|
||||||
println!(
|
fn parse_k_n(s: &str) -> io::Result<(u8, u8)> {
|
||||||
"The program secretshare is an implementation of Shamir's secret sharing scheme.\n\
|
let mut iter = s.split(',');
|
||||||
It is applied byte-wise within a finite field for arbitrarily long secrets.\n");
|
let msg = "K and N have to be separated with a comma";
|
||||||
println!("{}", opts.usage("Usage: secretshare [options]"));
|
let s1 = otry!(iter.next(), msg).trim();
|
||||||
println!("Input is read from STDIN and output is written to STDOUT.");
|
let s2 = otry!(iter.next(), msg).trim();
|
||||||
return;
|
let k = try!(s1.parse().map_err(pie2io));
|
||||||
}
|
let n = try!(s2.parse().map_err(pie2io));
|
||||||
|
Ok((k, n))
|
||||||
let action: Result<_,_> =
|
}
|
||||||
match (opt_matches.opt_present("e"), opt_matches.opt_present("d")) {
|
|
||||||
(false, false) => Err("Nothing to do! Use -e or -d"),
|
/// maps a ParseIntError to an io::Error
|
||||||
(true, true) => Err("Use either -e or -d and not both"),
|
fn pie2io(p: num::ParseIntError) -> io::Error {
|
||||||
(false, true) => Ok(Action::Decode),
|
convert::From::from(
|
||||||
(true, false) => {
|
Error::new("Integer parsing error", Some(p.to_string()))
|
||||||
if let Some(param) = opt_matches.opt_str("e") {
|
)
|
||||||
if let Ok((k,n)) = parse_k_n(&*param) {
|
|
||||||
if 0 < k && k <= n {
|
|
||||||
Ok(Action::Encode(k,n))
|
|
||||||
} else {
|
|
||||||
Err("Invalid encoding parameters K,N")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err("Could not parse K,N parameters")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err("No parameter for -e or -d provided")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let result =
|
|
||||||
match action {
|
|
||||||
Ok(Action::Encode(k,n)) => perform_encode(k, n),
|
|
||||||
Ok(Action::Decode) => perform_decode(),
|
|
||||||
Err(e) => Err(other_io_err(e, None))
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
|
||||||
drop(writeln!(&mut stderr, "{}", e));
|
|
||||||
// env::set_exit_status(1); // FIXME: unstable feature
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user