mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #159 from poanetwork/afck-into-fr
Accept more types in threshold crypto API.
This commit is contained in:
commit
8d449eceb5
|
@ -107,7 +107,7 @@ impl<T: Clone + Debug + AsRef<[u8]> + PartialEq + Send + Sync + From<Vec<u8>> +
|
||||||
// keys here. A fully-featured application would need to take appropriately initialized keys
|
// keys here. A fully-featured application would need to take appropriately initialized keys
|
||||||
// from elsewhere.
|
// from elsewhere.
|
||||||
let secret_key_set = SecretKeySet::from(Poly::zero());
|
let secret_key_set = SecretKeySet::from(Poly::zero());
|
||||||
let sk_share = secret_key_set.secret_key_share(our_id as u64);
|
let sk_share = secret_key_set.secret_key_share(our_id);
|
||||||
let pub_key_set = secret_key_set.public_keys();
|
let pub_key_set = secret_key_set.public_keys();
|
||||||
let sk = SecretKey::default();
|
let sk = SecretKey::default();
|
||||||
let pub_keys = all_ids
|
let pub_keys = all_ids
|
||||||
|
|
|
@ -207,16 +207,8 @@ where
|
||||||
|
|
||||||
fn combine_and_verify_sig(&self) -> Result<Signature> {
|
fn combine_and_verify_sig(&self) -> Result<Signature> {
|
||||||
// Pass the indices of sender nodes to `combine_signatures`.
|
// Pass the indices of sender nodes to `combine_signatures`.
|
||||||
let ids_shares: BTreeMap<&NodeUid, &SignatureShare> = self.received_shares.iter().collect();
|
let to_idx = |(id, share)| (self.netinfo.node_index(id).unwrap(), share);
|
||||||
let ids_u64: BTreeMap<&NodeUid, u64> = ids_shares
|
let shares = self.received_shares.iter().map(to_idx);
|
||||||
.keys()
|
|
||||||
.map(|&id| (id, self.netinfo.node_index(id).unwrap() as u64))
|
|
||||||
.collect();
|
|
||||||
// Convert indices to `u64` which is an interface type for `pairing`.
|
|
||||||
let shares: BTreeMap<&u64, &SignatureShare> = ids_shares
|
|
||||||
.iter()
|
|
||||||
.map(|(id, &share)| (&ids_u64[id], share))
|
|
||||||
.collect();
|
|
||||||
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
|
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
|
||||||
if !self
|
if !self
|
||||||
.netinfo
|
.netinfo
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
use pairing::bls12_381::Fr;
|
||||||
|
use pairing::{Field, PrimeField};
|
||||||
|
|
||||||
|
/// A conversion into an element of the field `Fr`.
|
||||||
|
pub trait IntoFr: Copy {
|
||||||
|
fn into_fr(self) -> Fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFr for Fr {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFr for u64 {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
Fr::from_repr(self.into()).expect("modulus is greater than u64::MAX")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFr for usize {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
(self as u64).into_fr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFr for i32 {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
if self >= 0 {
|
||||||
|
(self as u64).into_fr()
|
||||||
|
} else {
|
||||||
|
let mut result = ((-self) as u64).into_fr();
|
||||||
|
result.negate();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFr for i64 {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
if self >= 0 {
|
||||||
|
(self as u64).into_fr()
|
||||||
|
} else {
|
||||||
|
let mut result = ((-self) as u64).into_fr();
|
||||||
|
result.negate();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: IntoFr> IntoFr for &'a T {
|
||||||
|
fn into_fr(self) -> Fr {
|
||||||
|
(*self).into_fr()
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))]
|
#![cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))]
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
mod into_fr;
|
||||||
pub mod poly;
|
pub mod poly;
|
||||||
#[cfg(feature = "serialization-protobuf")]
|
#[cfg(feature = "serialization-protobuf")]
|
||||||
pub mod protobuf_impl;
|
pub mod protobuf_impl;
|
||||||
|
@ -14,12 +15,13 @@ use std::ptr::write_volatile;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use init_with::InitWith;
|
use init_with::InitWith;
|
||||||
use pairing::bls12_381::{Bls12, Fr, FrRepr, G1, G1Affine, G2, G2Affine};
|
use pairing::bls12_381::{Bls12, Fr, G1, G1Affine, G2, G2Affine};
|
||||||
use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
use pairing::{CurveAffine, CurveProjective, Engine, Field};
|
||||||
use rand::{ChaChaRng, OsRng, Rng, SeedableRng};
|
use rand::{ChaChaRng, OsRng, Rng, SeedableRng};
|
||||||
use ring::digest;
|
use ring::digest;
|
||||||
|
|
||||||
use self::error::{ErrorKind, Result};
|
use self::error::{ErrorKind, Result};
|
||||||
|
use self::into_fr::IntoFr;
|
||||||
use self::poly::{Commitment, Poly};
|
use self::poly::{Commitment, Poly};
|
||||||
use fmt::HexBytes;
|
use fmt::HexBytes;
|
||||||
|
|
||||||
|
@ -330,26 +332,26 @@ impl PublicKeySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `i`-th public key share.
|
/// Returns the `i`-th public key share.
|
||||||
pub fn public_key_share<T: Into<FrRepr>>(&self, i: T) -> PublicKeyShare {
|
pub fn public_key_share<T: IntoFr>(&self, i: T) -> PublicKeyShare {
|
||||||
let value = self.commit.evaluate(from_repr_plus_1::<Fr>(i.into()));
|
let value = self.commit.evaluate(into_fr_plus_1(i));
|
||||||
PublicKeyShare(PublicKey(value))
|
PublicKeyShare(PublicKey(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Combines the shares into a signature that can be verified with the main public key.
|
/// Combines the shares into a signature that can be verified with the main public key.
|
||||||
pub fn combine_signatures<'a, ITR, IND>(&self, shares: ITR) -> Result<Signature>
|
pub fn combine_signatures<'a, T, I>(&self, shares: I) -> Result<Signature>
|
||||||
where
|
where
|
||||||
ITR: IntoIterator<Item = (&'a IND, &'a SignatureShare)>,
|
I: IntoIterator<Item = (T, &'a SignatureShare)>,
|
||||||
IND: Into<FrRepr> + Clone + 'a,
|
T: IntoFr,
|
||||||
{
|
{
|
||||||
let samples = shares.into_iter().map(|(i, share)| (i, &(share.0).0));
|
let samples = shares.into_iter().map(|(i, share)| (i, &(share.0).0));
|
||||||
Ok(Signature(interpolate(self.commit.degree() + 1, samples)?))
|
Ok(Signature(interpolate(self.commit.degree() + 1, samples)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Combines the shares to decrypt the ciphertext.
|
/// Combines the shares to decrypt the ciphertext.
|
||||||
pub fn decrypt<'a, ITR, IND>(&self, shares: ITR, ct: &Ciphertext) -> Result<Vec<u8>>
|
pub fn decrypt<'a, T, I>(&self, shares: I, ct: &Ciphertext) -> Result<Vec<u8>>
|
||||||
where
|
where
|
||||||
ITR: IntoIterator<Item = (&'a IND, &'a DecryptionShare)>,
|
I: IntoIterator<Item = (T, &'a DecryptionShare)>,
|
||||||
IND: Into<FrRepr> + Clone + 'a,
|
T: IntoFr,
|
||||||
{
|
{
|
||||||
let samples = shares.into_iter().map(|(i, share)| (i, &share.0));
|
let samples = shares.into_iter().map(|(i, share)| (i, &share.0));
|
||||||
let g = interpolate(self.commit.degree() + 1, samples)?;
|
let g = interpolate(self.commit.degree() + 1, samples)?;
|
||||||
|
@ -386,8 +388,8 @@ impl SecretKeySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `i`-th secret key share.
|
/// Returns the `i`-th secret key share.
|
||||||
pub fn secret_key_share<T: Into<FrRepr>>(&self, i: T) -> SecretKeyShare {
|
pub fn secret_key_share<T: IntoFr>(&self, i: T) -> SecretKeyShare {
|
||||||
let value = self.poly.evaluate(from_repr_plus_1::<Fr>(i.into()));
|
let value = self.poly.evaluate(into_fr_plus_1(i));
|
||||||
SecretKeyShare(SecretKey(value))
|
SecretKeyShare(SecretKey(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,15 +448,15 @@ fn xor_vec(x: &[u8], y: &[u8]) -> Vec<u8> {
|
||||||
|
|
||||||
/// Given a list of `t` samples `(i - 1, f(i) * g)` for a polynomial `f` of degree `t - 1`, and a
|
/// Given a list of `t` samples `(i - 1, f(i) * g)` for a polynomial `f` of degree `t - 1`, and a
|
||||||
/// group generator `g`, returns `f(0) * g`.
|
/// group generator `g`, returns `f(0) * g`.
|
||||||
fn interpolate<'a, C, ITR, IND>(t: usize, items: ITR) -> Result<C>
|
fn interpolate<'a, C, T, I>(t: usize, items: I) -> Result<C>
|
||||||
where
|
where
|
||||||
C: CurveProjective,
|
C: CurveProjective<Scalar = Fr>,
|
||||||
ITR: IntoIterator<Item = (&'a IND, &'a C)>,
|
I: IntoIterator<Item = (T, &'a C)>,
|
||||||
IND: Into<<C::Scalar as PrimeField>::Repr> + Clone + 'a,
|
T: IntoFr,
|
||||||
{
|
{
|
||||||
let samples: Vec<_> = items
|
let samples: Vec<_> = items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(i, sample)| (from_repr_plus_1::<C::Scalar>(i.clone().into()), sample))
|
.map(|(i, sample)| (into_fr_plus_1(i), sample))
|
||||||
.collect();
|
.collect();
|
||||||
if samples.len() < t {
|
if samples.len() < t {
|
||||||
return Err(ErrorKind::NotEnoughShares.into());
|
return Err(ErrorKind::NotEnoughShares.into());
|
||||||
|
@ -480,10 +482,10 @@ where
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_repr_plus_1<F: PrimeField>(repr: F::Repr) -> F {
|
fn into_fr_plus_1<I: IntoFr>(x: I) -> Fr {
|
||||||
let mut x = F::one();
|
let mut result = Fr::one();
|
||||||
x.add_assign(&F::from_repr(repr).expect("invalid index"));
|
result.add_assign(&x.into_fr());
|
||||||
x
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -21,10 +21,12 @@ use std::hash::{Hash, Hasher};
|
||||||
use std::ptr::write_volatile;
|
use std::ptr::write_volatile;
|
||||||
use std::{cmp, iter, ops};
|
use std::{cmp, iter, ops};
|
||||||
|
|
||||||
use pairing::bls12_381::{Fr, FrRepr, G1, G1Affine};
|
use pairing::bls12_381::{Fr, G1, G1Affine};
|
||||||
use pairing::{CurveAffine, CurveProjective, Field, PrimeField};
|
use pairing::{CurveAffine, CurveProjective, Field};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
use super::IntoFr;
|
||||||
|
|
||||||
/// A univariate polynomial in the prime field.
|
/// A univariate polynomial in the prime field.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct Poly {
|
pub struct Poly {
|
||||||
|
@ -61,6 +63,30 @@ impl<B: Borrow<Poly>> ops::Add<B> for Poly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ops::Add<Fr> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn add(mut self, rhs: Fr) -> Self::Output {
|
||||||
|
if self.coeff.is_empty() {
|
||||||
|
if !rhs.is_zero() {
|
||||||
|
self.coeff.push(rhs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.coeff[0].add_assign(&rhs);
|
||||||
|
self.remove_zeros();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ops::Add<u64> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn add(self, rhs: u64) -> Self::Output {
|
||||||
|
self + rhs.into_fr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B: Borrow<Poly>> ops::SubAssign<B> for Poly {
|
impl<B: Borrow<Poly>> ops::SubAssign<B> for Poly {
|
||||||
fn sub_assign(&mut self, rhs: B) {
|
fn sub_assign(&mut self, rhs: B) {
|
||||||
let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
|
let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
|
||||||
|
@ -89,6 +115,25 @@ impl<B: Borrow<Poly>> ops::Sub<B> for Poly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clippy thinks using `+` in a `Sub` implementation is suspicious.
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(suspicious_arithmetic_impl))]
|
||||||
|
impl<'a> ops::Sub<Fr> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn sub(self, mut rhs: Fr) -> Self::Output {
|
||||||
|
rhs.negate();
|
||||||
|
self + rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ops::Sub<u64> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn sub(self, rhs: u64) -> Self::Output {
|
||||||
|
self - rhs.into_fr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clippy thinks using any `+` and `-` in a `Mul` implementation is suspicious.
|
// Clippy thinks using any `+` and `-` in a `Mul` implementation is suspicious.
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(suspicious_arithmetic_impl))]
|
#[cfg_attr(feature = "cargo-clippy", allow(suspicious_arithmetic_impl))]
|
||||||
impl<'a, B: Borrow<Poly>> ops::Mul<B> for &'a Poly {
|
impl<'a, B: Borrow<Poly>> ops::Mul<B> for &'a Poly {
|
||||||
|
@ -124,6 +169,27 @@ impl<B: Borrow<Self>> ops::MulAssign<B> for Poly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ops::Mul<Fr> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn mul(mut self, rhs: Fr) -> Self::Output {
|
||||||
|
if rhs.is_zero() {
|
||||||
|
self.coeff.clear();
|
||||||
|
} else {
|
||||||
|
self.coeff.iter_mut().for_each(|c| c.mul_assign(&rhs));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ops::Mul<u64> for Poly {
|
||||||
|
type Output = Poly;
|
||||||
|
|
||||||
|
fn mul(self, rhs: u64) -> Self::Output {
|
||||||
|
self * rhs.into_fr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for Poly {
|
impl Drop for Poly {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let start = self.coeff.as_mut_ptr();
|
let start = self.coeff.as_mut_ptr();
|
||||||
|
@ -176,15 +242,13 @@ impl Poly {
|
||||||
|
|
||||||
/// Returns the unique polynomial `f` of degree `samples.len() - 1` with the given values
|
/// Returns the unique polynomial `f` of degree `samples.len() - 1` with the given values
|
||||||
/// `(x, f(x))`.
|
/// `(x, f(x))`.
|
||||||
pub fn interpolate<'a, T, I>(samples_repr: I) -> Self
|
pub fn interpolate<T, U, I>(samples_repr: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (&'a T, &'a Fr)>,
|
I: IntoIterator<Item = (T, U)>,
|
||||||
T: Into<FrRepr> + Clone + 'a,
|
T: IntoFr,
|
||||||
|
U: IntoFr,
|
||||||
{
|
{
|
||||||
let convert = |(x_repr, y): (&T, &Fr)| {
|
let convert = |(x, y): (T, U)| (x.into_fr(), y.into_fr());
|
||||||
let x = Fr::from_repr(x_repr.clone().into()).expect("invalid index");
|
|
||||||
(x, *y)
|
|
||||||
};
|
|
||||||
let samples: Vec<(Fr, Fr)> = samples_repr.into_iter().map(convert).collect();
|
let samples: Vec<(Fr, Fr)> = samples_repr.into_iter().map(convert).collect();
|
||||||
Self::compute_interpolation(&samples)
|
Self::compute_interpolation(&samples)
|
||||||
}
|
}
|
||||||
|
@ -195,12 +259,12 @@ impl Poly {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value at the point `i`.
|
/// Returns the value at the point `i`.
|
||||||
pub fn evaluate<T: Into<FrRepr>>(&self, i: T) -> Fr {
|
pub fn evaluate<T: IntoFr>(&self, i: T) -> Fr {
|
||||||
let mut result = match self.coeff.last() {
|
let mut result = match self.coeff.last() {
|
||||||
None => return Fr::zero(),
|
None => return Fr::zero(),
|
||||||
Some(c) => *c,
|
Some(c) => *c,
|
||||||
};
|
};
|
||||||
let x = Fr::from_repr(i.into()).expect("invalid index");
|
let x = i.into_fr();
|
||||||
for c in self.coeff.iter().rev().skip(1) {
|
for c in self.coeff.iter().rev().skip(1) {
|
||||||
result.mul_assign(&x);
|
result.mul_assign(&x);
|
||||||
result.add_assign(c);
|
result.add_assign(c);
|
||||||
|
@ -306,12 +370,12 @@ impl Commitment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `i`-th public key share.
|
/// Returns the `i`-th public key share.
|
||||||
pub fn evaluate<T: Into<FrRepr>>(&self, i: T) -> G1 {
|
pub fn evaluate<T: IntoFr>(&self, i: T) -> G1 {
|
||||||
let mut result = match self.coeff.last() {
|
let mut result = match self.coeff.last() {
|
||||||
None => return G1::zero(),
|
None => return G1::zero(),
|
||||||
Some(c) => *c,
|
Some(c) => *c,
|
||||||
};
|
};
|
||||||
let x = Fr::from_repr(i.into()).expect("invalid index");
|
let x = i.into_fr();
|
||||||
for c in self.coeff.iter().rev().skip(1) {
|
for c in self.coeff.iter().rev().skip(1) {
|
||||||
result.mul_assign(x);
|
result.mul_assign(x);
|
||||||
result.add_assign(c);
|
result.add_assign(c);
|
||||||
|
@ -367,7 +431,7 @@ impl BivarPoly {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the polynomial's value at the point `(x, y)`.
|
/// Returns the polynomial's value at the point `(x, y)`.
|
||||||
pub fn evaluate<T: Into<FrRepr>>(&self, x: T, y: T) -> Fr {
|
pub fn evaluate<T: IntoFr>(&self, x: T, y: T) -> Fr {
|
||||||
let x_pow = self.powers(x);
|
let x_pow = self.powers(x);
|
||||||
let y_pow = self.powers(y);
|
let y_pow = self.powers(y);
|
||||||
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
||||||
|
@ -384,7 +448,7 @@ impl BivarPoly {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `x`-th row, as a univariate polynomial.
|
/// Returns the `x`-th row, as a univariate polynomial.
|
||||||
pub fn row<T: Into<FrRepr>>(&self, x: T) -> Poly {
|
pub fn row<T: IntoFr>(&self, x: T) -> Poly {
|
||||||
let x_pow = self.powers(x);
|
let x_pow = self.powers(x);
|
||||||
let coeff: Vec<Fr> = (0..=self.degree)
|
let coeff: Vec<Fr> = (0..=self.degree)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
|
@ -410,8 +474,8 @@ impl BivarPoly {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `0`-th to `degree`-th power of `x`.
|
/// Returns the `0`-th to `degree`-th power of `x`.
|
||||||
fn powers<T: Into<FrRepr>>(&self, x_repr: T) -> Vec<Fr> {
|
fn powers<T: IntoFr>(&self, x: T) -> Vec<Fr> {
|
||||||
powers(x_repr, self.degree)
|
powers(x, self.degree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +505,7 @@ impl BivarCommitment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the commitment's value at the point `(x, y)`.
|
/// Returns the commitment's value at the point `(x, y)`.
|
||||||
pub fn evaluate<T: Into<FrRepr>>(&self, x: T, y: T) -> G1 {
|
pub fn evaluate<T: IntoFr>(&self, x: T, y: T) -> G1 {
|
||||||
let x_pow = self.powers(x);
|
let x_pow = self.powers(x);
|
||||||
let y_pow = self.powers(y);
|
let y_pow = self.powers(y);
|
||||||
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
||||||
|
@ -458,7 +522,7 @@ impl BivarCommitment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `x`-th row, as a commitment to a univariate polynomial.
|
/// Returns the `x`-th row, as a commitment to a univariate polynomial.
|
||||||
pub fn row<T: Into<FrRepr>>(&self, x: T) -> Commitment {
|
pub fn row<T: IntoFr>(&self, x: T) -> Commitment {
|
||||||
let x_pow = self.powers(x);
|
let x_pow = self.powers(x);
|
||||||
let coeff: Vec<G1> = (0..=self.degree)
|
let coeff: Vec<G1> = (0..=self.degree)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
|
@ -475,18 +539,18 @@ impl BivarCommitment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `0`-th to `degree`-th power of `x`.
|
/// Returns the `0`-th to `degree`-th power of `x`.
|
||||||
fn powers<T: Into<FrRepr>>(&self, x_repr: T) -> Vec<Fr> {
|
fn powers<T: IntoFr>(&self, x: T) -> Vec<Fr> {
|
||||||
powers(x_repr, self.degree)
|
powers(x, self.degree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `0`-th to `degree`-th power of `x`.
|
/// Returns the `0`-th to `degree`-th power of `x`.
|
||||||
fn powers<P: PrimeField, T: Into<P::Repr>>(x_repr: T, degree: usize) -> Vec<P> {
|
fn powers<T: IntoFr>(into_x: T, degree: usize) -> Vec<Fr> {
|
||||||
let x = &P::from_repr(x_repr.into()).expect("invalid index");
|
let x = into_x.into_fr();
|
||||||
let mut x_pow_i = P::one();
|
let mut x_pow_i = Fr::one();
|
||||||
iter::once(x_pow_i)
|
iter::once(x_pow_i)
|
||||||
.chain((0..degree).map(|_| {
|
.chain((0..degree).map(|_| {
|
||||||
x_pow_i.mul_assign(x);
|
x_pow_i.mul_assign(&x);
|
||||||
x_pow_i
|
x_pow_i
|
||||||
}))
|
}))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -507,20 +571,12 @@ fn coeff_pos(i: usize, j: usize) -> usize {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use super::{coeff_pos, BivarPoly, Poly};
|
use super::{coeff_pos, BivarPoly, IntoFr, Poly};
|
||||||
|
|
||||||
use pairing::bls12_381::{Fr, G1Affine};
|
use pairing::bls12_381::{Fr, G1Affine};
|
||||||
use pairing::{CurveAffine, Field, PrimeField};
|
use pairing::{CurveAffine, Field};
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
fn fr(x: i64) -> Fr {
|
|
||||||
let mut result = Fr::from_repr((x.abs() as u64).into()).unwrap();
|
|
||||||
if x < 0 {
|
|
||||||
result.negate();
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_coeff_pos() {
|
fn test_coeff_pos() {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -538,22 +594,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn poly() {
|
fn poly() {
|
||||||
// The polynomial "`5 * x.pow(3) + x.pow(1) - 2`".
|
// The polynomial 5 X³ + X - 2.
|
||||||
let poly =
|
let poly = Poly::monomial(3) * 5 + Poly::monomial(1) - 2;
|
||||||
Poly::monomial(3) * Poly::constant(fr(5)) + Poly::monomial(1) - Poly::constant(fr(2));
|
let coeff: Vec<_> = [-2, 1, 0, 5].into_iter().map(IntoFr::into_fr).collect();
|
||||||
let coeff = vec![fr(-2), fr(1), fr(0), fr(5)];
|
|
||||||
assert_eq!(Poly { coeff }, poly);
|
assert_eq!(Poly { coeff }, poly);
|
||||||
let samples = vec![
|
let samples = vec![(-1, -8), (2, 40), (3, 136), (5, 628)];
|
||||||
(fr(-1), fr(-8)),
|
|
||||||
(fr(2), fr(40)),
|
|
||||||
(fr(3), fr(136)),
|
|
||||||
(fr(5), fr(628)),
|
|
||||||
];
|
|
||||||
for &(x, y) in &samples {
|
for &(x, y) in &samples {
|
||||||
assert_eq!(y, poly.evaluate(x));
|
assert_eq!(y.into_fr(), poly.evaluate(x));
|
||||||
}
|
}
|
||||||
let sample_iter = samples.iter().map(|&(ref x, ref y)| (x, y));
|
assert_eq!(Poly::interpolate(samples), poly);
|
||||||
assert_eq!(Poly::interpolate(sample_iter), poly);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -571,7 +620,7 @@ mod tests {
|
||||||
.collect();
|
.collect();
|
||||||
let pub_bi_commits: Vec<_> = bi_polys.iter().map(BivarPoly::commitment).collect();
|
let pub_bi_commits: Vec<_> = bi_polys.iter().map(BivarPoly::commitment).collect();
|
||||||
|
|
||||||
let mut sec_keys = vec![fr(0); node_num];
|
let mut sec_keys = vec![Fr::zero(); node_num];
|
||||||
|
|
||||||
// Each dealer sends row `m` to node `m`, where the index starts at `1`. Don't send row `0`
|
// Each dealer sends row `m` to node `m`, where the index starts at `1`. Don't send row `0`
|
||||||
// to anyone! The nodes verify their rows, and send _value_ `s` on to node `s`. They again
|
// to anyone! The nodes verify their rows, and send _value_ `s` on to node `s`. They again
|
||||||
|
@ -579,20 +628,20 @@ mod tests {
|
||||||
for (bi_poly, bi_commit) in bi_polys.iter().zip(&pub_bi_commits) {
|
for (bi_poly, bi_commit) in bi_polys.iter().zip(&pub_bi_commits) {
|
||||||
for m in 1..=node_num {
|
for m in 1..=node_num {
|
||||||
// Node `m` receives its row and verifies it.
|
// Node `m` receives its row and verifies it.
|
||||||
let row_poly = bi_poly.row(m as u64);
|
let row_poly = bi_poly.row(m);
|
||||||
let row_commit = bi_commit.row(m as u64);
|
let row_commit = bi_commit.row(m);
|
||||||
assert_eq!(row_poly.commitment(), row_commit);
|
assert_eq!(row_poly.commitment(), row_commit);
|
||||||
// Node `s` receives the `s`-th value and verifies it.
|
// Node `s` receives the `s`-th value and verifies it.
|
||||||
for s in 1..=node_num {
|
for s in 1..=node_num {
|
||||||
let val = row_poly.evaluate(s as u64);
|
let val = row_poly.evaluate(s);
|
||||||
let val_g1 = G1Affine::one().mul(val);
|
let val_g1 = G1Affine::one().mul(val);
|
||||||
assert_eq!(bi_commit.evaluate(m as u64, s as u64), val_g1);
|
assert_eq!(bi_commit.evaluate(m, s), val_g1);
|
||||||
// The node can't verify this directly, but it should have the correct value:
|
// The node can't verify this directly, but it should have the correct value:
|
||||||
assert_eq!(bi_poly.evaluate(m as u64, s as u64), val);
|
assert_eq!(bi_poly.evaluate(m, s), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A cheating dealer who modified the polynomial would be detected.
|
// A cheating dealer who modified the polynomial would be detected.
|
||||||
let wrong_poly = row_poly.clone() + Poly::monomial(2) * Poly::constant(fr(5));
|
let wrong_poly = row_poly.clone() + Poly::monomial(2) * Poly::constant(5.into_fr());
|
||||||
assert_ne!(wrong_poly.commitment(), row_commit);
|
assert_ne!(wrong_poly.commitment(), row_commit);
|
||||||
|
|
||||||
// If `2 * faulty_num + 1` nodes confirm that they received a valid row, then at
|
// If `2 * faulty_num + 1` nodes confirm that they received a valid row, then at
|
||||||
|
@ -604,15 +653,15 @@ mod tests {
|
||||||
// `m` received three correct entries from that row:
|
// `m` received three correct entries from that row:
|
||||||
let received: BTreeMap<_, _> = [1, 2, 4]
|
let received: BTreeMap<_, _> = [1, 2, 4]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&i| (i, bi_poly.evaluate(m as u64, i as u64)))
|
.map(|&i| (i, bi_poly.evaluate(m, i)))
|
||||||
.collect();
|
.collect();
|
||||||
let my_row = Poly::interpolate(&received);
|
let my_row = Poly::interpolate(received);
|
||||||
assert_eq!(bi_poly.evaluate(m as u64, 0), my_row.evaluate(0));
|
assert_eq!(bi_poly.evaluate(m, 0), my_row.evaluate(0));
|
||||||
assert_eq!(row_poly, my_row);
|
assert_eq!(row_poly, my_row);
|
||||||
|
|
||||||
// The node sums up all values number `0` it received from the different dealer. No
|
// The node sums up all values number `0` it received from the different dealer. No
|
||||||
// dealer and no other node knows the sum in the end.
|
// dealer and no other node knows the sum in the end.
|
||||||
sec_keys[m - 1].add_assign(&my_row.evaluate(0));
|
sec_keys[m - 1].add_assign(&my_row.evaluate(Fr::zero()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,7 +675,7 @@ mod tests {
|
||||||
sec_key_set += bi_poly.row(0);
|
sec_key_set += bi_poly.row(0);
|
||||||
}
|
}
|
||||||
for m in 1..=node_num {
|
for m in 1..=node_num {
|
||||||
assert_eq!(sec_key_set.evaluate(m as u64), sec_keys[m - 1]);
|
assert_eq!(sec_key_set.evaluate(m), sec_keys[m - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The sum of the first rows of the public commitments is the commitment to the secret key
|
// The sum of the first rows of the public commitments is the commitment to the secret key
|
||||||
|
|
|
@ -407,19 +407,11 @@ where
|
||||||
.get(&self.epoch)
|
.get(&self.epoch)
|
||||||
.and_then(|cts| cts.get(&proposer_id))
|
.and_then(|cts| cts.get(&proposer_id))
|
||||||
{
|
{
|
||||||
let ids_u64: BTreeMap<&NodeUid, u64> = shares
|
match {
|
||||||
.keys()
|
let to_idx = |(id, share)| (self.netinfo.node_index(id).unwrap(), share);
|
||||||
.map(|id| (id, self.netinfo.node_index(id).unwrap() as u64))
|
let share_itr = shares.into_iter().map(to_idx);
|
||||||
.collect();
|
self.netinfo.public_key_set().decrypt(share_itr, ciphertext)
|
||||||
let indexed_shares: BTreeMap<&u64, _> = shares
|
} {
|
||||||
.into_iter()
|
|
||||||
.map(|(id, share)| (&ids_u64[id], share))
|
|
||||||
.collect();
|
|
||||||
match self
|
|
||||||
.netinfo
|
|
||||||
.public_key_set()
|
|
||||||
.decrypt(indexed_shares, ciphertext)
|
|
||||||
{
|
|
||||||
Ok(contrib) => {
|
Ok(contrib) => {
|
||||||
self.decrypted_contributions.insert(proposer_id, contrib);
|
self.decrypted_contributions.insert(proposer_id, contrib);
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
|
||||||
.collect();
|
.collect();
|
||||||
let public_key_shares = node_indices
|
let public_key_shares = node_indices
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, idx)| (id.clone(), public_key_set.public_key_share(*idx as u64)))
|
.map(|(id, idx)| (id.clone(), public_key_set.public_key_share(*idx)))
|
||||||
.collect();
|
.collect();
|
||||||
NetworkInfo {
|
NetworkInfo {
|
||||||
our_uid,
|
our_uid,
|
||||||
|
@ -371,7 +371,7 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
|
||||||
let create_netinfo = |(i, uid): (usize, NodeUid)| {
|
let create_netinfo = |(i, uid): (usize, NodeUid)| {
|
||||||
let netinfo = NetworkInfo::new(
|
let netinfo = NetworkInfo::new(
|
||||||
uid.clone(),
|
uid.clone(),
|
||||||
sk_set.secret_key_share(i as u64),
|
sk_set.secret_key_share(i),
|
||||||
pk_set.clone(),
|
pk_set.clone(),
|
||||||
sec_keys[&uid].clone(),
|
sec_keys[&uid].clone(),
|
||||||
pub_keys.clone(),
|
pub_keys.clone(),
|
||||||
|
|
|
@ -106,18 +106,18 @@
|
||||||
//! let (pks, opt_sks) = node.generate();
|
//! let (pks, opt_sks) = node.generate();
|
||||||
//! assert_eq!(pks, pub_key_set); // All nodes now know the public keys and public key shares.
|
//! assert_eq!(pks, pub_key_set); // All nodes now know the public keys and public key shares.
|
||||||
//! let sks = opt_sks.expect("Not an observer node: We receive a secret key share.");
|
//! let sks = opt_sks.expect("Not an observer node: We receive a secret key share.");
|
||||||
//! secret_key_shares.insert(id as u64, sks);
|
//! secret_key_shares.insert(id, sks);
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! // Three out of four nodes can now sign a message. Each share can be verified individually.
|
//! // Three out of four nodes can now sign a message. Each share can be verified individually.
|
||||||
//! let msg = "Nodes 0 and 1 does not agree with this.";
|
//! let msg = "Nodes 0 and 1 does not agree with this.";
|
||||||
//! let mut sig_shares: BTreeMap<u64, SignatureShare> = BTreeMap::new();
|
//! let mut sig_shares: BTreeMap<usize, SignatureShare> = BTreeMap::new();
|
||||||
//! for (&id, sks) in &secret_key_shares {
|
//! for (&id, sks) in &secret_key_shares {
|
||||||
//! if id != 0 && id != 1 {
|
//! if id != 0 && id != 1 {
|
||||||
//! let sig_share = sks.sign(msg);
|
//! let sig_share = sks.sign(msg);
|
||||||
//! let pks = pub_key_set.public_key_share(id as u64);
|
//! let pks = pub_key_set.public_key_share(id);
|
||||||
//! assert!(pks.verify(&sig_share, msg));
|
//! assert!(pks.verify(&sig_share, msg));
|
||||||
//! sig_shares.insert(id as u64, sig_share);
|
//! sig_shares.insert(id, sig_share);
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
@ -286,7 +286,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
|
||||||
let our_part = BivarPoly::random(threshold, &mut rng);
|
let our_part = BivarPoly::random(threshold, &mut rng);
|
||||||
let commit = our_part.commitment();
|
let commit = our_part.commitment();
|
||||||
let encrypt = |(i, pk): (usize, &PublicKey)| {
|
let encrypt = |(i, pk): (usize, &PublicKey)| {
|
||||||
let row = our_part.row(i as u64 + 1);
|
let row = our_part.row(i + 1);
|
||||||
let bytes = bincode::serialize(&row).expect("failed to serialize row");
|
let bytes = bincode::serialize(&row).expect("failed to serialize row");
|
||||||
pk.encrypt(&bytes)
|
pk.encrypt(&bytes)
|
||||||
};
|
};
|
||||||
|
@ -334,7 +334,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
|
||||||
}
|
}
|
||||||
// The row is valid: now encrypt one value for each node.
|
// The row is valid: now encrypt one value for each node.
|
||||||
let encrypt = |(idx, pk): (usize, &PublicKey)| {
|
let encrypt = |(idx, pk): (usize, &PublicKey)| {
|
||||||
let val = row.evaluate(idx as u64 + 1);
|
let val = row.evaluate(idx + 1);
|
||||||
let wrap = FieldWrap::new(val);
|
let wrap = FieldWrap::new(val);
|
||||||
// TODO: Handle errors.
|
// TODO: Handle errors.
|
||||||
let ser_val = bincode::serialize(&wrap).expect("failed to serialize value");
|
let ser_val = bincode::serialize(&wrap).expect("failed to serialize value");
|
||||||
|
|
|
@ -68,8 +68,8 @@ fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
||||||
let sk = opt_sk.expect("new secret key");
|
let sk = opt_sk.expect("new secret key");
|
||||||
assert_eq!(pks, pub_key_set);
|
assert_eq!(pks, pub_key_set);
|
||||||
let sig = sk.sign(msg);
|
let sig = sk.sign(msg);
|
||||||
assert!(pks.public_key_share(idx as u64).verify(&sig, msg));
|
assert!(pks.public_key_share(idx).verify(&sig, msg));
|
||||||
(idx as u64, sig)
|
(idx, sig)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let sig = pub_key_set
|
let sig = pub_key_set
|
||||||
|
|
Loading…
Reference in New Issue