Implement SyncKeyGen.
This is a _synchronous_ key generation algorithm. We will use it in `DynamicHoneyBadger`, on top of `HoneyBadger` to satisfy the synchrony requirements. It can also be used independently e.g. on top of a blockchain.
This commit is contained in:
parent
1c3afe85eb
commit
81cbe5a63b
24
mod.rs
24
mod.rs
|
@ -2,7 +2,7 @@ pub mod error;
|
|||
pub mod poly;
|
||||
#[cfg(feature = "serialization-protobuf")]
|
||||
pub mod protobuf_impl;
|
||||
mod serde_impl;
|
||||
pub mod serde_impl;
|
||||
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
@ -132,6 +132,10 @@ impl<E: Engine> SecretKey<E> {
|
|||
SecretKey(rng.gen())
|
||||
}
|
||||
|
||||
pub fn from_value(f: E::Fr) -> Self {
|
||||
SecretKey(f)
|
||||
}
|
||||
|
||||
/// Returns the matching public key.
|
||||
pub fn public_key(&self) -> PublicKey<E> {
|
||||
PublicKey(E::G1Affine::one().mul(self.0))
|
||||
|
@ -167,7 +171,7 @@ impl<E: Engine> SecretKey<E> {
|
|||
}
|
||||
|
||||
/// An encrypted message.
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct Ciphertext<E: Engine>(
|
||||
#[serde(with = "serde_impl::projective")] E::G1,
|
||||
Vec<u8>,
|
||||
|
@ -216,13 +220,25 @@ impl<E: Engine> Hash for DecryptionShare<E> {
|
|||
}
|
||||
|
||||
/// A public key and an associated set of public key shares.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct PublicKeySet<E: Engine> {
|
||||
/// The coefficients of a polynomial whose value at `0` is the "master key", and value at
|
||||
/// `i + 1` is key share number `i`.
|
||||
commit: Commitment<E>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for PublicKeySet<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.commit == other.commit
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for PublicKeySet<E> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.commit.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> From<Commitment<E>> for PublicKeySet<E> {
|
||||
fn from(commit: Commitment<E>) -> PublicKeySet<E> {
|
||||
PublicKeySet { commit }
|
||||
|
@ -449,7 +465,7 @@ mod tests {
|
|||
|
||||
// Each of the shares is a valid signature matching its public key share.
|
||||
for (i, sig) in &sigs {
|
||||
pk_set.public_key_share(*i).verify(sig, msg);
|
||||
assert!(pk_set.public_key_share(*i).verify(sig, msg));
|
||||
}
|
||||
|
||||
// Combined, they produce a signature matching the main public key.
|
||||
|
|
34
poly.rs
34
poly.rs
|
@ -1,23 +1,20 @@
|
|||
//! Utilities for distributed key generation.
|
||||
//! Utilities for distributed key generation: uni- and bivariate polynomials and commitments.
|
||||
//!
|
||||
//! A `BivarPoly` can be used for Verifiable Secret Sharing (VSS) and for key generation by a
|
||||
//! trusted dealer. In a perfectly synchronous setting, e.g. on a blockchain or other agreed
|
||||
//! transaction log, it works like this:
|
||||
//! If `G` is a group of prime order `r` (written additively), and `g` is a generator, then
|
||||
//! multiplication by integers factors through `r`, so the map `x -> x * g` (the sum of `x`
|
||||
//! copies of `g`) is a homomorphism from the field `Fr` of integers modulo `r` to `G`. If the
|
||||
//! _discrete logarithm_ is hard, i.e. it is infeasible to reverse this map, then `x * g` can be
|
||||
//! considered a _commitment_ to `x`: By publishing it, you can guarantee to others that you won't
|
||||
//! change your mind about the value `x`, without revealing it.
|
||||
//!
|
||||
//! The dealer generates a `BivarPoly` of degree `t` and publishes the `BivariateCommitment`,
|
||||
//! with which the polynomial's values can be publicly verified. They then send _row_ `m > 0` to
|
||||
//! node number `m`. Node `m`, in turn, sends _value_ `s` to node number `s`. Then if `2 * t + 1`
|
||||
//! nodes confirm that they received a valid row, and there are at most `t` faulty nodes, then at
|
||||
//! least `t + 1` honest nodes sent on an entry of every other node's column to that node. So we
|
||||
//! know that every node can now reconstruct its column and the value at `0` of its column. These
|
||||
//! values all lie on a univariate polynomial of degree `t`, so they can be used as secret keys.
|
||||
//! This concept extends to polynomials: If you have a polynomial `f` over `Fr`, defined as
|
||||
//! `a * X * X + b * X + c`, you can publish `a * g`, `b * g` and `c * g`. Then others will be able
|
||||
//! to verify any single value `f(x)` of the polynomial without learning the original polynomial,
|
||||
//! because `f(x) * g == x * x * (a * g) + x * (b * g) + (c * g)`. Only after learning three (in
|
||||
//! general `degree + 1`) values, they can interpolate `f` itself.
|
||||
//!
|
||||
//! For Distributed Key Generation (DKG), every node proposes a polynomial via VSS. After a fixed
|
||||
//! number (at least `N - 2 * t` if there are `N` nodes and up to `t` faulty ones) of them have
|
||||
//! successfully been distributed, every node adds up the resulting secrets. Since the sum of
|
||||
//! polynomials of degree `t` is itself a polynomial of degree `t`, these sums are still valid
|
||||
//! secret keys, but now nobody knows the master key (number `0`).
|
||||
// TODO: Expand this explanation and add examples, once the API is complete and stable.
|
||||
//! This module defines univariate polynomials (in one variable) and _symmetric_ bivariate
|
||||
//! polynomials (in two variables) over a field `Fr`, as well as their _commitments_ in `G`.
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
@ -27,9 +24,10 @@ use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
|||
use rand::Rng;
|
||||
|
||||
/// A univariate polynomial in the prime field.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Poly<E: Engine> {
|
||||
/// The coefficients of a polynomial.
|
||||
#[serde(with = "super::serde_impl::field_vec")]
|
||||
coeff: Vec<E::Fr>,
|
||||
}
|
||||
|
||||
|
|
102
serde_impl.rs
102
serde_impl.rs
|
@ -80,3 +80,105 @@ pub mod projective_vec {
|
|||
Ok(wrap_vec.into_iter().map(|CurveWrap(c, _)| c).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization and deserialization of vectors of field elements.
|
||||
pub mod field_vec {
|
||||
use std::borrow::Borrow;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use pairing::{PrimeField, PrimeFieldRepr};
|
||||
use serde::de::Error as DeserializeError;
|
||||
use serde::ser::Error as SerializeError;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// A wrapper type to facilitate serialization and deserialization of field elements.
|
||||
pub struct FieldWrap<F, B>(B, PhantomData<F>);
|
||||
|
||||
impl<F, B> FieldWrap<F, B> {
|
||||
pub fn new(f: B) -> Self {
|
||||
FieldWrap(f, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> FieldWrap<F, F> {
|
||||
pub fn into_inner(self) -> F {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: PrimeField, B: Borrow<F>> Serialize for FieldWrap<F, B> {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
let mut bytes = Vec::new();
|
||||
self.0
|
||||
.borrow()
|
||||
.into_repr()
|
||||
.write_be(&mut bytes)
|
||||
.map_err(|_| S::Error::custom("failed to write bytes"))?;
|
||||
bytes.serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, F: PrimeField> Deserialize<'de> for FieldWrap<F, F> {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
let bytes: Vec<u8> = Deserialize::deserialize(d)?;
|
||||
let mut repr = F::zero().into_repr();
|
||||
repr.read_be(&bytes[..])
|
||||
.map_err(|_| D::Error::custom("failed to write bytes"))?;
|
||||
Ok(FieldWrap::new(F::from_repr(repr).map_err(|_| {
|
||||
D::Error::custom("invalid field element representation")
|
||||
})?))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S, F>(vec: &[F], s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
F: PrimeField,
|
||||
{
|
||||
let wrap_vec: Vec<FieldWrap<F, &F>> = vec.iter().map(FieldWrap::new).collect();
|
||||
wrap_vec.serialize(s)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, F>(d: D) -> Result<Vec<F>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
F: PrimeField,
|
||||
{
|
||||
let wrap_vec = <Vec<FieldWrap<F, F>>>::deserialize(d)?;
|
||||
Ok(wrap_vec.into_iter().map(|FieldWrap(f, _)| f).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bincode;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use pairing::Engine;
|
||||
use rand::{self, Rng};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Vecs<E: Engine> {
|
||||
#[serde(with = "super::projective_vec")]
|
||||
curve_points: Vec<E::G1>,
|
||||
#[serde(with = "super::field_vec")]
|
||||
field_elements: Vec<E::Fr>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Vecs<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.curve_points == other.curve_points && self.field_elements == other.field_elements
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vecs() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let vecs: Vecs<Bls12> = Vecs {
|
||||
curve_points: rng.gen_iter().take(10).collect(),
|
||||
field_elements: rng.gen_iter().take(10).collect(),
|
||||
};
|
||||
let ser_vecs = bincode::serialize(&vecs).expect("serialize vecs");
|
||||
let de_vecs = bincode::deserialize(&ser_vecs).expect("deserialize vecs");
|
||||
assert_eq!(vecs, de_vecs);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue