Initial commit
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
local
|
||||
.idea
|
||||
*.iml
|
||||
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "rssss"
|
||||
version = "0.1.0"
|
||||
authors = ["TQ Hirsch <thequux@thequux.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
num-bigint = {version = "0.2.2", features = ["rand", "serde"]}
|
||||
lazy_static = "1.2.0"
|
||||
structopt = "0.2.14"
|
||||
failure = "0.1.5"
|
||||
crc = "1.8.1"
|
||||
byteorder = "1.3.1"
|
||||
num-traits = "0.2.6"
|
||||
rand = "0.6.5"
|
||||
serde = "1.0.87"
|
||||
serde_derive = "1.0.87"
|
||||
serde_cbor = "0.9.0"
|
||||
8
src/lib.rs
Normal file
8
src/lib.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use num_bigint::BigUint;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod primes;
|
||||
pub mod poly;
|
||||
pub mod s4;
|
||||
|
||||
|
||||
187
src/main.rs
Normal file
187
src/main.rs
Normal file
@@ -0,0 +1,187 @@
|
||||
use structopt::StructOpt;
|
||||
use std::path::PathBuf;
|
||||
use failure::Error;
|
||||
use std::io;
|
||||
|
||||
|
||||
|
||||
/// Rust implementation of Shamir Secret Sharing
|
||||
///
|
||||
/// Securely divides a small amount of data into shares, some subset of which are required
|
||||
/// to reproduce the original data
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// Generating shares:
|
||||
///
|
||||
/// # Precompute data for secret sharing requiring 2 shares to reconsitute the data
|
||||
///
|
||||
/// rssss gen-poly 2 <secret >poly
|
||||
///
|
||||
/// # Generate a few shares
|
||||
///
|
||||
/// rssss gen-share <poly >share-1
|
||||
///
|
||||
/// rssss gen-share <poly >share-2
|
||||
///
|
||||
/// rssss gen-share <poly >share-3
|
||||
///
|
||||
/// rssss gen-share <poly >share-4
|
||||
///
|
||||
/// # Recover the poly from two of those shares
|
||||
///
|
||||
/// rssss solve share-2 share-4 >recovered-poly
|
||||
///
|
||||
/// # Generate some more shares from that poly
|
||||
///
|
||||
/// rssss gen-share <recovered-poly >share-5
|
||||
///
|
||||
/// # Get the secret back
|
||||
///
|
||||
/// rssss extract <recovered-poly >recovered-secret
|
||||
#[derive(StructOpt)]
|
||||
enum Cmdline {
|
||||
/// Generate a poly from a secret
|
||||
#[structopt(name = "gen-poly")]
|
||||
GenPoly(GenPoly),
|
||||
|
||||
/// Generate a share from a poly
|
||||
#[structopt(name = "gen-share")]
|
||||
GenShare(GenShare),
|
||||
|
||||
/// Solve a set of shares to get the poly back
|
||||
#[structopt(name = "solve")]
|
||||
Solve(Solve),
|
||||
|
||||
/// Combine a set of shares to get the secret back
|
||||
#[structopt(name = "combine")]
|
||||
Combine(Combine),
|
||||
|
||||
/// Extract a secret from a poly
|
||||
#[structopt(name="extract")]
|
||||
ExtractSecret(ExtractSecret),
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct GenPoly {
|
||||
#[structopt(short="p", long="prime", default_value="p384", parse(try_from_str))]
|
||||
prime: rssss::primes::Prime,
|
||||
|
||||
min_shares: u32,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct GenShare {
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Solve {
|
||||
#[structopt(short="p", long="prime", default_value="p384", parse(try_from_str))]
|
||||
prime: rssss::primes::Prime,
|
||||
#[structopt(parse(from_os_str))]
|
||||
data: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
/// Extract a secret
|
||||
#[derive(StructOpt)]
|
||||
struct ExtractSecret {
|
||||
#[structopt(short="p", long="prime", default_value="p384", parse(try_from_str))]
|
||||
prime: rssss::primes::Prime,
|
||||
}
|
||||
|
||||
/// Combine a set of shares to find the secret
|
||||
/// This is equivalent to solve followed by extract, but without the intermediate step
|
||||
#[derive(StructOpt)]
|
||||
struct Combine {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cmdline = Cmdline::from_args();
|
||||
let cmd: &Command = match cmdline {
|
||||
Cmdline::GenPoly(ref cmd) => cmd,
|
||||
Cmdline::GenShare(ref cmd) => cmd,
|
||||
Cmdline::Solve(ref cmd) => cmd,
|
||||
Cmdline::ExtractSecret(ref cmd) => cmd,
|
||||
Cmdline::Combine(ref cmd) => cmd,
|
||||
};
|
||||
|
||||
cmd.run();
|
||||
}
|
||||
|
||||
trait Command {
|
||||
fn run(&self) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl Command for GenPoly {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
use std::io::Read;
|
||||
use num_bigint::{RandBigInt, BigUint};
|
||||
|
||||
let mut rng = rand::rngs::JitterRng::new()?;
|
||||
|
||||
let mut payload = vec![];
|
||||
io::stdin().read_to_end(&mut payload)?;
|
||||
|
||||
let secret = rssss::s4::Secret::new(payload);
|
||||
let mut poly = rssss::poly::Poly::zero(self.prime);
|
||||
for i in 1..self.min_shares {
|
||||
poly += rng.gen_biguint_below(self.prime.modulus());
|
||||
poly.mul_x();
|
||||
}
|
||||
poly += &BigUint::from(secret);
|
||||
|
||||
// export the poly
|
||||
serde_cbor::to_writer(&mut io::stdout(), &poly)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for GenShare {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
let mut poly: rssss::poly::Poly = serde_cbor::from_reader(io::stdin())?;
|
||||
let mut rng = rand::rngs::JitterRng::new()?;
|
||||
|
||||
let share = rssss::s4::Share::new(&mut rng, &poly);
|
||||
share.write_to(io::stdout())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Solve {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
use std::fs::File;
|
||||
let shares = self.data.iter().map(|filename| {
|
||||
Ok(File::open(&filename)
|
||||
.and_then(|f| rssss::s4::Share::read_from(f, self.prime))
|
||||
.map_err(|err| Error::from(err)
|
||||
.context(format!("Failed to read {:?}", filename)))?)
|
||||
}).collect::<Result<Vec<rssss::s4::Share>, Error>>();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for ExtractSecret {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
use num_bigint::BigUint;
|
||||
use num_traits::Zero;
|
||||
use std::io::Write;
|
||||
let mut poly: rssss::poly::Poly = serde_cbor::from_reader(io::stdin())?;
|
||||
let secret = rssss::s4::Secret::from(poly.eval_at(&BigUint::zero()));
|
||||
io::stdout().write_all(&secret[..])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Combine {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// Impl
|
||||
|
||||
|
||||
|
||||
|
||||
182
src/poly.rs
Normal file
182
src/poly.rs
Normal file
@@ -0,0 +1,182 @@
|
||||
use std::io::{self, prelude::*};
|
||||
use std::ops::{Mul, Div, Add, AddAssign, DivAssign, Neg};
|
||||
|
||||
use num_bigint::BigUint;
|
||||
use num_traits::{Zero, One};
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
use crate::primes::Prime;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Poly {
|
||||
// coeff[0] + coeff[1]*x + coeff[2] * x^2
|
||||
// i.e., $$\sum_i coeff_i x^i$$
|
||||
pub prime: Prime,
|
||||
coeff: Vec<BigUint>,
|
||||
}
|
||||
|
||||
impl Poly {
|
||||
pub fn zero(modulus: Prime) -> Self {
|
||||
Poly {
|
||||
prime: modulus,
|
||||
coeff: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn x(modulus: Prime) -> Self {
|
||||
Poly {
|
||||
prime: modulus,
|
||||
coeff: vec![BigUint::zero(), BigUint::one()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_x(&mut self) {
|
||||
self.coeff.insert(0, BigUint::zero());
|
||||
|
||||
}
|
||||
|
||||
pub fn eval_at(&self, point: &BigUint) -> BigUint {
|
||||
let mut result: BigUint = BigUint::zero();
|
||||
for item in self.coeff.iter().rev() {
|
||||
result *= point;
|
||||
result += item;
|
||||
result %= self.prime.modulus();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Poly> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn add(self, rhs: &Poly) -> Self::Output {
|
||||
let mut res = self.clone();
|
||||
res += rhs;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<&Poly> for Poly {
|
||||
fn add_assign(&mut self, rhs: &Poly) {
|
||||
assert_eq!(self.prime, rhs.prime);
|
||||
if self.coeff.len() < rhs.coeff.len() {
|
||||
self.coeff.extend(::std::iter::repeat(BigUint::zero()).take(rhs.coeff.len() - self.coeff.len()));
|
||||
}
|
||||
for (a, b) in self.coeff.iter_mut().zip(rhs.coeff.iter()) {
|
||||
*a += b;
|
||||
*a %= self.prime.modulus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn add(mut self, rhs: &BigUint) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<&BigUint> for Poly {
|
||||
fn add_assign(&mut self, rhs: &BigUint) {
|
||||
if self.coeff.len() == 0 {
|
||||
self.coeff.push(rhs % self.prime.modulus())
|
||||
} else {
|
||||
self.coeff[0] += rhs;
|
||||
self.coeff[0] %= self.prime.modulus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn add(mut self, rhs: BigUint) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<BigUint> for Poly {
|
||||
fn add_assign(&mut self, rhs: BigUint) {
|
||||
if self.coeff.len() == 0 {
|
||||
self.coeff.push(rhs % self.prime.modulus())
|
||||
} else {
|
||||
self.coeff[0] += rhs;
|
||||
self.coeff[0] %= self.prime.modulus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<&BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
fn mul(mut self, rhs: &BigUint) -> Poly {
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a *= rhs;
|
||||
*a %= self.prime.modulus();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<&BigUint> for &Poly {
|
||||
type Output = Poly;
|
||||
fn mul(mut self, rhs: &BigUint) -> Poly {
|
||||
Poly {
|
||||
prime: self.prime,
|
||||
coeff: self.coeff.iter().map(|a| (a * rhs) % self.prime.modulus()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<&Poly> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn mul(mut self, rhs: &Poly) -> Self::Output {
|
||||
let mut result = Poly::zero(self.prime);
|
||||
for factor in rhs.coeff.iter() {
|
||||
result += &(&self * factor);
|
||||
self.mul_x();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<&Poly> for &Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn mul(self, rhs: &Poly) -> Self::Output {
|
||||
self.clone() * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn div(mut self, rhs: BigUint) -> Poly {
|
||||
self /= rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<BigUint> for Poly {
|
||||
fn div_assign(&mut self, rhs: BigUint) {
|
||||
let inv = self.prime.inverse(rhs);
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a *= &inv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn neg(mut self) -> Self::Output {
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a = self.prime.negate(&*a);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
116
src/primes.rs
Normal file
116
src/primes.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use num_bigint::BigUint;
|
||||
use lazy_static::lazy_static;
|
||||
use num_traits::identities::{Zero, One};
|
||||
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
lazy_static!{
|
||||
// 2^384 - 2^128 - 2^96 + 2^32 - 1
|
||||
// Chosen to be large enough to hold any AES key
|
||||
static ref PRIME_P384: BigUint = BigUint::new(vec![
|
||||
0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFE,
|
||||
0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
]);
|
||||
|
||||
static ref PRIME_P448: BigUint = BigUint::new(vec![
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE,
|
||||
0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||
0xFFFFFFFE, 0xFFFFFFFF,
|
||||
]);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Prime {
|
||||
// 2^384 - 2^128 - 2^96 + 2^32 - 1
|
||||
P384,
|
||||
// 2^448 - 2^224 - 1
|
||||
P448,
|
||||
}
|
||||
|
||||
impl Prime {
|
||||
pub fn to_id(self) -> u8 {
|
||||
match self {
|
||||
Prime::P384 => 1,
|
||||
Prime::P448 => 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn byte_size(self) -> usize {
|
||||
match self {
|
||||
Prime::P448 => 56,
|
||||
Prime::P384 => 48,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulus(self) -> &'static BigUint {
|
||||
match self {
|
||||
Prime::P384 => &PRIME_P384,
|
||||
Prime::P448 => &PRIME_P448,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inverse(self, value: BigUint) -> BigUint {
|
||||
ext_gcd(value, self.modulus().clone()).0
|
||||
}
|
||||
|
||||
pub fn negate(self, value: &BigUint) -> BigUint {
|
||||
self.modulus() - value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl FromStr for Prime {
|
||||
type Err = failure::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"p384" => Ok(Prime::P384),
|
||||
"p448" => Ok(Prime::P448),
|
||||
_ => Err(failure::err_msg("Invalid prime spec; expected P384 or P448")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ext_gcd(mut a: BigUint, mut b: BigUint) -> (BigUint, BigUint) {
|
||||
use std::mem::swap;
|
||||
let mut x = BigUint::zero();
|
||||
let mut last_x = BigUint::one();
|
||||
let mut y = BigUint::one();
|
||||
let mut last_y = BigUint::zero();
|
||||
|
||||
while !b.is_zero() {
|
||||
let quot = &a / &b;
|
||||
swap(&mut a, &mut b);
|
||||
b %= &a;
|
||||
swap(&mut x, &mut last_x);
|
||||
swap(&mut y, &mut last_y);
|
||||
|
||||
|
||||
last_x *= "
|
||||
x -= &last_x;
|
||||
|
||||
last_y *= quot;
|
||||
y -= &last_y;
|
||||
}
|
||||
(last_x, last_y)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use num_bigint::BigUint;
|
||||
use super::Prime;
|
||||
|
||||
#[test]
|
||||
fn check_value_of_p384() {
|
||||
let one = &BigUint::new(vec![1]);
|
||||
assert_eq!(Prime::P384::modulus, one << 384 - one - one << 128 - one << 96 - one << 32);
|
||||
}
|
||||
fn check_value_of_p448() {
|
||||
let one = &BigUint::new(vec![1]);
|
||||
assert_eq!(Prime::P448::modulus, one << 448 - one - one << 224);
|
||||
}
|
||||
}
|
||||
138
src/s4.rs
Normal file
138
src/s4.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use std::io::{self, prelude::*};
|
||||
use std::ops::Deref;
|
||||
|
||||
|
||||
use num_bigint::BigUint;
|
||||
use serde::Serialize;
|
||||
|
||||
/// Structure
|
||||
/// | off | len | meaning |
|
||||
/// | 0 | 1 | Length of payload (L)
|
||||
/// | 1 | L | Payload
|
||||
/// | L+1 | 4 | CRC32c
|
||||
/// Note that these bytes are interpreted in big-endian form to get a field element;
|
||||
/// this way, the high bit is always unset
|
||||
#[derive(Default,Clone, Debug)]
|
||||
pub struct Secret {
|
||||
length: u8,
|
||||
data: Vec<u8>,
|
||||
crc32: u32,
|
||||
|
||||
}
|
||||
|
||||
impl Secret {
|
||||
pub fn new(data: Vec<u8>) -> Self {
|
||||
if data.len() == 0 {
|
||||
panic!("Must have at least one byte of payload");
|
||||
} else if data.len() > 127 {
|
||||
panic!("Too much data");
|
||||
}
|
||||
|
||||
let mut res = Secret {
|
||||
length: data.len() as u8,
|
||||
data,
|
||||
crc32: 0,
|
||||
};
|
||||
res.crc32 = res.compute_crc();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn compute_crc(&self) -> u32 {
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use crc::crc32::{CASTAGNOLI, Digest, Hasher32};
|
||||
let mut hasher = Digest::new(CASTAGNOLI);
|
||||
hasher.reset();
|
||||
hasher.write(&[self.length]);
|
||||
hasher.write(&self.data[..]);
|
||||
hasher.write(&[0, 0, 0, 0]);
|
||||
hasher.sum32()
|
||||
}
|
||||
|
||||
pub fn check_crc(&self) -> bool {
|
||||
let crc = self.compute_crc();
|
||||
crc == self.crc32
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Secret {
|
||||
type Target = Vec<u8>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BigUint> for Secret {
|
||||
fn from(ui: BigUint) -> Self {
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
let decoded = ui.to_bytes_be();
|
||||
let mut res = Secret::default();
|
||||
res.length = decoded[0];
|
||||
let len = res.length as usize;
|
||||
res.data = decoded[1..len+1].to_owned();
|
||||
res.crc32 = BigEndian::read_u32(&decoded[len+1..len+5]);
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Secret> for BigUint {
|
||||
fn from(obj: Secret) -> BigUint {
|
||||
use std::io::Write;
|
||||
use byteorder::{WriteBytesExt, BigEndian};
|
||||
let mut buf = vec![];
|
||||
buf.write(&[obj.length]);
|
||||
buf.write(&obj.data[..]);
|
||||
buf.write_u32::<BigEndian>(obj.crc32);
|
||||
BigUint::from_bytes_be(&buf[..])
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
pub struct Share {
|
||||
pub prime: crate::primes::Prime,
|
||||
pub x: BigUint,
|
||||
pub y: BigUint,
|
||||
}
|
||||
|
||||
impl Share {
|
||||
pub fn new<Rng: num_bigint::RandBigInt + ?Sized>(rnd: &mut Rng, poly: &crate::poly::Poly) -> Self {
|
||||
use num_bigint::RandBigInt;
|
||||
let x = rnd.gen_biguint_below(poly.prime.modulus());
|
||||
let y = poly.eval_at(&x);
|
||||
Share {
|
||||
prime: poly.prime,
|
||||
x, y,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_to<W: Write>(&self, mut w: W) -> io::Result<()> {
|
||||
let mut x = self.x.to_bytes_le();
|
||||
x.resize(self.prime.byte_size(), 0);
|
||||
let mut y = self.y.to_bytes_le();
|
||||
y.resize(self.prime.byte_size(), 0);
|
||||
|
||||
(&mut w).write_all(&x[..])?;
|
||||
(&mut w).write_all(&y[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_from<R: Read>(mut r: R, prime: crate::primes::Prime) -> io::Result<Self> {
|
||||
let size = prime.byte_size();
|
||||
let mut x = vec![0; size];
|
||||
(&mut r).read_exact(&mut x[..])?;
|
||||
let mut x = BigUint::from_bytes_le(&x[..]);
|
||||
|
||||
let mut y = vec![0; size];
|
||||
(&mut r).read_exact(&mut y[..])?;
|
||||
let mut y = BigUint::from_bytes_le(&y[..]);
|
||||
|
||||
if &x >= prime.modulus() || &y >= prime.modulus() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid point: out of range"));
|
||||
}
|
||||
|
||||
Ok(Share{ prime, x, y })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user