Massive rewrite to be based on GF(2^8) rather than a prime field; this results in much faster operation and no size limit
This commit is contained in:
@@ -2,10 +2,9 @@
|
||||
name = "rssss"
|
||||
version = "0.1.0"
|
||||
authors = ["TQ Hirsch <thequux@thequux.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
num-bigint = {version = "0.2.2", features = ["rand", "serde"]}
|
||||
lazy_static = "1.2.0"
|
||||
structopt = "0.2.14"
|
||||
failure = "0.1.5"
|
||||
@@ -15,4 +14,8 @@ num-traits = "0.2.6"
|
||||
rand = "0.6.5"
|
||||
serde = "1.0.87"
|
||||
serde_derive = "1.0.87"
|
||||
serde_cbor = "0.9.0"
|
||||
serde_cbor = "0.9.0"
|
||||
serde_json = "1.0.111"
|
||||
bendy = "0.3.3"
|
||||
generic-array = "1.0.0"
|
||||
anyhow = "1.0.79"
|
||||
31
src/gf.rs
Normal file
31
src/gf.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{Rng, RngCore};
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
pub trait GF: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Copy + Clone + Eq + TryFrom<usize> {
|
||||
const ORDER: usize;
|
||||
type ChunkSize: ArrayLength;
|
||||
|
||||
|
||||
/// Additive identity
|
||||
const ZERO: Self;
|
||||
/// Multiplicative identity
|
||||
const ONE: Self;
|
||||
|
||||
/// Multiplicative inverse
|
||||
fn minv(self) -> Self;
|
||||
|
||||
fn decode(chunk: GenericArray<u8, Self::ChunkSize>) -> Self;
|
||||
fn encode(self) -> GenericArray<u8, Self::ChunkSize>;
|
||||
|
||||
fn decode_slice(s: &[u8]) -> Self {
|
||||
let mut chunk = GenericArray::<u8, Self::ChunkSize>::default();
|
||||
for i in 0..Self::ChunkSize::to_usize() {
|
||||
chunk[i] = s.get(i).copied().unwrap_or(0);
|
||||
}
|
||||
Self::decode(chunk)
|
||||
}
|
||||
fn sample(rng: &mut (impl Rng + ?Sized)) -> Self;
|
||||
}
|
||||
|
||||
188
src/gf256.rs
Normal file
188
src/gf256.rs
Normal file
@@ -0,0 +1,188 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::U1;
|
||||
use rand::distributions::{Standard};
|
||||
use rand::prelude::Distribution;
|
||||
use rand::Rng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::gf::GF;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
/// Field element of GF(2^8)
|
||||
///
|
||||
/// Multiplication is performed modulo $x^8 + x^4 + x^3 + x + 1$, or `{11B}`
|
||||
///
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct GF256(u8);
|
||||
|
||||
impl GF256 {
|
||||
|
||||
/// Multiply by x, reducing modulo 14E
|
||||
const fn mulx(self) -> Self {
|
||||
let poly = self.0;
|
||||
let mask = ((poly as i8) >> 7) as u8;
|
||||
GF256(poly << 1 ^ (0x1B & mask))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl GF for GF256 {
|
||||
const ORDER: usize = 256;
|
||||
type ChunkSize = U1;
|
||||
const ZERO: Self = GF256(0);
|
||||
const ONE: Self = GF256(1);
|
||||
|
||||
|
||||
/// Multiplicative inverse
|
||||
/// Note that this is an expensive operation
|
||||
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
|
||||
}
|
||||
|
||||
fn decode(chunk: GenericArray<u8, Self::ChunkSize>) -> Self {
|
||||
GF256(u8::from_le_bytes(chunk.into_array()))
|
||||
}
|
||||
|
||||
fn encode(self) -> GenericArray<u8, Self::ChunkSize> {
|
||||
self.0.to_le_bytes().into()
|
||||
}
|
||||
|
||||
fn sample(rng: &mut (impl Rng + ?Sized)) -> Self {
|
||||
GF256(rng.sample(Standard))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for GF256 {
|
||||
fn from(value: u8) -> Self {
|
||||
GF256(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GF256> for u8 {
|
||||
fn from(value: GF256) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for GF256 {
|
||||
type Output = GF256;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
GF256(self.0 ^ rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for GF256 {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 ^= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that in GF(2^n), addition is equivalent to subtraction
|
||||
impl Sub for GF256 {
|
||||
type Output = GF256;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for GF256 {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self += rhs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Mul for GF256 {
|
||||
type Output = GF256;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
let mut res = 0;
|
||||
let mut a = self.0;
|
||||
let mut b = rhs;
|
||||
// println!("{:2} {:2} {:2}", "a", "b", "m");
|
||||
for _ in 0..8 {
|
||||
let mask = uneg(a & 1);
|
||||
// println!("{:02x} {:02x} {:02x}", a, b.0, mask);
|
||||
res ^= b.0 & mask;
|
||||
a >>= 1;
|
||||
b = b.mulx();
|
||||
}
|
||||
GF256(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RangeError;
|
||||
|
||||
impl Display for RangeError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Range error")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for RangeError {
|
||||
}
|
||||
|
||||
impl TryFrom<usize> for GF256 {
|
||||
type Error = RangeError;
|
||||
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
if value < Self::ORDER {
|
||||
Ok(GF256(value as u8))
|
||||
} else {
|
||||
Err(RangeError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Utility functions
|
||||
/// Unsigned negate
|
||||
fn uneg(v: u8) -> u8 {
|
||||
(-(v as i8)) as u8
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::GF256;
|
||||
use crate::gf::GF;
|
||||
|
||||
#[test]
|
||||
fn mulx_1() {
|
||||
assert_eq!(GF256(1).mulx(), GF256(2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_1_1() {
|
||||
assert_eq!(GF256(1) * GF256(1), GF256(1))
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn minv_works() {
|
||||
// 0 has no multiplicative inverse
|
||||
for i in 1..=255 {
|
||||
let base = GF256(i);
|
||||
let inv = base.minv();
|
||||
println!("Testing {{{i:02x}}}^-1 = {{{:02x}}}", inv.0);
|
||||
assert_eq!(GF256(1), base*inv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use num_bigint::BigUint;
|
||||
use lazy_static::lazy_static;
|
||||
pub mod gf;
|
||||
pub mod gf256;
|
||||
|
||||
pub mod primes;
|
||||
pub mod poly;
|
||||
pub mod s4;
|
||||
|
||||
|
||||
69
src/main.rs
69
src/main.rs
@@ -2,7 +2,11 @@ use structopt::StructOpt;
|
||||
use std::path::PathBuf;
|
||||
use failure::Error;
|
||||
use std::io;
|
||||
|
||||
use generic_array::typenum::Unsigned;
|
||||
use rand::Rng;
|
||||
use rssss::gf256::GF256;
|
||||
use rssss::gf::GF;
|
||||
use rssss::poly::UniformPoly;
|
||||
|
||||
|
||||
/// Rust implementation of Shamir Secret Sharing
|
||||
@@ -80,20 +84,17 @@ enum Cmdline {
|
||||
|
||||
#[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 {
|
||||
/// The share number. Must be between 1 and 255
|
||||
share_no: u32,
|
||||
}
|
||||
|
||||
#[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>,
|
||||
}
|
||||
@@ -101,23 +102,19 @@ struct Solve {
|
||||
/// 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 {
|
||||
#[structopt(short="p", long="prime", default_value="p384", parse(try_from_str))]
|
||||
prime: rssss::primes::Prime,
|
||||
#[structopt(parse(from_os_str))]
|
||||
data: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cmdline = Cmdline::from_args();
|
||||
let cmd: &Command = match cmdline {
|
||||
let cmd: &dyn Command = match cmdline {
|
||||
Cmdline::GenPoly(ref cmd) => cmd,
|
||||
Cmdline::GenShare(ref cmd) => cmd,
|
||||
Cmdline::Solve(ref cmd) => cmd,
|
||||
@@ -125,7 +122,7 @@ fn main() {
|
||||
Cmdline::Combine(ref cmd) => cmd,
|
||||
};
|
||||
|
||||
cmd.run();
|
||||
cmd.run().unwrap();
|
||||
}
|
||||
|
||||
trait Command {
|
||||
@@ -135,7 +132,6 @@ trait Command {
|
||||
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()?;
|
||||
|
||||
@@ -143,26 +139,30 @@ impl Command for GenPoly {
|
||||
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();
|
||||
let mut payload = Vec::new();
|
||||
secret.to_buf(&mut payload);
|
||||
|
||||
|
||||
let mut polys = Vec::with_capacity(payload.len());
|
||||
for i in 0..payload.len() {
|
||||
polys.push(rng.sample(UniformPoly{ intercept: GF256::from(payload[i]), degree: self.min_shares as usize}));
|
||||
}
|
||||
poly += &BigUint::from(secret);
|
||||
|
||||
// export the poly
|
||||
serde_cbor::to_writer(&mut io::stdout(), &poly)?;
|
||||
|
||||
serde_cbor::to_writer(&mut io::stdout(), &polys)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for GenShare {
|
||||
fn run(&self) -> Result<(), Error> {
|
||||
let mut poly: rssss::poly::Poly = serde_cbor::from_reader(io::stdin())?;
|
||||
eprintln!("Reading poly");
|
||||
let mut poly: Vec<rssss::poly::Poly<GF256>> = serde_cbor::from_reader(io::stdin())?;
|
||||
eprintln!("Read poly");
|
||||
let mut rng = rand::rngs::JitterRng::new()?;
|
||||
|
||||
let share = rssss::s4::Share::new(&mut rng, &poly);
|
||||
let share = rssss::s4::Share::new((self.share_no as u8).into(), poly.as_slice());
|
||||
eprintln!("{share:?}");
|
||||
share.write_to(io::stdout())?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -173,10 +173,10 @@ impl Command for Solve {
|
||||
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))
|
||||
.and_then(|f| rssss::s4::Share::read_from(f))
|
||||
.map_err(|err| Error::from(err)
|
||||
.context(format!("Failed to read {:?}", filename)))?)
|
||||
}).collect::<Result<Vec<rssss::s4::Share>, Error>>()?;
|
||||
}).collect::<Result<Vec<rssss::s4::Share<GF256>>, Error>>()?;
|
||||
|
||||
let poly = rssss::s4::solve(&shares[..]);
|
||||
serde_cbor::to_writer(&mut io::stdout(), &poly)?;
|
||||
@@ -186,11 +186,12 @@ impl Command for Solve {
|
||||
|
||||
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()));
|
||||
let mut 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<_>>();
|
||||
let secret = rssss::s4::Secret::from_buf(interpolated.as_slice())?;
|
||||
io::stdout().write_all(&secret[..])?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -202,12 +203,16 @@ impl Command for Combine {
|
||||
use std::io::Write;
|
||||
let shares = self.data.iter().map(|filename| {
|
||||
Ok(File::open(&filename)
|
||||
.and_then(|f| rssss::s4::Share::read_from(f, self.prime))
|
||||
.and_then(|f| rssss::s4::Share::read_from(f))
|
||||
.map_err(|err| Error::from(err)
|
||||
.context(format!("Failed to read {:?}", filename)))?)
|
||||
}).collect::<Result<Vec<rssss::s4::Share>, Error>>()?;
|
||||
|
||||
let secret = rssss::s4::Secret::from(rssss::s4::interpolate0(&shares[..]));
|
||||
}).collect::<Result<Vec<rssss::s4::Share<GF256>>, Error>>()?;
|
||||
let mut 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()[..])
|
||||
}
|
||||
let secret = rssss::s4::Secret::from_buf(secret.as_slice())?;
|
||||
|
||||
if !secret.check_crc() {
|
||||
eprintln!("CRC failed; not enough shares or corrupted share")
|
||||
|
||||
224
src/poly.rs
224
src/poly.rs
@@ -1,54 +1,56 @@
|
||||
use std::fmt::Formatter;
|
||||
use std::io::{self, prelude::*};
|
||||
use std::ops::{Mul, Div, Add, AddAssign, DivAssign, Neg};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Mul, Div, Add, AddAssign, DivAssign, Neg, Sub};
|
||||
|
||||
use num_bigint::BigUint;
|
||||
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::primes::Prime;
|
||||
use crate::gf::GF;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Poly {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Poly<F: GF> {
|
||||
// coeff[0] + coeff[1]*x + coeff[2] * x^2
|
||||
// i.e., $$\sum_i coeff_i x^i$$
|
||||
pub prime: Prime,
|
||||
coeff: Vec<BigUint>,
|
||||
coeff: Vec<F>,
|
||||
}
|
||||
|
||||
impl Poly {
|
||||
pub fn zero(modulus: Prime) -> Self {
|
||||
impl<F: GF> Poly<F> {
|
||||
pub fn zero() -> Self {
|
||||
Poly {
|
||||
prime: modulus,
|
||||
coeff: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn x(modulus: Prime) -> Self {
|
||||
pub fn x() -> Self {
|
||||
Poly {
|
||||
prime: modulus,
|
||||
coeff: vec![BigUint::zero(), BigUint::one()],
|
||||
coeff: vec![F::ZERO, F::ONE],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_x(&mut self) {
|
||||
self.coeff.insert(0, BigUint::zero());
|
||||
self.coeff.insert(0, F::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();
|
||||
pub fn eval_at(&self, point: F) -> F {
|
||||
let mut result: F = F::ZERO;
|
||||
for item in self.coeff.iter().rev().copied() {
|
||||
result = result * point + item;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn trim(&mut self) {
|
||||
while !self.coeff.is_empty() {
|
||||
if self.coeff[self.coeff.len()-1].is_zero() {
|
||||
if self.coeff[self.coeff.len()-1] == F::ZERO {
|
||||
self.coeff.pop();
|
||||
} else {
|
||||
break
|
||||
@@ -57,144 +59,174 @@ impl Poly {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Poly> for Poly {
|
||||
type Output = Poly;
|
||||
impl<F: GF> Add<&Poly<F>> for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn add(self, rhs: &Poly) -> Self::Output {
|
||||
fn add(self, rhs: &Poly<F>) -> 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);
|
||||
impl<F: GF> AddAssign<&Poly<F>> for Poly<F> {
|
||||
fn add_assign(&mut self, rhs: &Poly<F>) {
|
||||
if self.coeff.len() < rhs.coeff.len() {
|
||||
self.coeff.extend(::std::iter::repeat(BigUint::zero()).take(rhs.coeff.len() - self.coeff.len()));
|
||||
self.coeff.extend(::std::iter::repeat(F::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();
|
||||
for (a, b) in self.coeff.iter_mut().zip(rhs.coeff.iter().copied()) {
|
||||
*a = *a + b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
impl<F: GF> Add for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn add(mut self, rhs: &BigUint) -> Self::Output {
|
||||
fn add(mut self, rhs: Poly<F>) -> Self::Output {
|
||||
self += &rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: GF> Add<F> for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
fn add(mut self, rhs: F) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<&BigUint> for Poly {
|
||||
fn add_assign(&mut self, rhs: &BigUint) {
|
||||
|
||||
impl<F: GF> AddAssign<F> for Poly<F> {
|
||||
fn add_assign(&mut self, rhs: F) {
|
||||
if self.coeff.len() == 0 {
|
||||
self.coeff.push(rhs % self.prime.modulus())
|
||||
self.coeff.push(rhs)
|
||||
} else {
|
||||
self.coeff[0] += rhs;
|
||||
self.coeff[0] %= self.prime.modulus()
|
||||
self.coeff[0] = self.coeff[0] + rhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
impl <F: GF> Sub<F> for Poly<F> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(mut self, rhs: BigUint) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
fn sub(mut self, rhs: F) -> Self::Output {
|
||||
self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
impl<F: GF> Mul<F> for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
fn mul(mut self, rhs: F) -> Poly<F> {
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a *= rhs;
|
||||
*a %= self.prime.modulus();
|
||||
*a = *a * rhs;
|
||||
}
|
||||
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;
|
||||
impl<F: GF> Mul<&Poly<F>> for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn mul(mut self, rhs: &Poly) -> Self::Output {
|
||||
let mut result = Poly::zero(self.prime);
|
||||
for factor in rhs.coeff.iter() {
|
||||
result += &(&self * factor);
|
||||
fn mul(mut self, rhs: &Poly<F>) -> Self::Output {
|
||||
let mut result = Self::zero();
|
||||
for factor in rhs.coeff.iter().copied() {
|
||||
result += &(self.clone() * factor);
|
||||
self.mul_x();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<&Poly> for &Poly {
|
||||
type Output = Poly;
|
||||
impl<F: GF> Mul<&Poly<F>> for &Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn mul(self, rhs: &Poly) -> Self::Output {
|
||||
fn mul(self, rhs: &Poly<F>) -> Self::Output {
|
||||
self.clone() * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<BigUint> for Poly {
|
||||
type Output = Poly;
|
||||
impl<F: GF> Div<F> for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn div(mut self, rhs: BigUint) -> Poly {
|
||||
fn div(mut self, rhs: F) -> Poly<F> {
|
||||
self /= rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<BigUint> for Poly {
|
||||
fn div_assign(&mut self, rhs: BigUint) {
|
||||
let inv = self.prime.inverse(rhs);
|
||||
impl<F: GF> DivAssign<F> for Poly<F> {
|
||||
fn div_assign(&mut self, rhs: F) {
|
||||
let inv = rhs.minv();
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a *= &inv;
|
||||
*a = *a * inv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Poly {
|
||||
type Output = Poly;
|
||||
impl<F: GF> Neg for Poly<F> {
|
||||
type Output = Poly<F>;
|
||||
|
||||
fn neg(mut self) -> Self::Output {
|
||||
for a in self.coeff.iter_mut() {
|
||||
*a = self.prime.negate(&*a);
|
||||
}
|
||||
// Elements in GF(2^n) are their own negative
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Poly;
|
||||
use num_bigint::BigUint;
|
||||
use crate::primes::Prime;
|
||||
pub struct UniformPoly<F: GF>{
|
||||
pub intercept: F,
|
||||
pub degree: usize
|
||||
}
|
||||
|
||||
impl<F: GF> Distribution<Poly<F>> for UniformPoly<F> {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Poly<F> {
|
||||
let mut coeff = Vec::with_capacity(self.degree + 1);
|
||||
coeff.push(self.intercept);
|
||||
for _ in 1..=self.degree {
|
||||
coeff.push(F::sample(rng));
|
||||
}
|
||||
while coeff[self.degree] == F::ZERO {
|
||||
// highest degree coefficient must be non-zero
|
||||
coeff[self.degree] = F::sample(rng);
|
||||
}
|
||||
|
||||
Poly{
|
||||
coeff,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: GF+Serialize> Serialize for Poly<F> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
let mut seq = serializer.serialize_seq(Some(self.coeff.len()))?;
|
||||
for coeff in self.coeff.iter() {
|
||||
seq.serialize_element(coeff)?
|
||||
};
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl <'de, F:GF+Deserialize<'de>+'de> Deserialize<'de> for Poly<F> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
struct V<'de, F: GF+Deserialize<'de>+'de>(PhantomData<&'de F>);
|
||||
impl<'de, F: GF+Deserialize<'de>> Visitor<'de> for V<'de, F> {
|
||||
type Value = Poly<F>;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("list of coefficients")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: SeqAccess<'de> {
|
||||
let mut coeff = Vec::with_capacity(seq.size_hint().unwrap_or(4));
|
||||
while let Some(item) = seq.next_element()? {
|
||||
coeff.push(item)
|
||||
}
|
||||
Ok(Poly{ coeff })
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(V(PhantomData))
|
||||
}
|
||||
}
|
||||
159
src/primes.rs
159
src/primes.rs
@@ -1,159 +0,0 @@
|
||||
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, 0x00000000, 0x00000000, 0xFFFFFFFF,
|
||||
0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
]);
|
||||
|
||||
static ref PRIME_P448: BigUint = BigUint::new(vec![
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF,
|
||||
]);
|
||||
|
||||
static ref PRIME_M12: BigUint = BigUint::new(vec![
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF,
|
||||
]);
|
||||
|
||||
static ref PRIME_M13: BigUint = (BigUint::one() << 521) - BigUint::one();
|
||||
static ref PRIME_M19: BigUint = (BigUint::one() << 4253) - BigUint::one();
|
||||
static ref PRIME_M34: BigUint = (BigUint::one() << 1257787) - BigUint::one();
|
||||
}
|
||||
|
||||
// Other primes to possibly implemet:
|
||||
// 2^521-1
|
||||
// 2^384 - 2^128 - 2^96 + 2^32 - 1 (still a bit painful)
|
||||
// 2^448 - 2^224 - 1
|
||||
// 2^256 - 2^32 - 977
|
||||
|
||||
|
||||
#[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,
|
||||
M12,
|
||||
M13,
|
||||
M19,
|
||||
M34,
|
||||
}
|
||||
|
||||
impl Prime {
|
||||
pub fn to_id(self) -> u8 {
|
||||
match self {
|
||||
Prime::P384 => 1,
|
||||
Prime::P448 => 2,
|
||||
Prime::M12 => 3,
|
||||
Prime::M13 => 4,
|
||||
Prime::M19 => 5,
|
||||
Prime::M34 => 6,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn byte_size(self) -> usize {
|
||||
match self {
|
||||
Prime::P448 => 56,
|
||||
Prime::P384 => 48,
|
||||
Prime::M12 => 16,
|
||||
Prime::M13 => 66,
|
||||
Prime::M19 => 532,
|
||||
Prime::M34 => 157224,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulus(self) -> &'static BigUint {
|
||||
match self {
|
||||
Prime::P384 => &PRIME_P384,
|
||||
Prime::P448 => &PRIME_P448,
|
||||
Prime::M12 => &PRIME_M12,
|
||||
Prime::M13 => &PRIME_M13,
|
||||
Prime::M19 => &PRIME_M19,
|
||||
Prime::M34 => &PRIME_M34,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inverse(self, value: BigUint) -> BigUint {
|
||||
let saved_value = value.clone();
|
||||
let a = ext_gcd(self, value, self.modulus().clone()).0;
|
||||
assert_eq!((&a * saved_value) % self.modulus(), BigUint::one());
|
||||
a
|
||||
}
|
||||
|
||||
pub fn negate(self, mut value: &BigUint) -> BigUint {
|
||||
let result = self.modulus() - (value % self.modulus());
|
||||
assert_eq!(BigUint::zero(), (&result + value) % self.modulus());
|
||||
result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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),
|
||||
"m12" => Ok(Prime::M12),
|
||||
"m13" => Ok(Prime::M13),
|
||||
"m19" => Ok(Prime::M19),
|
||||
"m34" => Ok(Prime::M34),
|
||||
_ => Err(failure::err_msg("Invalid prime spec; expected P384, P448, M12, M13, M19, or M34")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ext_gcd(prime: Prime, 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;
|
||||
let new_b = a % &b;
|
||||
a = b;
|
||||
b = new_b;
|
||||
|
||||
let new_x = (last_x + prime.negate(&(&x * "))) % prime.modulus();
|
||||
let new_y = (last_y + prime.negate(&(&y * "))) % prime.modulus();
|
||||
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
x = new_x;
|
||||
y = new_y;
|
||||
}
|
||||
(last_x, last_y)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use num_bigint::BigUint;
|
||||
use super::Prime;
|
||||
|
||||
// These definitions are much slower than the above static ones, but in
|
||||
// exchange, they're much more likely to be correct
|
||||
#[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)));
|
||||
}
|
||||
#[test]
|
||||
fn check_value_of_p448() {
|
||||
let one = &BigUint::new(vec![1]);
|
||||
assert_eq!(Prime::P448.modulus(), &((one << 448) - one - (one << 224)));
|
||||
}
|
||||
}
|
||||
208
src/s4.rs
208
src/s4.rs
@@ -1,11 +1,14 @@
|
||||
use std::io::{self, prelude::*};
|
||||
use std::ops::Deref;
|
||||
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
||||
use crc::Hasher32;
|
||||
use failure::err_msg;
|
||||
use generic_array::GenericArray;
|
||||
use crate::gf256::GF256;
|
||||
|
||||
use num_bigint::BigUint;
|
||||
use serde::Serialize;
|
||||
use crate::gf::GF;
|
||||
|
||||
use crate::poly::Poly;
|
||||
use crate::primes::Prime;
|
||||
|
||||
|
||||
/// Structure
|
||||
@@ -17,12 +20,40 @@ use crate::primes::Prime;
|
||||
/// this way, the high bit is always unset
|
||||
#[derive(Default,Clone, Debug)]
|
||||
pub struct Secret {
|
||||
length: u16,
|
||||
data: Vec<u8>,
|
||||
crc32: u32,
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -30,7 +61,6 @@ impl Secret {
|
||||
}
|
||||
|
||||
let mut res = Secret {
|
||||
length: data.len() as u16,
|
||||
data,
|
||||
crc32: 0,
|
||||
};
|
||||
@@ -40,11 +70,12 @@ impl Secret {
|
||||
}
|
||||
|
||||
fn compute_crc(&self) -> u32 {
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use crc::crc32::{CASTAGNOLI, Digest, Hasher32};
|
||||
let mut hasher = Digest::new(CASTAGNOLI);
|
||||
let mut size_vi = Vec::with_capacity(5);
|
||||
hasher.reset();
|
||||
hasher.write(&[1]);
|
||||
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()
|
||||
@@ -54,6 +85,38 @@ impl Secret {
|
||||
let crc = self.compute_crc();
|
||||
crc == self.crc32
|
||||
}
|
||||
|
||||
pub fn from_buf(mut buf: &[u8]) -> Result<Self, failure::Error> {
|
||||
use failure::err_msg;
|
||||
if buf[0] != 2 {
|
||||
return Err(err_msg("Invalid version")) // Invalid version
|
||||
}
|
||||
|
||||
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 data = content.into();
|
||||
let crc32 = buf.read_u32::<BE>().unwrap();
|
||||
|
||||
let result = Self { data, crc32 };
|
||||
if result.crc32 != result.compute_crc() {
|
||||
return Err(err_msg("Invalid CRC")) // Invalid CRC
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn to_buf(&self, buf: &mut Vec<u8>) {
|
||||
buf.push(2); // version
|
||||
write_varint(self.data.len() as u32, &mut *buf);
|
||||
buf.extend_from_slice(self.data.as_slice());
|
||||
buf.write_u32::<BE>(self.crc32).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Secret {
|
||||
@@ -64,117 +127,88 @@ impl Deref for Secret {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if decoded[0] != 1 {
|
||||
panic!("Unknown version {}", decoded[0]);
|
||||
}
|
||||
if decoded.len() < 5 {
|
||||
panic!("Data too short");
|
||||
}
|
||||
res.data = decoded[1..decoded.len() - 4].to_owned();
|
||||
res.crc32 = BigEndian::read_u32(&decoded[decoded.len()-4 .. ]);
|
||||
|
||||
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(&[1]);
|
||||
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,
|
||||
#[derive(Debug)]
|
||||
pub struct Share<Field: GF> {
|
||||
pub x: Field,
|
||||
pub y: Vec<Field>,
|
||||
}
|
||||
|
||||
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);
|
||||
impl<F: GF> Share<F> {
|
||||
pub fn new(share_no: F, poly: &[Poly<F>]) -> Self {
|
||||
let x= share_no;
|
||||
let y = poly.iter().map(|word| word.eval_at(x)).collect();
|
||||
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[..])?;
|
||||
w.write_all(&self.x.encode()[..])?;
|
||||
for y in self.y.iter().copied() {
|
||||
w.write_all(&y.encode()[..])?;
|
||||
}
|
||||
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[..]);
|
||||
pub fn read_from<R: Read>(mut r: R) -> io::Result<Self> {
|
||||
let mut buf = GenericArray::<u8, F::ChunkSize>::default();
|
||||
r.read_exact(&mut buf[..])?;
|
||||
let x = F::decode(buf.clone());
|
||||
let mut y = Vec::new();
|
||||
|
||||
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"));
|
||||
while let Ok(()) = r.read_exact(&mut buf[..]) {
|
||||
y.push(F::decode(buf.clone()));
|
||||
}
|
||||
|
||||
Ok(Share{ prime, x, y })
|
||||
Ok(Share { x, y })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solve(shares: &[Share]) -> Poly {
|
||||
let prime = shares[0].prime;
|
||||
let mut result = Poly::zero(prime);
|
||||
|
||||
pub fn solve<F: GF>(shares: &[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()];
|
||||
for j in 0..shares.len() {
|
||||
let mut basis = Poly::zero(prime) + &shares[j].y;
|
||||
let mut basis: Vec<Poly<F>> = shares[j].y.iter().copied().map(|y| Poly::<F>::zero() + y).collect();
|
||||
for m in 0..shares.len() {
|
||||
if j == m {
|
||||
continue;
|
||||
}
|
||||
basis = (Poly::x(prime) + prime.negate(&shares[m].x))
|
||||
/ (&shares[j].x + prime.negate(&shares[m].x)) * &basis;
|
||||
let dx_inv = (shares[j].x - shares[m].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;
|
||||
}
|
||||
}
|
||||
result += &basis;
|
||||
result.iter_mut().zip(basis).for_each(|(result, basis)| *result += &basis);
|
||||
}
|
||||
result.trim();
|
||||
|
||||
result.iter_mut().for_each(|r| r.trim());
|
||||
result
|
||||
}
|
||||
|
||||
pub fn interpolate0(shares: &[Share]) -> BigUint {
|
||||
pub fn interpolate0<F: GF>(shares: &[Share<F>]) -> Vec<F> {
|
||||
use num_traits::Zero;
|
||||
let prime = shares[0].prime;
|
||||
let mut result = BigUint::zero();
|
||||
for j in 0..shares.len() {
|
||||
let mut basis = shares[j].y.clone();
|
||||
for m in 0..shares.len() {
|
||||
if j == m {
|
||||
continue;
|
||||
let mut result: Vec<F> = vec![F::ZERO; shares[0].y.len()];
|
||||
for j in shares {
|
||||
let mut basis = j.y.clone();
|
||||
|
||||
for k in shares {
|
||||
if j.x == k.x {
|
||||
continue
|
||||
}
|
||||
basis *= &shares[m].x *
|
||||
prime.inverse(&shares[m].x + prime.negate(&shares[j].x));
|
||||
basis %= prime.modulus();
|
||||
let bscale = k.x * (k.x - j.x).minv();
|
||||
basis.iter_mut().for_each(|b| {
|
||||
*b = *b * bscale
|
||||
});
|
||||
}
|
||||
result += basis;
|
||||
result.iter_mut().zip(basis).for_each(|(r,b)| {
|
||||
*r = *r + b;
|
||||
});
|
||||
}
|
||||
result % prime.modulus()
|
||||
result
|
||||
}
|
||||
Reference in New Issue
Block a user