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;
|
pub mod poly;
|
||||||
#[cfg(feature = "serialization-protobuf")]
|
#[cfg(feature = "serialization-protobuf")]
|
||||||
pub mod protobuf_impl;
|
pub mod protobuf_impl;
|
||||||
mod serde_impl;
|
pub mod serde_impl;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -132,6 +132,10 @@ impl<E: Engine> SecretKey<E> {
|
||||||
SecretKey(rng.gen())
|
SecretKey(rng.gen())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_value(f: E::Fr) -> Self {
|
||||||
|
SecretKey(f)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the matching public key.
|
/// Returns the matching public key.
|
||||||
pub fn public_key(&self) -> PublicKey<E> {
|
pub fn public_key(&self) -> PublicKey<E> {
|
||||||
PublicKey(E::G1Affine::one().mul(self.0))
|
PublicKey(E::G1Affine::one().mul(self.0))
|
||||||
|
@ -167,7 +171,7 @@ impl<E: Engine> SecretKey<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An encrypted message.
|
/// An encrypted message.
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct Ciphertext<E: Engine>(
|
pub struct Ciphertext<E: Engine>(
|
||||||
#[serde(with = "serde_impl::projective")] E::G1,
|
#[serde(with = "serde_impl::projective")] E::G1,
|
||||||
Vec<u8>,
|
Vec<u8>,
|
||||||
|
@ -216,13 +220,25 @@ impl<E: Engine> Hash for DecryptionShare<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A public key and an associated set of public key shares.
|
/// 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> {
|
pub struct PublicKeySet<E: Engine> {
|
||||||
/// The coefficients of a polynomial whose value at `0` is the "master key", and value at
|
/// The coefficients of a polynomial whose value at `0` is the "master key", and value at
|
||||||
/// `i + 1` is key share number `i`.
|
/// `i + 1` is key share number `i`.
|
||||||
commit: Commitment<E>,
|
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> {
|
impl<E: Engine> From<Commitment<E>> for PublicKeySet<E> {
|
||||||
fn from(commit: Commitment<E>) -> PublicKeySet<E> {
|
fn from(commit: Commitment<E>) -> PublicKeySet<E> {
|
||||||
PublicKeySet { commit }
|
PublicKeySet { commit }
|
||||||
|
@ -449,7 +465,7 @@ mod tests {
|
||||||
|
|
||||||
// Each of the shares is a valid signature matching its public key share.
|
// Each of the shares is a valid signature matching its public key share.
|
||||||
for (i, sig) in &sigs {
|
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.
|
// 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
|
//! If `G` is a group of prime order `r` (written additively), and `g` is a generator, then
|
||||||
//! trusted dealer. In a perfectly synchronous setting, e.g. on a blockchain or other agreed
|
//! multiplication by integers factors through `r`, so the map `x -> x * g` (the sum of `x`
|
||||||
//! transaction log, it works like this:
|
//! 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`,
|
//! This concept extends to polynomials: If you have a polynomial `f` over `Fr`, defined as
|
||||||
//! with which the polynomial's values can be publicly verified. They then send _row_ `m > 0` to
|
//! `a * X * X + b * X + c`, you can publish `a * g`, `b * g` and `c * g`. Then others will be able
|
||||||
//! node number `m`. Node `m`, in turn, sends _value_ `s` to node number `s`. Then if `2 * t + 1`
|
//! to verify any single value `f(x)` of the polynomial without learning the original polynomial,
|
||||||
//! nodes confirm that they received a valid row, and there are at most `t` faulty nodes, then at
|
//! because `f(x) * g == x * x * (a * g) + x * (b * g) + (c * g)`. Only after learning three (in
|
||||||
//! least `t + 1` honest nodes sent on an entry of every other node's column to that node. So we
|
//! general `degree + 1`) values, they can interpolate `f` itself.
|
||||||
//! 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.
|
|
||||||
//!
|
//!
|
||||||
//! For Distributed Key Generation (DKG), every node proposes a polynomial via VSS. After a fixed
|
//! This module defines univariate polynomials (in one variable) and _symmetric_ bivariate
|
||||||
//! number (at least `N - 2 * t` if there are `N` nodes and up to `t` faulty ones) of them have
|
//! polynomials (in two variables) over a field `Fr`, as well as their _commitments_ in `G`.
|
||||||
//! 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.
|
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -27,9 +24,10 @@ use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
/// A univariate polynomial in the prime field.
|
/// A univariate polynomial in the prime field.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Poly<E: Engine> {
|
pub struct Poly<E: Engine> {
|
||||||
/// The coefficients of a polynomial.
|
/// The coefficients of a polynomial.
|
||||||
|
#[serde(with = "super::serde_impl::field_vec")]
|
||||||
coeff: Vec<E::Fr>,
|
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())
|
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