Skip to content

Commit

Permalink
Proof-Setup: Make benchmarks run over all circuits
Browse files Browse the repository at this point in the history
Probably the more useful benchmarks to run
  • Loading branch information
cronokirby authored and redshiftzero committed Oct 20, 2023
1 parent f5425f7 commit 1d12603
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 117 deletions.
2 changes: 1 addition & 1 deletion crates/crypto/proof-setup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ harness = false

[features]
default = []
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-groth16/parallel", "decaf377/parallel", "rayon"]
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-groth16/parallel", "decaf377/parallel", "rayon", "penumbra-shielded-pool/parallel"]
73 changes: 27 additions & 46 deletions crates/crypto/proof-setup/benches/all.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
use ark_ec::pairing::Pairing;
use ark_relations::r1cs::ConstraintMatrices;
use criterion::{criterion_group, criterion_main, Criterion};
use decaf377::Bls12_377;
use rand_core::OsRng;

use penumbra_dex::swap_claim::proof::SwapClaimCircuit;
use penumbra_proof_params::generate_constraint_matrices;
use penumbra_proof_setup::single::{
circuit_degree,
log::{ContributionHash, Hashable},
transition, ExtraTransitionInformation, Phase2CRSElements, Phase2Contribution,
Phase2RawContribution, {Phase1CRSElements, Phase1Contribution, Phase1RawContribution},
use penumbra_proof_setup::all::{
transition, AllExtraTransitionInformation, Phase1CeremonyCRS, Phase1CeremonyContribution,
Phase1RawCeremonyContribution, Phase2CeremonyCRS, Phase2CeremonyContribution,
Phase2RawCeremonyContribution,
};

fn run_phase1(parent: ContributionHash, old: &Phase1CRSElements) -> Phase1Contribution {
Phase1Contribution::make(&mut OsRng, parent, old)
fn run_phase1(old: &Phase1CeremonyCRS) -> Phase1CeremonyContribution {
Phase1CeremonyContribution::make(old)
}

fn check_phase1(contribution: &Phase1RawContribution, parent: &Phase1CRSElements) -> bool {
let validated_contribution = contribution.validate(&mut OsRng);
fn check_phase1(contribution: Phase1RawCeremonyContribution, parent: &Phase1CeremonyCRS) -> bool {
let validated_contribution = contribution.validate();
if validated_contribution.is_none() {
return false;
}
Expand All @@ -28,22 +20,21 @@ fn check_phase1(contribution: &Phase1RawContribution, parent: &Phase1CRSElements
}

fn run_phase_transition(
phase1: &Phase1CRSElements,
circuit: &ConstraintMatrices<<Bls12_377 as Pairing>::ScalarField>,
) -> anyhow::Result<(ExtraTransitionInformation, Phase2CRSElements)> {
transition(phase1, circuit)
phase1: &Phase1CeremonyCRS,
) -> anyhow::Result<(AllExtraTransitionInformation, Phase2CeremonyCRS)> {
transition(phase1)
}

fn run_phase2(parent: ContributionHash, old: &Phase2CRSElements) -> Phase2Contribution {
Phase2Contribution::make(&mut OsRng, parent, old)
fn run_phase2(old: &Phase2CeremonyCRS) -> Phase2CeremonyContribution {
Phase2CeremonyContribution::make(old)
}

fn check_phase2(
contribution: Phase2RawContribution,
root: &Phase2CRSElements,
parent: &Phase2CRSElements,
contribution: Phase2RawCeremonyContribution,
root: &Phase2CeremonyCRS,
parent: &Phase2CeremonyCRS,
) -> bool {
let validated_contribution = contribution.validate(&mut OsRng, root);
let validated_contribution = contribution.validate(root);
if validated_contribution.is_none() {
return false;
}
Expand All @@ -53,39 +44,29 @@ fn check_phase2(
}

fn benchmarks(c: &mut Criterion) {
// Generate contribution for degree = 37,061, which gets rounded up to next power of 2.
// (size of largest proof)
let matrices = generate_constraint_matrices::<SwapClaimCircuit>();
let d = circuit_degree(&matrices).expect("failed to calculate circuit degree");

let root = Phase1CRSElements::root(d);
let root_hash = root.hash();

let phase1out = run_phase1(root_hash, &root);
c.bench_function("phase 1", |b| b.iter(|| run_phase1(root_hash, &root)));
let root = Phase1CeremonyCRS::root().unwrap();
let phase1out = run_phase1(&root);
c.bench_function("phase 1", |b| b.iter(|| run_phase1(&root)));
c.bench_function("phase 1 check", |b| {
b.iter(|| check_phase1(&phase1out.clone().into(), &root))
b.iter(|| check_phase1(phase1out.clone().into(), &root))
});

let (_, phase2root) = run_phase_transition(&phase1out.new_elements, &matrices)
.expect("failed to perform transition");
let phase2root_hash = phase2root.hash();
let (_, phase2root) =
run_phase_transition(&phase1out.new_elements()).expect("failed to perform transition");
c.bench_function("phase transition", |b| {
b.iter(|| run_phase_transition(&phase1out.new_elements, &matrices))
b.iter(|| run_phase_transition(&phase1out.new_elements()))
});

let phase2out = run_phase2(phase2root_hash, &phase2root);
c.bench_function("phase 2", |b| {
b.iter(|| run_phase2(phase2root_hash, &phase2root))
});
let phase2out = run_phase2(&phase2root);
c.bench_function("phase 2", |b| b.iter(|| run_phase2(&phase2root)));
c.bench_function("phase 2 check", |b| {
b.iter(|| check_phase2(phase2out.clone().into(), &phase2root, &phase2root))
});
}

criterion_group! {
name = benches;
config = Criterion::default().sample_size(10);
config = Criterion::default().sample_size(2);
targets = benchmarks
}
criterion_main!(benches);
40 changes: 2 additions & 38 deletions crates/crypto/proof-setup/src/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! along with the corresponding protobufs.
use std::array;

use crate::parallel_utils::{flatten_results, transform, transform_parallel};
use crate::single::{
self, circuit_degree, group::F, log::ContributionHash, DLogProof, ExtraTransitionInformation,
LinkingProof, Phase1CRSElements, Phase1Contribution, Phase1RawCRSElements,
Expand Down Expand Up @@ -42,43 +43,6 @@ fn from_bytes_unchecked<T: CanonicalDeserialize>(data: &[u8]) -> Result<T> {

pub const NUM_CIRCUITS: usize = 7;

fn transform<A, B>(data: [A; NUM_CIRCUITS], f: impl Fn(A) -> B) -> [B; NUM_CIRCUITS] {
match data.into_iter().map(f).collect::<Vec<B>>().try_into() {
Ok(x) => x,
_ => panic!("The size of the iterator should not have changed"),
}
}

#[cfg(not(feature = "parallel"))]
fn transform_parallel<A, B>(data: [A; NUM_CIRCUITS], f: impl Fn(A) -> B) -> [B; NUM_CIRCUITS] {
transform(data, f)
}

#[cfg(feature = "parallel")]
fn transform_parallel<A: Send, B: Sync + Send, const N: usize>(
data: [A; N],
f: impl Fn(A) -> B + Sync + Send,
) -> [B; N] {
use rayon::prelude::*;
let out: Vec<B> = data.into_par_iter().map(f).collect();
// Note: we do it this way because we don't have a Debug implementation for B
match out.try_into() {
Ok(x) => x,
_ => panic!("The size of the iterator should not have changed"),
}
}

fn flatten_results<A, const N: usize>(data: [Result<A>; N]) -> Result<[A; N]> {
let mut buf = Vec::with_capacity(N);
for x in data {
buf.push(x?);
}
match buf.try_into() {
Ok(x) => Ok(x),
_ => panic!("The size of the iterator should not have changed"),
}
}

/// Generate all of the circuits as matrices.
fn circuits() -> [ConstraintMatrices<F>; NUM_CIRCUITS] {
[
Expand Down Expand Up @@ -596,7 +560,7 @@ impl Phase1RawCeremonyContribution {
/// step you want to do.
pub fn validate(self) -> Option<Phase1CeremonyContribution> {
let out = transform_parallel(self.0, |x| {
x.validate(&mut OsRng).ok_or(anyhow!("failed to validate"))
x.validate().ok_or(anyhow!("failed to validate"))
});
Some(Phase1CeremonyContribution(flatten_results(out).ok()?))
}
Expand Down
1 change: 1 addition & 0 deletions crates/crypto/proof-setup/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod all;
mod parallel_utils;
pub mod single;
36 changes: 36 additions & 0 deletions crates/crypto/proof-setup/src/parallel_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pub fn transform<A, B, const N: usize>(data: [A; N], f: impl Fn(A) -> B) -> [B; N] {
match data.into_iter().map(f).collect::<Vec<B>>().try_into() {
Ok(x) => x,
_ => panic!("The size of the iterator should not have changed"),
}
}

#[cfg(not(feature = "parallel"))]
pub fn transform_parallel<A, B, const N: usize>(data: [A; N], f: impl Fn(A) -> B) -> [B; N] {
transform(data, f)
}

#[cfg(feature = "parallel")]
pub fn transform_parallel<A: Send, B: Sync + Send, const N: usize>(
data: [A; N],
f: impl Fn(A) -> B + Sync + Send,
) -> [B; N] {
use rayon::prelude::*;
let out: Vec<B> = data.into_par_iter().map(f).collect();
// Note: we do it this way because we don't have a Debug implementation for B
match out.try_into() {
Ok(x) => x,
_ => panic!("The size of the iterator should not have changed"),
}
}

pub fn flatten_results<A, E, const N: usize>(data: [Result<A, E>; N]) -> Result<[A; N], E> {
let mut buf = Vec::with_capacity(N);
for x in data {
buf.push(x?);
}
match buf.try_into() {
Ok(x) => Ok(x),
_ => panic!("The size of the iterator should not have changed"),
}
}
66 changes: 34 additions & 32 deletions crates/crypto/proof-setup/src/single/phase1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ark_ff::{One, UniformRand, Zero};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use rand_core::{CryptoRngCore, OsRng};

use crate::parallel_utils::transform_parallel;
use crate::single::dlog;
use crate::single::group::{
pairing, BatchedPairingChecker11, BatchedPairingChecker12, GroupHasher, F, G1, G2,
Expand Down Expand Up @@ -71,7 +72,7 @@ impl RawCRSElements {
/// This checks if the structure of the elements uses the secret scalars
/// hidden behind the group elements correctly.
#[must_use]
pub fn validate<R: CryptoRngCore>(self, rng: &mut R) -> Option<CRSElements> {
pub fn validate(self) -> Option<CRSElements> {
// 0. Check that we can extract a valid degree out of these elements.
let d = self.get_degree()?;
// 1. Check that the elements committing to the secret values are not 0.
Expand All @@ -85,31 +86,22 @@ impl RawCRSElements {
}
// 2. Check that the two beta commitments match.
// 3. Check that the x values match on both groups.
let mut checker = BatchedPairingChecker12::new(G2::generator(), G1::generator());
checker.add(self.beta_1, self.beta_2);
let mut checker0 = BatchedPairingChecker12::new(G2::generator(), G1::generator());
checker0.add(self.beta_1, self.beta_2);
for (&x_1_i, &x_2_i) in self.x_1.iter().zip(self.x_2.iter()) {
checker.add(x_1_i, x_2_i);
}
if !checker.check(rng) {
return None;
checker0.add(x_1_i, x_2_i);
}

// 4. Check that alpha and x are connected in alpha_x.
let mut checker = BatchedPairingChecker12::new(G2::generator(), self.alpha_1);
let mut checker1 = BatchedPairingChecker12::new(G2::generator(), self.alpha_1);
for (&alpha_x_i, &x_i) in self.alpha_x_1.iter().zip(self.x_2.iter()) {
checker.add(alpha_x_i, x_i);
}
if !checker.check(rng) {
return None;
checker1.add(alpha_x_i, x_i);
}
//
// 5. Check that beta and x are connected in beta_x.
let mut checker = BatchedPairingChecker12::new(G2::generator(), self.beta_1);
let mut checker2 = BatchedPairingChecker12::new(G2::generator(), self.beta_1);
for (&beta_x_i, &x_i) in self.beta_x_1.iter().zip(self.x_2.iter()) {
checker.add(beta_x_i, x_i);
}
if !checker.check(rng) {
return None;
checker2.add(beta_x_i, x_i);
}
if !self
.x_2
Expand All @@ -120,11 +112,21 @@ impl RawCRSElements {
return None;
}
// 6. Check that the x_i are the correct powers of x.
let mut checker = BatchedPairingChecker11::new(self.x_2[1], G2::generator());
let mut checker3 = BatchedPairingChecker11::new(self.x_2[1], G2::generator());
for (&x_i, &x_i_plus_1) in self.x_1.iter().zip(self.x_1.iter().skip(1)) {
checker.add(x_i, x_i_plus_1);
checker3.add(x_i, x_i_plus_1);
}
if !checker.check(&mut OsRng) {
// "神だけが私を裁ける"
if transform_parallel(
[Ok(checker0), Ok(checker1), Ok(checker2), Err(checker3)],
|x| match x {
Ok(x) => x.check(&mut OsRng),
Err(x) => x.check(&mut OsRng),
},
)
.iter()
.any(|x| !x)
{
return None;
}

Expand Down Expand Up @@ -240,10 +242,10 @@ pub struct RawContribution {

impl RawContribution {
/// Validate this raw contribution, potentially producing a valid one.
pub fn validate<R: CryptoRngCore>(&self, rng: &mut R) -> Option<Contribution> {
pub fn validate(&self) -> Option<Contribution> {
self.new_elements
.to_owned()
.validate(rng)
.validate()
.map(|new_elements| Contribution {
parent: self.parent,
new_elements,
Expand Down Expand Up @@ -453,7 +455,7 @@ impl Phase for Phase1 {
_root: &Self::CRSElements,
contribution: &Self::RawContribution,
) -> Option<Self::Contribution> {
contribution.validate(&mut OsRng)
contribution.validate()
}

fn is_linked_to(contribution: &Self::Contribution, elements: &Self::CRSElements) -> bool {
Expand Down Expand Up @@ -502,27 +504,27 @@ mod test {
#[test]
fn test_root_crs_is_valid() {
let root = CRSElements::root(D);
assert!(root.raw.validate(&mut OsRng).is_some());
assert!(root.raw.validate().is_some());
}

#[test]
fn test_nontrivial_crs_is_valid() {
let crs = non_trivial_crs();
assert!(crs.validate(&mut OsRng).is_some());
assert!(crs.validate().is_some());
}

#[test]
fn test_changing_alpha_makes_crs_invalid() {
let mut crs = non_trivial_crs();
crs.alpha_1 = G1::generator();
assert!(crs.validate(&mut OsRng).is_none());
assert!(crs.validate().is_none());
}

#[test]
fn test_changing_beta_makes_crs_invalid() {
let mut crs = non_trivial_crs();
crs.beta_1 = G1::generator();
assert!(crs.validate(&mut OsRng).is_none());
assert!(crs.validate().is_none());
}

#[test]
Expand All @@ -532,11 +534,11 @@ mod test {
let x = F::rand(&mut OsRng);

let crs0 = make_crs(F::zero(), beta, x);
assert!(crs0.validate(&mut OsRng).is_none());
assert!(crs0.validate().is_none());
let crs1 = make_crs(alpha, F::zero(), x);
assert!(crs1.validate(&mut OsRng).is_none());
assert!(crs1.validate().is_none());
let crs2 = make_crs(alpha, beta, F::zero());
assert!(crs2.validate(&mut OsRng).is_none());
assert!(crs2.validate().is_none());
}

#[test]
Expand All @@ -559,7 +561,7 @@ mod test {
alpha_x_1: vec![G1::generator() * alpha, G1::generator() * (alpha * x)],
beta_x_1: vec![G1::generator() * beta, G1::generator() * (beta * x)],
};
assert!(crs.validate(&mut OsRng).is_none());
assert!(crs.validate().is_none());
}

#[test]
Expand All @@ -570,7 +572,7 @@ mod test {
ContributionHash([0u8; CONTRIBUTION_HASH_SIZE]),
&root,
);
assert!(contribution.new_elements.raw.validate(&mut OsRng).is_some());
assert!(contribution.new_elements.raw.validate().is_some());
}

#[test]
Expand Down

0 comments on commit 1d12603

Please sign in to comment.