Compare commits
2 Commits
c5d33bc5da
...
937b8eb6b7
| Author | SHA1 | Date | |
|---|---|---|---|
| 937b8eb6b7 | |||
| b1dfd56446 |
27
Cargo.toml
27
Cargo.toml
@@ -1,21 +1,6 @@
|
||||
[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 = "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"
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members=[
|
||||
"rssss",
|
||||
"rssss-wasm",
|
||||
]
|
||||
|
||||
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"
|
||||
30
rssss/build.rs
Normal file
30
rssss/build.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
#![allow(unused)]
|
||||
use std::path::Path;
|
||||
use crate::gf256::GF256;
|
||||
|
||||
#[path="src/gf.rs"]
|
||||
mod gf;
|
||||
#[path="src/gf256.rs"]
|
||||
mod gf256;
|
||||
|
||||
fn write_tbl(path: impl AsRef<Path>, name: &str, tbl: &[u8; 256]) {
|
||||
let mut res = format!("const INV_TBL: [{name}; {tbl_len}] = [\n", tbl_len=tbl.len());
|
||||
for v in tbl {
|
||||
res += &format!("\t{name}({v}),\n");
|
||||
}
|
||||
res += "];\n";
|
||||
|
||||
std::fs::write(path, res).unwrap();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let mut gf256_inv_tbl = [0;256];
|
||||
for i in 0..256 {
|
||||
gf256_inv_tbl[i] = u8::from(GF256::from(i as u8).minv_slow());
|
||||
}
|
||||
let mut out_file = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
out_file.push("gf256_inv.rs");
|
||||
write_tbl(&out_file, "GF256", &gf256_inv_tbl);
|
||||
|
||||
println!("cargo::rustc-cfg=rssss_have_codegen")
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{Rng, RngCore};
|
||||
use rand::Rng;
|
||||
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;
|
||||
type ChunkSize: ArrayLength;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::error::Error;
|
||||
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::typenum::U1;
|
||||
use rand::distributions::{Standard};
|
||||
use rand::prelude::Distribution;
|
||||
use rand::distributions::Standard;
|
||||
use rand::Rng;
|
||||
|
||||
#[cfg(rssss_have_codegen)]
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::gf::GF;
|
||||
|
||||
@@ -15,9 +16,12 @@ use crate::gf::GF;
|
||||
///
|
||||
/// Multiplication is performed modulo $x^8 + x^4 + x^3 + x + 1$, or `{11B}`
|
||||
///
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(rssss_have_codegen, derive(Serialize, Deserialize))]
|
||||
pub struct GF256(u8);
|
||||
|
||||
#[cfg(rssss_have_codegen)]
|
||||
include!(concat!(env!("OUT_DIR"), "/gf256_inv.rs"));
|
||||
|
||||
impl GF256 {
|
||||
|
||||
/// Multiply by x, reducing modulo 14E
|
||||
@@ -27,6 +31,21 @@ impl GF256 {
|
||||
GF256(poly << 1 ^ (0x1B & mask))
|
||||
}
|
||||
|
||||
// This exists for the benefit of the table generator
|
||||
#[allow(unused)]
|
||||
pub(crate) fn minv_slow(self) -> Self {
|
||||
let mut res = self;
|
||||
let mut factor = 1;
|
||||
for _ in 0..6 {
|
||||
res = res * res * self;
|
||||
factor = factor * 2 + 1;
|
||||
}
|
||||
res = res * res;
|
||||
factor = factor*2;
|
||||
//assert_eq!(factor, 254);
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl GF for GF256 {
|
||||
@@ -38,19 +57,13 @@ impl GF for GF256 {
|
||||
|
||||
/// Multiplicative inverse
|
||||
/// Note that this is an expensive operation
|
||||
#[cfg(rssss_have_codegen)]
|
||||
fn minv(self) -> Self {
|
||||
// For constant time evaluation, we compute self**254
|
||||
let mut res = self;
|
||||
let mut factor = 1;
|
||||
for _ in 0..6 {
|
||||
res = res * res * self;
|
||||
factor = factor * 2 + 1;
|
||||
}
|
||||
res = res * res;
|
||||
factor = factor*2;
|
||||
assert_eq!(factor, 254);
|
||||
|
||||
res
|
||||
INV_TBL[self.0 as usize]
|
||||
}
|
||||
#[cfg(not(rssss_have_codegen))]
|
||||
fn minv(self) -> Self {
|
||||
self.minv_slow()
|
||||
}
|
||||
|
||||
fn decode(chunk: GenericArray<u8, Self::ChunkSize>) -> Self {
|
||||
@@ -151,10 +164,15 @@ impl TryFrom<usize> for GF256 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GF256> for usize {
|
||||
fn from(value: GF256) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
/// Unsigned negate
|
||||
fn uneg(v: u8) -> u8 {
|
||||
const fn uneg(v: u8) -> u8 {
|
||||
(-(v as i8)) as u8
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ impl Command for GenPoly {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
use std::io::Read;
|
||||
|
||||
let mut rng = rand::rngs::JitterRng::new()?;
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
|
||||
let mut payload = vec![];
|
||||
io::stdin().read_to_end(&mut payload)?;
|
||||
@@ -160,12 +160,11 @@ impl Command for GenPoly {
|
||||
impl Command for GenShare {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
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");
|
||||
let mut rng = rand::rngs::OsRng::new()?;
|
||||
|
||||
let share = rssss::s4::Share::new((self.share_no as u8).into(), poly.as_slice());
|
||||
eprintln!("{share:?}");
|
||||
// eprintln!("{share:?}");
|
||||
share.write_to(io::stdout())?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -190,7 +189,7 @@ impl Command for Solve {
|
||||
impl Command for ExtractSecret {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
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))
|
||||
.flat_map(|f| f.encode())
|
||||
.collect::<Vec<_>>();
|
||||
@@ -210,7 +209,7 @@ impl Command for Combine {
|
||||
.map_err(|err| Error::from(err)
|
||||
.context(format!("Failed to read {:?}", filename)))?)
|
||||
}).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());
|
||||
for chunk in interpolated {
|
||||
secret.extend_from_slice(&chunk.encode()[..])
|
||||
@@ -1,20 +1,15 @@
|
||||
use std::fmt::Formatter;
|
||||
use std::io::{self, prelude::*};
|
||||
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::Rng;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::{SeqAccess, Visitor};
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
use crate::gf::GF;
|
||||
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Poly<F: GF> {
|
||||
// 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> {
|
||||
@@ -111,7 +110,7 @@ impl<F: GF> AddAssign<F> for Poly<F> {
|
||||
impl <F: GF> Sub<F> for Poly<F> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(mut self, rhs: F) -> Self::Output {
|
||||
fn sub(self, rhs: F) -> Self::Output {
|
||||
self + rhs
|
||||
}
|
||||
}
|
||||
@@ -169,7 +168,7 @@ impl<F: GF> DivAssign<F> for Poly<F> {
|
||||
impl<F: GF> Neg for 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
|
||||
self
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
use std::io::{self, prelude::*};
|
||||
use std::ops::Deref;
|
||||
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
||||
use crc::Hasher32;
|
||||
use failure::err_msg;
|
||||
use byteorder::{BE, LE, ReadBytesExt, WriteBytesExt};
|
||||
use crc::Crc;
|
||||
use generic_array::GenericArray;
|
||||
use crate::gf256::GF256;
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
use crate::gf::GF;
|
||||
|
||||
use crate::poly::Poly;
|
||||
|
||||
|
||||
/// Structure
|
||||
/// | off | len | meaning |
|
||||
/// | 0 | 1 | Length of payload (L)
|
||||
/// | 1 | L | Payload
|
||||
/// | L+1 | 4 | CRC32c
|
||||
/// | 0 | L | Payload
|
||||
/// | L | 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)]
|
||||
@@ -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 {
|
||||
pub fn new(data: Vec<u8>) -> Self {
|
||||
if data.len() == 0 {
|
||||
@@ -70,15 +37,12 @@ impl Secret {
|
||||
}
|
||||
|
||||
fn compute_crc(&self) -> u32 {
|
||||
use crc::crc32::{CASTAGNOLI, Digest, Hasher32};
|
||||
let mut hasher = Digest::new(CASTAGNOLI);
|
||||
let mut size_vi = Vec::with_capacity(5);
|
||||
hasher.reset();
|
||||
hasher.write(&[2]);
|
||||
write_varint(self.data.len() as u32, &mut size_vi);
|
||||
hasher.write(&self.data[..]);
|
||||
hasher.write(&[0, 0, 0, 0]);
|
||||
hasher.sum32()
|
||||
use crc::CRC_32_ISCSI;
|
||||
let crc = Crc::<u32>::new(&CRC_32_ISCSI);
|
||||
let mut hasher = crc.digest();
|
||||
hasher.update(&self.data[..]);
|
||||
hasher.update(&[0, 0, 0, 0]);
|
||||
hasher.finalize()
|
||||
}
|
||||
|
||||
pub fn check_crc(&self) -> bool {
|
||||
@@ -86,20 +50,14 @@ impl Secret {
|
||||
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;
|
||||
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 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 (content, mut buf) = buf.split_at(buf.len() - 4);
|
||||
let data = content.into();
|
||||
let crc32 = buf.read_u32::<BE>().unwrap();
|
||||
|
||||
@@ -112,8 +70,7 @@ impl Secret {
|
||||
}
|
||||
|
||||
pub fn to_buf(&self, buf: &mut Vec<u8>) {
|
||||
buf.push(2); // version
|
||||
write_varint(self.data.len() as u32, &mut *buf);
|
||||
buf.reserve(self.data.len() + 4);
|
||||
buf.extend_from_slice(self.data.as_slice());
|
||||
buf.write_u32::<BE>(self.crc32).unwrap();
|
||||
}
|
||||
@@ -131,20 +88,46 @@ impl Deref for Secret {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Share<Field: GF> {
|
||||
pub n_required: usize,
|
||||
pub x: 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> {
|
||||
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 y = poly.iter().map(|word| word.eval_at(x)).collect();
|
||||
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<()> {
|
||||
w.write_u8(0)?;
|
||||
w.write_uint::<LE>(self.n_required as u64, F::ChunkSize::to_usize())?;
|
||||
w.write_all(&self.x.encode()[..])?;
|
||||
for y in self.y.iter().copied() {
|
||||
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> {
|
||||
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[..])?;
|
||||
let x = F::decode(buf.clone());
|
||||
let mut y = Vec::new();
|
||||
@@ -162,26 +152,26 @@ impl<F: GF> Share<F> {
|
||||
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
|
||||
if shares.len() == 0 {
|
||||
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() {
|
||||
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() {
|
||||
if j == m {
|
||||
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() {
|
||||
*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);
|
||||
@@ -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> {
|
||||
use num_traits::Zero;
|
||||
let mut result: Vec<F> = vec![F::ZERO; shares[0].y.len()];
|
||||
for j in shares {
|
||||
let mut basis = j.y.clone();
|
||||
Reference in New Issue
Block a user