Compare commits
2 Commits
c5d33bc5da
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 937b8eb6b7 | |||
| b1dfd56446 |
27
Cargo.toml
27
Cargo.toml
@@ -1,21 +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"
|
|
||||||
|
|||||||
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 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,11 +1,12 @@
|
|||||||
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)]
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use crate::gf::GF;
|
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}`
|
/// 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);
|
pub struct GF256(u8);
|
||||||
|
|
||||||
|
#[cfg(rssss_have_codegen)]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/gf256_inv.rs"));
|
||||||
|
|
||||||
impl GF256 {
|
impl GF256 {
|
||||||
|
|
||||||
/// Multiply by x, reducing modulo 14E
|
/// Multiply by x, reducing modulo 14E
|
||||||
@@ -27,6 +31,21 @@ 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 {
|
||||||
|
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 {
|
impl GF for GF256 {
|
||||||
@@ -38,19 +57,13 @@ impl GF for GF256 {
|
|||||||
|
|
||||||
/// Multiplicative inverse
|
/// Multiplicative inverse
|
||||||
/// Note that this is an expensive operation
|
/// Note that this is an expensive operation
|
||||||
|
#[cfg(rssss_have_codegen)]
|
||||||
fn minv(self) -> Self {
|
fn minv(self) -> Self {
|
||||||
// For constant time evaluation, we compute self**254
|
INV_TBL[self.0 as usize]
|
||||||
let mut res = self;
|
|
||||||
let mut factor = 1;
|
|
||||||
for _ in 0..6 {
|
|
||||||
res = res * res * self;
|
|
||||||
factor = factor * 2 + 1;
|
|
||||||
}
|
}
|
||||||
res = res * res;
|
#[cfg(not(rssss_have_codegen))]
|
||||||
factor = factor*2;
|
fn minv(self) -> Self {
|
||||||
assert_eq!(factor, 254);
|
self.minv_slow()
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(chunk: GenericArray<u8, Self::ChunkSize>) -> Self {
|
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
|
// Utility functions
|
||||||
/// Unsigned negate
|
/// Unsigned negate
|
||||||
fn uneg(v: u8) -> u8 {
|
const fn uneg(v: u8) -> u8 {
|
||||||
(-(v as i8)) as u8
|
(-(v as i8)) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,12 +160,11 @@ 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:?}");
|
||||||
share.write_to(io::stdout())?;
|
share.write_to(io::stdout())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -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