Added wasm bindings, modified format to have version in share rather than secret and remove some baggage from the encoded share. This is an incompatible change
This commit is contained in:
31
Cargo.toml
31
Cargo.toml
@@ -1,25 +1,6 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "rssss"
|
resolver = "2"
|
||||||
version = "0.1.0"
|
members=[
|
||||||
authors = ["TQ Hirsch <thequux@thequux.com>"]
|
"rssss",
|
||||||
edition = "2021"
|
"rssss-wasm",
|
||||||
|
]
|
||||||
[dependencies]
|
|
||||||
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"
|
|
||||||
serde_json = "1.0.111"
|
|
||||||
bendy = "0.3.3"
|
|
||||||
generic-array = "1.0.0"
|
|
||||||
anyhow = "1.0.79"
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
rand = "0.6.5"
|
|
||||||
generic-array = "1.0.0"
|
|
||||||
|
|||||||
15
rssss-wasm/Cargo.toml
Normal file
15
rssss-wasm/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "rssss-wasm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type=["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wasm-bindgen = "0.2.92"
|
||||||
|
rssss = {path = "../rssss"}
|
||||||
|
rand = { version = "0.8.5", default-features = false, features = ["getrandom"] }
|
||||||
|
getrandom = { version = "0.2.15", default-features = false, features = ["js"] }
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
thiserror = "1.0.61"
|
||||||
91
rssss-wasm/src/lib.rs
Normal file
91
rssss-wasm/src/lib.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use rssss::poly::{Poly, UniformPoly};
|
||||||
|
use rssss::gf256::GF256;
|
||||||
|
use rssss::s4;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct ShareGenerator {
|
||||||
|
poly: Vec<Poly<GF256>>,
|
||||||
|
last_share: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share format: [0, min_shares, *data]
|
||||||
|
impl ShareGenerator {
|
||||||
|
pub fn new_from_vec(min_shares: u8, secret: Vec<u8>) -> Self {
|
||||||
|
let mut secret_buf = Vec::with_capacity(secret.len() + 5);
|
||||||
|
let secret = s4::Secret::new(secret);
|
||||||
|
secret.to_buf(&mut secret_buf);
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
|
let mut poly = Vec::with_capacity(secret.len());
|
||||||
|
for c in secret_buf.iter().copied() {
|
||||||
|
poly.push(rng.sample(UniformPoly { intercept: GF256::from(c), degree: min_shares as usize - 1 }))
|
||||||
|
}
|
||||||
|
|
||||||
|
Self{
|
||||||
|
poly,
|
||||||
|
last_share: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl ShareGenerator {
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new_from_buf(min_shares: u8, secret: &[u8]) -> Self {
|
||||||
|
Self::new_from_vec(min_shares, Vec::from(secret))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_string(min_shares: u8, secret: String) -> Self {
|
||||||
|
Self::new_from_vec(min_shares, secret.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_share(&mut self, n: Option<u8>) -> Option<Share> {
|
||||||
|
let n = if let Some(n) = n {
|
||||||
|
if self.last_share < n {
|
||||||
|
self.last_share = n;
|
||||||
|
}
|
||||||
|
n
|
||||||
|
} else {
|
||||||
|
self.last_share += 1;
|
||||||
|
self.last_share
|
||||||
|
};
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let share = s4::Share::new(GF256::from(n), self.poly.as_slice());
|
||||||
|
|
||||||
|
Some(Share(share))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Share(s4::Share<GF256>);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Share {
|
||||||
|
pub fn to_blob(&self) -> Box<[u8]> {
|
||||||
|
let mut ret = Vec::with_capacity(self.0.y.len() + 1);
|
||||||
|
self.0.write_to(&mut ret).unwrap();
|
||||||
|
ret.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_blob(blob: &[u8]) -> Result<Share, String> {
|
||||||
|
|
||||||
|
s4::Share::<GF256>::read_from(blob)
|
||||||
|
.map(Share)
|
||||||
|
.map_err(|err| format!("{}", err))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(getter)]
|
||||||
|
pub fn x(&self) -> usize {
|
||||||
|
usize::from(self.0.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
26
rssss/Cargo.toml
Normal file
26
rssss/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[package]
|
||||||
|
name = "rssss"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["TQ Hirsch <thequux@thequux.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy_static = "1.2.0"
|
||||||
|
structopt = "0.2.14"
|
||||||
|
failure = "0.1.5"
|
||||||
|
crc = "3.2.1"
|
||||||
|
byteorder = "1.3.1"
|
||||||
|
num-traits = "0.2.6"
|
||||||
|
rand = "0.8.5"
|
||||||
|
serde = "1.0.87"
|
||||||
|
serde_derive = "1.0.87"
|
||||||
|
serde_cbor = "0.11.2"
|
||||||
|
serde_json = "1.0.111"
|
||||||
|
bendy = "0.3.3"
|
||||||
|
generic-array = "1.0.0"
|
||||||
|
anyhow = "1.0.79"
|
||||||
|
thiserror = "1.0.61"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
generic-array = "1.0.0"
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#![allow(unused)]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::gf256::GF256;
|
use crate::gf256::GF256;
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::ops::{Add, Mul, Sub};
|
use std::ops::{Add, Mul, Sub};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{Rng, RngCore};
|
use rand::Rng;
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
|
|
||||||
pub trait GF: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Copy + Clone + Eq + TryFrom<usize> {
|
pub trait GF: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Copy + Clone + Eq + TryFrom<usize> + Into<usize> {
|
||||||
const ORDER: usize;
|
const ORDER: usize;
|
||||||
type ChunkSize: ArrayLength;
|
type ChunkSize: ArrayLength;
|
||||||
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
|
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul};
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use generic_array::typenum::U1;
|
use generic_array::typenum::U1;
|
||||||
use rand::distributions::Standard;
|
use rand::distributions::Standard;
|
||||||
use rand::prelude::Distribution;
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
#[cfg(rssss_have_codegen)]
|
#[cfg(rssss_have_codegen)]
|
||||||
@@ -32,6 +31,8 @@ impl GF256 {
|
|||||||
GF256(poly << 1 ^ (0x1B & mask))
|
GF256(poly << 1 ^ (0x1B & mask))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This exists for the benefit of the table generator
|
||||||
|
#[allow(unused)]
|
||||||
pub(crate) fn minv_slow(self) -> Self {
|
pub(crate) fn minv_slow(self) -> Self {
|
||||||
let mut res = self;
|
let mut res = self;
|
||||||
let mut factor = 1;
|
let mut factor = 1;
|
||||||
@@ -163,6 +164,11 @@ impl TryFrom<usize> for GF256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<GF256> for usize {
|
||||||
|
fn from(value: GF256) -> Self {
|
||||||
|
value.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
/// Unsigned negate
|
/// Unsigned negate
|
||||||
@@ -133,7 +133,7 @@ impl Command for GenPoly {
|
|||||||
fn run(&self) -> Result<(), Error> {
|
fn run(&self) -> Result<(), Error> {
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
let mut rng = rand::rngs::JitterRng::new()?;
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
let mut payload = vec![];
|
let mut payload = vec![];
|
||||||
io::stdin().read_to_end(&mut payload)?;
|
io::stdin().read_to_end(&mut payload)?;
|
||||||
@@ -160,9 +160,8 @@ impl Command for GenPoly {
|
|||||||
impl Command for GenShare {
|
impl Command for GenShare {
|
||||||
fn run(&self) -> Result<(), Error> {
|
fn run(&self) -> Result<(), Error> {
|
||||||
eprintln!("Reading poly");
|
eprintln!("Reading poly");
|
||||||
let mut poly: Vec<rssss::poly::Poly<GF256>> = serde_cbor::from_reader(io::stdin())?;
|
let poly: Vec<rssss::poly::Poly<GF256>> = serde_cbor::from_reader(io::stdin())?;
|
||||||
eprintln!("Read poly");
|
eprintln!("Read poly");
|
||||||
let mut rng = rand::rngs::OsRng::new()?;
|
|
||||||
|
|
||||||
let share = rssss::s4::Share::new((self.share_no as u8).into(), poly.as_slice());
|
let share = rssss::s4::Share::new((self.share_no as u8).into(), poly.as_slice());
|
||||||
// eprintln!("{share:?}");
|
// eprintln!("{share:?}");
|
||||||
@@ -190,7 +189,7 @@ impl Command for Solve {
|
|||||||
impl Command for ExtractSecret {
|
impl Command for ExtractSecret {
|
||||||
fn run(&self) -> Result<(), Error> {
|
fn run(&self) -> Result<(), Error> {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let mut poly: Vec<rssss::poly::Poly<GF256>> = serde_cbor::from_reader(io::stdin())?;
|
let poly: Vec<rssss::poly::Poly<GF256>> = serde_cbor::from_reader(io::stdin())?;
|
||||||
let interpolated = poly.into_iter().map(|p| p.eval_at(GF256::ZERO))
|
let interpolated = poly.into_iter().map(|p| p.eval_at(GF256::ZERO))
|
||||||
.flat_map(|f| f.encode())
|
.flat_map(|f| f.encode())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@@ -210,7 +209,7 @@ impl Command for Combine {
|
|||||||
.map_err(|err| Error::from(err)
|
.map_err(|err| Error::from(err)
|
||||||
.context(format!("Failed to read {:?}", filename)))?)
|
.context(format!("Failed to read {:?}", filename)))?)
|
||||||
}).collect::<Result<Vec<rssss::s4::Share<GF256>>, Error>>()?;
|
}).collect::<Result<Vec<rssss::s4::Share<GF256>>, Error>>()?;
|
||||||
let mut interpolated = rssss::s4::interpolate0(&shares[..]);
|
let interpolated = rssss::s4::interpolate0(&shares[..]);
|
||||||
let mut secret = Vec::with_capacity(interpolated.len() * <GF256 as GF>::ChunkSize::to_usize());
|
let mut secret = Vec::with_capacity(interpolated.len() * <GF256 as GF>::ChunkSize::to_usize());
|
||||||
for chunk in interpolated {
|
for chunk in interpolated {
|
||||||
secret.extend_from_slice(&chunk.encode()[..])
|
secret.extend_from_slice(&chunk.encode()[..])
|
||||||
@@ -1,20 +1,15 @@
|
|||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::io::{self, prelude::*};
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Mul, Div, Add, AddAssign, DivAssign, Neg, Sub};
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, Neg, Sub};
|
||||||
|
|
||||||
use num_traits::{Zero, One};
|
|
||||||
use rand::distributions::Standard;
|
|
||||||
use rand::prelude::Distribution;
|
use rand::prelude::Distribution;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde::de::{SeqAccess, Visitor};
|
use serde::de::{SeqAccess, Visitor};
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
use serde_derive::{Serialize, Deserialize};
|
|
||||||
use crate::gf::GF;
|
use crate::gf::GF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Poly<F: GF> {
|
pub struct Poly<F: GF> {
|
||||||
// coeff[0] + coeff[1]*x + coeff[2] * x^2
|
// coeff[0] + coeff[1]*x + coeff[2] * x^2
|
||||||
@@ -57,6 +52,10 @@ impl<F: GF> Poly<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn degree(&self) -> usize {
|
||||||
|
self.coeff.len().max(1) - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: GF> Add<&Poly<F>> for Poly<F> {
|
impl<F: GF> Add<&Poly<F>> for Poly<F> {
|
||||||
@@ -111,7 +110,7 @@ impl<F: GF> AddAssign<F> for Poly<F> {
|
|||||||
impl <F: GF> Sub<F> for Poly<F> {
|
impl <F: GF> Sub<F> for Poly<F> {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn sub(mut self, rhs: F) -> Self::Output {
|
fn sub(self, rhs: F) -> Self::Output {
|
||||||
self + rhs
|
self + rhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +168,7 @@ impl<F: GF> DivAssign<F> for Poly<F> {
|
|||||||
impl<F: GF> Neg for Poly<F> {
|
impl<F: GF> Neg for Poly<F> {
|
||||||
type Output = Poly<F>;
|
type Output = Poly<F>;
|
||||||
|
|
||||||
fn neg(mut self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
// Elements in GF(2^n) are their own negative
|
// Elements in GF(2^n) are their own negative
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
use std::io::{self, prelude::*};
|
use std::io::{self, prelude::*};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BE, LE, ReadBytesExt, WriteBytesExt};
|
||||||
use crc::Hasher32;
|
use crc::Crc;
|
||||||
use failure::err_msg;
|
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use crate::gf256::GF256;
|
use generic_array::typenum::Unsigned;
|
||||||
|
|
||||||
use crate::gf::GF;
|
use crate::gf::GF;
|
||||||
|
|
||||||
use crate::poly::Poly;
|
use crate::poly::Poly;
|
||||||
|
|
||||||
|
|
||||||
/// Structure
|
/// Structure
|
||||||
/// | off | len | meaning |
|
/// | off | len | meaning |
|
||||||
/// | 0 | 1 | Length of payload (L)
|
/// | 0 | L | Payload
|
||||||
/// | 1 | L | Payload
|
/// | L | 4 | CRC32c
|
||||||
/// | L+1 | 4 | CRC32c
|
|
||||||
/// Note that these bytes are interpreted in big-endian form to get a field element;
|
/// Note that these bytes are interpreted in big-endian form to get a field element;
|
||||||
/// this way, the high bit is always unset
|
/// this way, the high bit is always unset
|
||||||
#[derive(Default,Clone, Debug)]
|
#[derive(Default,Clone, Debug)]
|
||||||
@@ -25,35 +21,6 @@ pub struct Secret {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_varint(mut v: u32, w: &mut Vec<u8>) {
|
|
||||||
while v > 127 {
|
|
||||||
w.push((v & 0x7F) as u8 | 0x80);
|
|
||||||
v >>= 7;
|
|
||||||
}
|
|
||||||
w.push(v as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_varint(buf: &mut &[u8]) -> Option<u32> {
|
|
||||||
let mut res = 0;
|
|
||||||
let mut scale = 0;
|
|
||||||
while buf.len() > 0 && (buf[0] & 0x80 != 0) {
|
|
||||||
let hd = buf[0];
|
|
||||||
eprintln!("Got head byte {hd:02x}");
|
|
||||||
res += (hd as u32 & 0x7F).checked_shl(scale)?;
|
|
||||||
*buf = &buf[1..];
|
|
||||||
scale += 7;
|
|
||||||
}
|
|
||||||
if buf.len() > 0 {
|
|
||||||
let hd = buf[0];
|
|
||||||
eprintln!("Got head byte {hd:02x}");
|
|
||||||
res += (hd as u32 & 0x7F).checked_shl(scale)?;
|
|
||||||
*buf = &buf[1..];
|
|
||||||
Some(res)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secret {
|
impl Secret {
|
||||||
pub fn new(data: Vec<u8>) -> Self {
|
pub fn new(data: Vec<u8>) -> Self {
|
||||||
if data.len() == 0 {
|
if data.len() == 0 {
|
||||||
@@ -70,15 +37,12 @@ impl Secret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_crc(&self) -> u32 {
|
fn compute_crc(&self) -> u32 {
|
||||||
use crc::crc32::{CASTAGNOLI, Digest, Hasher32};
|
use crc::CRC_32_ISCSI;
|
||||||
let mut hasher = Digest::new(CASTAGNOLI);
|
let crc = Crc::<u32>::new(&CRC_32_ISCSI);
|
||||||
let mut size_vi = Vec::with_capacity(5);
|
let mut hasher = crc.digest();
|
||||||
hasher.reset();
|
hasher.update(&self.data[..]);
|
||||||
hasher.write(&[2]);
|
hasher.update(&[0, 0, 0, 0]);
|
||||||
write_varint(self.data.len() as u32, &mut size_vi);
|
hasher.finalize()
|
||||||
hasher.write(&self.data[..]);
|
|
||||||
hasher.write(&[0, 0, 0, 0]);
|
|
||||||
hasher.sum32()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crc(&self) -> bool {
|
pub fn check_crc(&self) -> bool {
|
||||||
@@ -86,20 +50,14 @@ impl Secret {
|
|||||||
crc == self.crc32
|
crc == self.crc32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_buf(mut buf: &[u8]) -> Result<Self, failure::Error> {
|
pub fn from_buf(buf: &[u8]) -> Result<Self, failure::Error> {
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
if buf[0] != 2 {
|
|
||||||
return Err(err_msg("Invalid version")) // Invalid version
|
if buf.len() < 4 {
|
||||||
|
return Err(err_msg("Message too short"))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = &buf[1..];
|
let (content, mut buf) = buf.split_at(buf.len() - 4);
|
||||||
let size = read_varint(&mut buf)
|
|
||||||
.ok_or(err_msg("Invalid length"))?
|
|
||||||
as usize; // Invalid size
|
|
||||||
if size + 4 > buf.len() {
|
|
||||||
return Err(err_msg("Unexpected EOF")) // Unexpected EOF
|
|
||||||
}
|
|
||||||
let (content, mut buf) = buf.split_at(size);
|
|
||||||
let data = content.into();
|
let data = content.into();
|
||||||
let crc32 = buf.read_u32::<BE>().unwrap();
|
let crc32 = buf.read_u32::<BE>().unwrap();
|
||||||
|
|
||||||
@@ -112,8 +70,7 @@ impl Secret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_buf(&self, buf: &mut Vec<u8>) {
|
pub fn to_buf(&self, buf: &mut Vec<u8>) {
|
||||||
buf.push(2); // version
|
buf.reserve(self.data.len() + 4);
|
||||||
write_varint(self.data.len() as u32, &mut *buf);
|
|
||||||
buf.extend_from_slice(self.data.as_slice());
|
buf.extend_from_slice(self.data.as_slice());
|
||||||
buf.write_u32::<BE>(self.crc32).unwrap();
|
buf.write_u32::<BE>(self.crc32).unwrap();
|
||||||
}
|
}
|
||||||
@@ -131,20 +88,46 @@ impl Deref for Secret {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Share<Field: GF> {
|
pub struct Share<Field: GF> {
|
||||||
|
pub n_required: usize,
|
||||||
pub x: Field,
|
pub x: Field,
|
||||||
pub y: Vec<Field>,
|
pub y: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl <Field: GF> AsRef<Share<Field>> for Share<Field> {
|
||||||
|
fn as_ref(&self) -> &Share<Field> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<F: GF> Share<F> {
|
impl<F: GF> Share<F> {
|
||||||
pub fn new(share_no: F, poly: &[Poly<F>]) -> Self {
|
pub fn new(share_no: F, poly: &[Poly<F>]) -> Self {
|
||||||
|
let n_required = poly.iter().map(Poly::degree).max().unwrap_or(0);
|
||||||
let x= share_no;
|
let x= share_no;
|
||||||
let y = poly.iter().map(|word| word.eval_at(x)).collect();
|
let y = poly.iter().map(|word| word.eval_at(x)).collect();
|
||||||
Share {
|
Share {
|
||||||
x, y,
|
n_required,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Share format: [version, *n_req, *x, data...]
|
||||||
|
// n_req is little-endian, same size as field element
|
||||||
|
// Note: v0 is GF(2^8), v1 (unimplemented) is GF(2^16)
|
||||||
|
|
||||||
|
pub fn encoded_length(&self) -> usize {
|
||||||
|
(self.y.len() + 2) * F::ChunkSize::to_usize() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_buf(&self) -> Vec<u8> {
|
||||||
|
let mut ret = Vec::with_capacity(self.encoded_length());
|
||||||
|
self.write_to(&mut ret).unwrap();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_to<W: Write>(&self, mut w: W) -> io::Result<()> {
|
pub fn write_to<W: Write>(&self, mut w: W) -> io::Result<()> {
|
||||||
|
w.write_u8(0)?;
|
||||||
|
w.write_uint::<LE>(self.n_required as u64, F::ChunkSize::to_usize())?;
|
||||||
w.write_all(&self.x.encode()[..])?;
|
w.write_all(&self.x.encode()[..])?;
|
||||||
for y in self.y.iter().copied() {
|
for y in self.y.iter().copied() {
|
||||||
w.write_all(&y.encode()[..])?;
|
w.write_all(&y.encode()[..])?;
|
||||||
@@ -154,6 +137,13 @@ impl<F: GF> Share<F> {
|
|||||||
|
|
||||||
pub fn read_from<R: Read>(mut r: R) -> io::Result<Self> {
|
pub fn read_from<R: Read>(mut r: R) -> io::Result<Self> {
|
||||||
let mut buf = GenericArray::<u8, F::ChunkSize>::default();
|
let mut buf = GenericArray::<u8, F::ChunkSize>::default();
|
||||||
|
|
||||||
|
let version = r.read_u8()?;
|
||||||
|
if version != 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown version"))
|
||||||
|
}
|
||||||
|
let n_required = r.read_uint::<LE>(F::ChunkSize::to_usize())? as usize;
|
||||||
|
|
||||||
r.read_exact(&mut buf[..])?;
|
r.read_exact(&mut buf[..])?;
|
||||||
let x = F::decode(buf.clone());
|
let x = F::decode(buf.clone());
|
||||||
let mut y = Vec::new();
|
let mut y = Vec::new();
|
||||||
@@ -162,26 +152,26 @@ impl<F: GF> Share<F> {
|
|||||||
y.push(F::decode(buf.clone()));
|
y.push(F::decode(buf.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Share { x, y })
|
Ok(Share { n_required, x, y })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn solve<F: GF>(shares: &[Share<F>]) -> Vec<Poly<F>> {
|
pub fn solve<F: GF>(shares: &[impl AsRef<Share<F>>]) -> Vec<Poly<F>> {
|
||||||
// TODO: handle the case where shares have different size
|
// TODO: handle the case where shares have different size
|
||||||
if shares.len() == 0 {
|
if shares.len() == 0 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let mut result: Vec<Poly<F>> = vec![Poly::<F>::zero(); shares[0].y.len()];
|
let mut result: Vec<Poly<F>> = vec![Poly::<F>::zero(); shares[0].as_ref().y.len()];
|
||||||
for j in 0..shares.len() {
|
for j in 0..shares.len() {
|
||||||
let mut basis: Vec<Poly<F>> = shares[j].y.iter().copied().map(|y| Poly::<F>::zero() + y).collect();
|
let mut basis: Vec<Poly<F>> = shares[j].as_ref().y.iter().copied().map(|y| Poly::<F>::zero() + y).collect();
|
||||||
for m in 0..shares.len() {
|
for m in 0..shares.len() {
|
||||||
if j == m {
|
if j == m {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let dx_inv = (shares[j].x - shares[m].x).minv(); // TODO: we can cut runtime in half by sharing (j,m) with (m,j)
|
let dx_inv = (shares[j].as_ref().x - shares[m].as_ref().x).minv(); // TODO: we can cut runtime in half by sharing (j,m) with (m,j)
|
||||||
for bvec in basis.iter_mut() {
|
for bvec in basis.iter_mut() {
|
||||||
*bvec = (Poly::x() - shares[m].x) * &*bvec * dx_inv;
|
*bvec = (Poly::x() - shares[m].as_ref().x) * &*bvec * dx_inv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.iter_mut().zip(basis).for_each(|(result, basis)| *result += &basis);
|
result.iter_mut().zip(basis).for_each(|(result, basis)| *result += &basis);
|
||||||
@@ -192,7 +182,6 @@ pub fn solve<F: GF>(shares: &[Share<F>]) -> Vec<Poly<F>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpolate0<F: GF>(shares: &[Share<F>]) -> Vec<F> {
|
pub fn interpolate0<F: GF>(shares: &[Share<F>]) -> Vec<F> {
|
||||||
use num_traits::Zero;
|
|
||||||
let mut result: Vec<F> = vec![F::ZERO; shares[0].y.len()];
|
let mut result: Vec<F> = vec![F::ZERO; shares[0].y.len()];
|
||||||
for j in shares {
|
for j in shares {
|
||||||
let mut basis = j.y.clone();
|
let mut basis = j.y.clone();
|
||||||
Reference in New Issue
Block a user