Add documentation to the eVRF-based DKG

This commit is contained in:
Luke Parker
2024-07-24 20:55:35 -04:00
parent 96175e115d
commit 05c26d7818
3 changed files with 82 additions and 12 deletions

View File

@@ -39,8 +39,8 @@ dleq = { path = "../dleq", version = "^0.4.1", default-features = false }
# eVRF DKG dependencies
subtle = { version = "2", default-features = false, features = ["std"], optional = true }
generic-array = { version = "1", default-features = false, features = ["alloc"], optional = true }
rand_chacha = { version = "0.3", default-features = false, features = ["std"], optional = true }
blake2 = { version = "0.10", default-features = false, features = ["std"], optional = true }
rand_chacha = { version = "0.3", default-features = false, features = ["std"], optional = true }
generalized-bulletproofs = { path = "../evrf/generalized-bulletproofs", default-features = false, optional = true }
ec-divisors = { path = "../evrf/divisors", default-features = false, optional = true }
generalized-bulletproofs-circuit-abstraction = { path = "./circuit-abstraction", optional = true }
@@ -53,10 +53,6 @@ generalized-bulletproofs = { path = "./generalized-bulletproofs", features = ["t
ec-divisors = { path = "./divisors", features = ["pasta"] }
pasta_curves = "0.5"
[dependencies]
generalized-bulletproofs-circuit-abstraction = { path = "./circuit-abstraction" }
generalized-bulletproofs-ec-gadgets = { path = "./ec-gadgets" }
[features]
std = [
"thiserror",
@@ -79,6 +75,19 @@ std = [
"dleq/serialize"
]
borsh = ["dep:borsh"]
evrf = ["std", "dep:subtle", "dep:generic-array", "dep:rand_chacha", "dep:blake2", "dep:ec-divisors", "dep:generalized-bulletproofs", "dep:evrf"]
evrf = [
"std",
"dep:subtle",
"dep:generic-array",
"dep:blake2",
"dep:rand_chacha",
"dep:generalized-bulletproofs",
"dep:ec-divisors",
"dep:generalized-bulletproofs-circuit-abstraction",
"dep:generalized-bulletproofs-ec-gadgets",
]
tests = ["rand_core/getrandom"]
default = ["std"]

View File

@@ -1,3 +1,57 @@
/*
We implement a DKG using an eVRF, as detailed in the eVRF paper. For the eVRF itself, we do not
use a Paillier-based construction, nor the detailed construction premised on a Bulletproof.
For reference, the detailed construction premised on a Bulletproof involves two curves, notated
here as `C` and `E`, where the scalar field of `C` is the field of `E`. Accordingly, Bulletproofs
over `C` can efficiently perform group operations of points of curve `E`. Each participant has a
private point (`P_i`) on curve `E` committed to over curve `C`. The eVRF selects a pair of
scalars `a, b`, where the participant proves in-Bulletproof the points `A_i, B_i` are
`a * P_i, b * P_i`. The eVRF proceeds to commit to `A_i.x + B_i.x` in a Pedersen Commitment.
Our eVRF uses
[Generalized Bulletproofs](https://repo.getmonero.org/monero-project/ccs-proposals/uploads/a9baa50c38c6312efc0fea5c6a188bb9/gbp.pdf).
This allows us much larger witnesses without growing the reference string, and enables us to
efficiently sample challenges off in-circuit variables (via placing the variables in a vector
commitment, then challenging from a transcript of the commitments). We proceed to use
[elliptic curve divisors](https://repo.getmonero.org/-/project/54/uploads/eb1bf5b4d4855a3480c38abf895bd8e8/Veridise_Divisor_Proofs.pdf)
(which require the ability to sample a challenge off in-circuit variables) to prove discrete
logarithms efficiently.
This is done via having a private scalar (`p_i`) on curve `E`, not a private point, and
publishing the public key for it (`P_i = p_i * G`, where `G` is a generator of `E`). The eVRF
samples two points with unknown discrete logarithms `A, B`, and the circuit proves a Pedersen
Commitment commits to `(p_i * A).x + (p_i * B).x`.
With the eVRF established, we now detail our other novel aspect. The eVRF paper expects secret
shares to be sent to the other parties yet does not detail a precise way to do so. If we
encrypted the secret shares with some stream cipher, each recipient would have to attest validity
or accuse the sender of impropriety. We want an encryption scheme where anyone can verify the
secret shares were encrypted properly, without additional info, efficiently.
Please note from the published commitments, it's possible to calculcate a commitment to the
secret share each party should receive (`V_i`).
We have the sender sample two scalars per recipient, denoted `x_i, y_i` (where `i` is the
recipient index). They perform the eVRF to prove a Pedersen Commitment commits to
`z_i = (x_i * P_i).x + (y_i * P_i).x`. They then publish the encrypted share `s_i + z_i` and
`X_i = x_i * G, Y_i = y_i * G`.
The recipient is able to decrypt the share via calculating
`s_i - ((p_i * X_i).x + (p_i * Y_i).x)`.
To verify the secret share, we have the `F` terms of the Pedersen Commitments revealed (where
`F, H` are generators of `C`, `F` is used for binding and `H` for blinding). This already needs
to be done for the eVRF outputs used within the DKG, in order to obtain thecommitments to the
coefficients. When we have the commitment `Z_i = ((p_i * A).x + (p_i * B).x) * F`, we simply
check `s_i * F = Z_i + V_i`.
In order to open the Pedersen Commitments to their `F` terms, we transcript the commitments and
the claimed openings, then assign random weights to each pair of `(commitment, opening). The
prover proves knowledge of the discrete logarithm of the sum weighted commitments, minus the sum
sum weighted openings, over `H`.
*/
use core::ops::Deref;
use std::{
io::{self, Read, Write},

View File

@@ -28,6 +28,13 @@ use generalized_bulletproofs_ec_gadgets::*;
#[cfg(test)]
mod tests;
/*
The following circuit has two roles.
1) Generating every coefficient used in the DKG, per the eVRF paper, using the fixed eVRF key.
*/
/// A curve to perform the eVRF with.
pub trait EvrfCurve: Ciphersuite {
type EmbeddedCurve: Ciphersuite;
@@ -35,13 +42,13 @@ pub trait EvrfCurve: Ciphersuite {
}
/// The result of proving for an eVRF.
pub struct EvrfProveResult<C: Ciphersuite> {
pub scalars: Vec<Zeroizing<C::F>>,
pub proof: Vec<u8>,
pub(crate) struct EvrfProveResult<C: Ciphersuite> {
pub(crate) encrypted_scalars: Vec<C::F>,
pub(crate) proof: Vec<u8>,
}
/// A struct to prove/verify eVRFs with.
pub struct Evrf;
pub(crate) struct Evrf;
impl Evrf {
fn transcript_to_points<C: Ciphersuite>(seed: [u8; 32], quantity: usize) -> Vec<C::G> {
// We need to do two Diffie-Hellman's per point in order to achieve an unbiased result
@@ -182,7 +189,7 @@ impl Evrf {
}
/// Prove a point on an elliptic curve had its discrete logarithm generated via an eVRF.
pub fn prove<C: EvrfCurve>(
pub(crate) fn prove<C: EvrfCurve>(
rng: &mut (impl RngCore + CryptoRng),
generators: &Generators<C>,
evrf_private_key: Zeroizing<<<C as EvrfCurve>::EmbeddedCurve as Ciphersuite>::F>,
@@ -459,7 +466,7 @@ impl Evrf {
// TODO: Dedicated error
/// Verify an eVRF proof, returning the commitments output.
pub fn verify<C: EvrfCurve>(
pub(crate) fn verify<C: EvrfCurve>(
rng: &mut (impl RngCore + CryptoRng),
generators: &Generators<C>,
verifier: &mut BatchVerifier<C>,