mirror of https://github.com/zcash/halo2.git
Compare commits
6 Commits
5252810196
...
d223584f86
Author | SHA1 | Date |
---|---|---|
str4d | d223584f86 | |
Daira-Emma Hopwood | 7df93fd855 | |
adria0 | daaa638966 | |
Daira-Emma Hopwood | 81729eca91 | |
Daira-Emma Hopwood | 4a8e640afd | |
Jack Grigg | 3836b6e327 |
|
@ -12,7 +12,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: '1.76.0'
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
# - name: Setup mdBook
|
# - name: Setup mdBook
|
||||||
|
@ -26,7 +26,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: install
|
command: install
|
||||||
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 62e01b34c23b957579c04ee1b24b57814ed8a4d5
|
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 5830c9555a4dc051675d17f1fcb04dd0920543e8
|
||||||
|
|
||||||
- name: Install mdbook-katex and mdbook-pdf
|
- name: Install mdbook-katex and mdbook-pdf
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
@ -40,6 +40,11 @@ jobs:
|
||||||
- name: Build halo2 book
|
- name: Build halo2 book
|
||||||
run: mdbook build book/
|
run: mdbook build book/
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly-2023-10-05
|
||||||
|
override: true
|
||||||
|
|
||||||
- name: Build latest rustdocs
|
- name: Build latest rustdocs
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# halo2 [![Crates.io](https://img.shields.io/crates/v/halo2.svg)](https://crates.io/crates/halo2) #
|
# halo2
|
||||||
|
|
||||||
## [Documentation](https://docs.rs/halo2)
|
## Usage
|
||||||
|
|
||||||
|
This repository contains the [halo2_proofs](halo2_proofs/README.md) and
|
||||||
|
[halo2_gadgets](halo2_gadgets/README.md) crates, which should be used directly.
|
||||||
|
|
||||||
## Minimum Supported Rust Version
|
## Minimum Supported Rust Version
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@ title = "The halo2 Book"
|
||||||
macros = "macros.txt"
|
macros = "macros.txt"
|
||||||
renderers = ["html"]
|
renderers = ["html"]
|
||||||
|
|
||||||
[output.katex]
|
|
||||||
|
|
||||||
[output.html]
|
[output.html]
|
||||||
|
|
||||||
[output.html.print]
|
[output.html.print]
|
||||||
|
|
|
@ -54,6 +54,7 @@ blake2b_simd = "1"
|
||||||
maybe-rayon = {version = "0.1.0", default-features = false}
|
maybe-rayon = {version = "0.1.0", default-features = false}
|
||||||
|
|
||||||
# Developer tooling dependencies
|
# Developer tooling dependencies
|
||||||
|
criterion = { version = "0.3", optional = true }
|
||||||
plotters = { version = "0.3.0", default-features = false, optional = true }
|
plotters = { version = "0.3.0", default-features = false, optional = true }
|
||||||
tabbycat = { version = "0.1", features = ["attributes"], optional = true }
|
tabbycat = { version = "0.1", features = ["attributes"], optional = true }
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ getrandom = { version = "0.2", features = ["js"] }
|
||||||
[features]
|
[features]
|
||||||
default = ["batch", "multicore"]
|
default = ["batch", "multicore"]
|
||||||
multicore = ["maybe-rayon/threads"]
|
multicore = ["maybe-rayon/threads"]
|
||||||
|
dev-cost = ["criterion"]
|
||||||
dev-graph = ["plotters", "tabbycat"]
|
dev-graph = ["plotters", "tabbycat"]
|
||||||
test-dev-graph = [
|
test-dev-graph = [
|
||||||
"dev-graph",
|
"dev-graph",
|
||||||
|
|
|
@ -3,13 +3,16 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp,
|
cmp,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
iter,
|
iter::{self, Sum},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Add, Mul},
|
ops::{Add, Mul},
|
||||||
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::prime::PrimeGroup;
|
use group::{prime::PrimeGroup, Group};
|
||||||
|
use pasta_curves::arithmetic::{CurveAffine, CurveExt};
|
||||||
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
circuit::{layouter::RegionColumn, Value},
|
circuit::{layouter::RegionColumn, Value},
|
||||||
|
@ -20,6 +23,8 @@ use crate::{
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod time;
|
||||||
|
|
||||||
/// Measures a circuit to determine its costs, and explain what contributes to them.
|
/// Measures a circuit to determine its costs, and explain what contributes to them.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -28,8 +33,12 @@ pub struct CircuitCost<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> {
|
||||||
k: u32,
|
k: u32,
|
||||||
/// Maximum degree of the circuit.
|
/// Maximum degree of the circuit.
|
||||||
max_deg: usize,
|
max_deg: usize,
|
||||||
|
/// Number of instance columns.
|
||||||
|
instance_columns: usize,
|
||||||
/// Number of advice columns.
|
/// Number of advice columns.
|
||||||
advice_columns: usize,
|
advice_columns: usize,
|
||||||
|
/// Costs of the gate expressions.
|
||||||
|
gate_expressions: Vec<time::ExpressionCost>,
|
||||||
/// Number of direct queries for each column type.
|
/// Number of direct queries for each column type.
|
||||||
instance_queries: usize,
|
instance_queries: usize,
|
||||||
advice_queries: usize,
|
advice_queries: usize,
|
||||||
|
@ -38,8 +47,8 @@ pub struct CircuitCost<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> {
|
||||||
lookups: usize,
|
lookups: usize,
|
||||||
/// Number of columns in the global permutation.
|
/// Number of columns in the global permutation.
|
||||||
permutation_cols: usize,
|
permutation_cols: usize,
|
||||||
/// Number of distinct sets of points in the multiopening argument.
|
/// Size of each distinct sets of points in the multiopening argument.
|
||||||
point_sets: usize,
|
point_sets: Vec<usize>,
|
||||||
/// Maximum rows used over all columns
|
/// Maximum rows used over all columns
|
||||||
max_rows: usize,
|
max_rows: usize,
|
||||||
/// Maximum rows used over all advice columns
|
/// Maximum rows used over all advice columns
|
||||||
|
@ -274,6 +283,27 @@ impl<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> CircuitCost<G, Concrete
|
||||||
|
|
||||||
assert!((1 << k) >= cs.minimum_rows());
|
assert!((1 << k) >= cs.minimum_rows());
|
||||||
|
|
||||||
|
// Measure the gate expressions.
|
||||||
|
let gate_expressions = cs
|
||||||
|
.gates
|
||||||
|
.iter()
|
||||||
|
.flat_map(move |gate| {
|
||||||
|
gate.polynomials().iter().map(move |poly| {
|
||||||
|
poly.evaluate(
|
||||||
|
&|_| (0, 0, 0).into(),
|
||||||
|
&|_| panic!("virtual selectors are removed during optimization"),
|
||||||
|
&|_, _, _| (0, 0, 0).into(),
|
||||||
|
&|_, _, _| (0, 0, 0).into(),
|
||||||
|
&|_, _, _| (0, 0, 0).into(),
|
||||||
|
&|a| a,
|
||||||
|
&|a, b| a + b + (1, 0, 0).into(),
|
||||||
|
&|a, b| a + b + (0, 1, 0).into(),
|
||||||
|
&|a, _| a + (0, 0, 1).into(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Figure out how many point sets we have due to queried cells.
|
// Figure out how many point sets we have due to queried cells.
|
||||||
let mut column_queries: HashMap<Column<Any>, HashSet<i32>> = HashMap::new();
|
let mut column_queries: HashMap<Column<Any>, HashSet<i32>> = HashMap::new();
|
||||||
for (c, r) in iter::empty()
|
for (c, r) in iter::empty()
|
||||||
|
@ -318,13 +348,15 @@ impl<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> CircuitCost<G, Concrete
|
||||||
CircuitCost {
|
CircuitCost {
|
||||||
k,
|
k,
|
||||||
max_deg,
|
max_deg,
|
||||||
|
instance_columns: cs.num_instance_columns,
|
||||||
advice_columns: cs.num_advice_columns,
|
advice_columns: cs.num_advice_columns,
|
||||||
|
gate_expressions,
|
||||||
instance_queries: cs.instance_queries.len(),
|
instance_queries: cs.instance_queries.len(),
|
||||||
advice_queries: cs.advice_queries.len(),
|
advice_queries: cs.advice_queries.len(),
|
||||||
fixed_queries: cs.fixed_queries.len(),
|
fixed_queries: cs.fixed_queries.len(),
|
||||||
lookups: cs.lookups.len(),
|
lookups: cs.lookups.len(),
|
||||||
permutation_cols,
|
permutation_cols,
|
||||||
point_sets: point_sets.len(),
|
point_sets: point_sets.into_iter().map(|set| set.len()).collect(),
|
||||||
_marker: PhantomData::default(),
|
_marker: PhantomData::default(),
|
||||||
max_rows: layout.total_rows,
|
max_rows: layout.total_rows,
|
||||||
max_advice_rows: layout.total_advice_rows,
|
max_advice_rows: layout.total_advice_rows,
|
||||||
|
@ -402,7 +434,7 @@ impl<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> CircuitCost<G, Concrete
|
||||||
// Multiopening argument:
|
// Multiopening argument:
|
||||||
// - f_commitment
|
// - f_commitment
|
||||||
// - 1 eval per set of points in multiopen argument
|
// - 1 eval per set of points in multiopen argument
|
||||||
multiopen: ProofContribution::new(1, self.point_sets),
|
multiopen: ProofContribution::new(1, self.point_sets.len()),
|
||||||
|
|
||||||
// Polycommit:
|
// Polycommit:
|
||||||
// - s_poly commitment
|
// - s_poly commitment
|
||||||
|
@ -417,7 +449,7 @@ impl<G: PrimeGroup, ConcreteCircuit: Circuit<G::Scalar>> CircuitCost<G, Concrete
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (commitments, evaluations)
|
/// (commitments, evaluations)
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct ProofContribution {
|
struct ProofContribution {
|
||||||
commitments: usize,
|
commitments: usize,
|
||||||
evaluations: usize,
|
evaluations: usize,
|
||||||
|
@ -459,7 +491,7 @@ impl Mul<usize> for ProofContribution {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The marginal size of a Halo 2 proof, broken down into its contributing factors.
|
/// The marginal size of a Halo 2 proof, broken down into its contributing factors.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct MarginalProofSize<G: PrimeGroup> {
|
pub struct MarginalProofSize<G: PrimeGroup> {
|
||||||
instance: ProofContribution,
|
instance: ProofContribution,
|
||||||
advice: ProofContribution,
|
advice: ProofContribution,
|
||||||
|
@ -481,7 +513,7 @@ impl<G: PrimeGroup> From<MarginalProofSize<G>> for usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The size of a Halo 2 proof, broken down into its contributing factors.
|
/// The size of a Halo 2 proof, broken down into its contributing factors.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ProofSize<G: PrimeGroup> {
|
pub struct ProofSize<G: PrimeGroup> {
|
||||||
instance: ProofContribution,
|
instance: ProofContribution,
|
||||||
advice: ProofContribution,
|
advice: ProofContribution,
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
use std::{
|
||||||
|
iter::{self, Sum},
|
||||||
|
marker::PhantomData,
|
||||||
|
ops::{Add, Mul},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
use group::{ff::Field, prime::PrimeGroup, Group};
|
||||||
|
use pasta_curves::arithmetic::{CurveAffine, CurveExt};
|
||||||
|
|
||||||
|
use super::{CircuitCost, MarginalProofSize, ProofContribution, ProofSize};
|
||||||
|
use crate::{
|
||||||
|
plonk::Circuit,
|
||||||
|
transcript::{Blake2bRead, Transcript, TranscriptRead},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<C: CurveExt, ConcreteCircuit: Circuit<<C as Group>::Scalar>> CircuitCost<C, ConcreteCircuit> {
|
||||||
|
/// Returns the marginal verifying cost per instance of this circuit.
|
||||||
|
pub fn marginal_verifying(&self) -> MarginalVerifyingCost<C::AffineExt> {
|
||||||
|
let chunks = self.permutation_chunks();
|
||||||
|
|
||||||
|
MarginalVerifyingCost {
|
||||||
|
// Transcript:
|
||||||
|
// - the marginal proof size
|
||||||
|
proof: self.marginal_proof_size(),
|
||||||
|
|
||||||
|
// Cells:
|
||||||
|
// - 1 polynomial commitment per instance column per instance
|
||||||
|
// - 1 commitment per instance column per instance
|
||||||
|
instance_columns: self.instance_columns,
|
||||||
|
|
||||||
|
// Gates:
|
||||||
|
gates: TimeContribution::new(0, self.gate_expressions.iter().copied()),
|
||||||
|
|
||||||
|
// Lookup arguments:
|
||||||
|
// - 7 additions per lookup argument per instance
|
||||||
|
// - 6 multiplications per lookup argument per instance
|
||||||
|
lookups: TimeContribution::new(0, [(1, 1), (1, 2), (1, 1), (4, 2)].into_iter())
|
||||||
|
* self.lookups,
|
||||||
|
|
||||||
|
// Global permutation argument:
|
||||||
|
// - 5 * chunks + 3 additions and multiplications per instance
|
||||||
|
equality: TimeContribution::new(
|
||||||
|
0,
|
||||||
|
[(1, 1)]
|
||||||
|
.into_iter()
|
||||||
|
.chain((0..chunks - 1).map(|_| (1, 1)))
|
||||||
|
.chain((0..chunks).map(|_| (4 * chunks + 3, 4 * chunks + 3))),
|
||||||
|
),
|
||||||
|
|
||||||
|
_marker: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the verifying cost for the given number of instances of this circuit.
|
||||||
|
pub fn verifying(&self, instances: usize) -> VerifyingCost<C::AffineExt> {
|
||||||
|
let marginal = self.marginal_verifying();
|
||||||
|
|
||||||
|
VerifyingCost {
|
||||||
|
// Transcript:
|
||||||
|
// - the proof
|
||||||
|
// - marginal cost per instance
|
||||||
|
proof: self.proof_size(instances),
|
||||||
|
instance_columns: marginal.instance_columns * instances,
|
||||||
|
|
||||||
|
// - Verifying key
|
||||||
|
// - 5 challenges
|
||||||
|
|
||||||
|
// Gates:
|
||||||
|
// - marginal cost per instance
|
||||||
|
gates: marginal.gates * instances,
|
||||||
|
|
||||||
|
// Lookup arguments:
|
||||||
|
// - marginal cost per instance
|
||||||
|
lookups: marginal.lookups * instances,
|
||||||
|
|
||||||
|
// Global permutation argument:
|
||||||
|
// - marginal cost per instance
|
||||||
|
// - TODO: global cost
|
||||||
|
equality: marginal.equality * instances,
|
||||||
|
|
||||||
|
// Vanishing argument:
|
||||||
|
// - expressions + 1 commitments
|
||||||
|
// - 1 random_poly eval
|
||||||
|
vanishing: TimeContribution::new(0, [(1, 1)].into_iter()),
|
||||||
|
|
||||||
|
// Multiopening argument:
|
||||||
|
// - TODO: point set evals
|
||||||
|
// - TODO: Lagrange interpolation per point set
|
||||||
|
// - TODO: inversions
|
||||||
|
// - 2 additions and mults per point in multiopen argument
|
||||||
|
// - 2 additions per set of points in multiopen argument
|
||||||
|
// - 1 multiplication per set of points in multiopen argument
|
||||||
|
multiopen: self
|
||||||
|
.point_sets
|
||||||
|
.iter()
|
||||||
|
.map(|points| TimeContribution::new(0, (2 * points + 2, 2 * points + 1).into()))
|
||||||
|
.sum(),
|
||||||
|
|
||||||
|
// Polycommit:
|
||||||
|
// - s_poly commitment
|
||||||
|
// - inner product argument (2 * k round commitments)
|
||||||
|
// - a
|
||||||
|
// - xi
|
||||||
|
polycomm: ProofContribution::new(1 + 2 * self.k, 2),
|
||||||
|
|
||||||
|
_marker: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The marginal time cost of verifying a specific Halo 2 proof, broken down into its
|
||||||
|
/// contributing factors.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MarginalVerifyingCost<C: CurveAffine> {
|
||||||
|
proof: MarginalProofSize<C::Curve>,
|
||||||
|
instance_columns: usize,
|
||||||
|
gates: TimeContribution,
|
||||||
|
lookups: TimeContribution,
|
||||||
|
equality: TimeContribution,
|
||||||
|
_marker: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveAffine> MarginalVerifyingCost<C> {
|
||||||
|
fn transcript_inputs(&self) -> ProofContribution {
|
||||||
|
self.proof.instance + self.proof.advice + self.proof.lookups + self.proof.equality
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expressions(&self) -> ExpressionCost {
|
||||||
|
iter::empty()
|
||||||
|
.chain(self.gates.expressions.iter())
|
||||||
|
.chain(self.lookups.expressions.iter())
|
||||||
|
.chain(self.equality.expressions.iter())
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates the concrete time cost for verifying this proof.
|
||||||
|
#[cfg(feature = "dev-cost")]
|
||||||
|
pub fn estimate(&self) -> TimeCost {
|
||||||
|
TimeCost::estimate::<C>(
|
||||||
|
self.instance_columns,
|
||||||
|
self.transcript_inputs(),
|
||||||
|
self.expressions(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluates the concrete time cost for verifying this proof.
|
||||||
|
pub fn evaluate(&self, single_field_add: Duration, single_field_mul: Duration) -> TimeCost {
|
||||||
|
TimeCost::evaluate::<C>(
|
||||||
|
self.instance_columns,
|
||||||
|
self.transcript_inputs(),
|
||||||
|
self.expressions(),
|
||||||
|
single_field_add,
|
||||||
|
single_field_mul,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The time cost of verifying a specific Halo 2 proof, broken down into its contributing
|
||||||
|
/// factors.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct VerifyingCost<C: CurveAffine> {
|
||||||
|
proof: ProofSize<C::Curve>,
|
||||||
|
instance_columns: usize,
|
||||||
|
gates: TimeContribution,
|
||||||
|
lookups: TimeContribution,
|
||||||
|
equality: TimeContribution,
|
||||||
|
vanishing: TimeContribution,
|
||||||
|
multiopen: TimeContribution,
|
||||||
|
polycomm: TimeContribution,
|
||||||
|
_marker: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveAffine> VerifyingCost<C> {
|
||||||
|
fn transcript_inputs(&self) -> ProofContribution {
|
||||||
|
// TODO
|
||||||
|
self.proof.instance + self.proof.advice + self.proof.lookups + self.proof.equality
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expressions(&self) -> ExpressionCost {
|
||||||
|
iter::empty()
|
||||||
|
.chain(self.gates.expressions.iter())
|
||||||
|
.chain(self.lookups.expressions.iter())
|
||||||
|
.chain(self.equality.expressions.iter())
|
||||||
|
.chain(self.vanishing.expressions.iter())
|
||||||
|
.chain(self.multiopen.expressions.iter())
|
||||||
|
.chain(self.polycomm.expressions.iter())
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates the concrete time cost for verifying this proof.
|
||||||
|
#[cfg(feature = "dev-cost")]
|
||||||
|
pub fn estimate(&self) -> TimeCost {
|
||||||
|
TimeCost::estimate::<C>(
|
||||||
|
self.instance_columns,
|
||||||
|
self.transcript_inputs(),
|
||||||
|
self.expressions(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluates the concrete time cost for verifying this proof.
|
||||||
|
pub fn evaluate(&self, single_field_add: Duration, single_field_mul: Duration) -> TimeCost {
|
||||||
|
TimeCost::evaluate::<C>(
|
||||||
|
self.instance_columns,
|
||||||
|
self.transcript_inputs(),
|
||||||
|
self.expressions(),
|
||||||
|
single_field_add,
|
||||||
|
single_field_mul,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The estimated time cost of proving or verifying a specific Halo 2 circuit.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct TimeCost {
|
||||||
|
transcript: Duration,
|
||||||
|
expressions: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeCost {
|
||||||
|
#[cfg(feature = "dev-cost")]
|
||||||
|
fn estimate<C: CurveAffine>(
|
||||||
|
instance_columns: usize,
|
||||||
|
transcript_inputs: ProofContribution,
|
||||||
|
expressions: ExpressionCost,
|
||||||
|
) -> Self {
|
||||||
|
use rand_core::OsRng;
|
||||||
|
|
||||||
|
let pairs = [0; 100].map(|_| (C::Scalar::random(OsRng), C::Scalar::random(OsRng)));
|
||||||
|
|
||||||
|
let runner = |f: fn(C::Scalar, C::Scalar) -> C::Scalar| {
|
||||||
|
let start = Instant::now();
|
||||||
|
for _ in 0..100 {
|
||||||
|
for (a, b) in pairs.into_iter() {
|
||||||
|
let _ = criterion::black_box(f(a, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instant::now().duration_since(start) / (100 * pairs.len() as u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
let single_field_add = runner(|a, b| a + b);
|
||||||
|
let single_field_mul = runner(|a, b| a * b);
|
||||||
|
|
||||||
|
Self::evaluate::<C>(
|
||||||
|
instance_columns,
|
||||||
|
transcript_inputs,
|
||||||
|
expressions,
|
||||||
|
single_field_add,
|
||||||
|
single_field_mul,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate<C: CurveAffine>(
|
||||||
|
instance_columns: usize,
|
||||||
|
transcript_inputs: ProofContribution,
|
||||||
|
expressions: ExpressionCost,
|
||||||
|
single_field_add: Duration,
|
||||||
|
single_field_mul: Duration,
|
||||||
|
) -> Self {
|
||||||
|
let dummy_point = C::generator();
|
||||||
|
|
||||||
|
// Transcript cost
|
||||||
|
let transcript = {
|
||||||
|
let mut transcript = Blake2bRead::init(std::io::repeat(1));
|
||||||
|
let start = Instant::now();
|
||||||
|
for _ in 0..instance_columns {
|
||||||
|
let _ = transcript.common_point(dummy_point).unwrap();
|
||||||
|
}
|
||||||
|
for _ in 0..transcript_inputs.commitments {
|
||||||
|
let _ = transcript.read_point().unwrap();
|
||||||
|
}
|
||||||
|
for _ in 0..transcript_inputs.evaluations {
|
||||||
|
let _ = transcript.read_scalar().unwrap();
|
||||||
|
}
|
||||||
|
Instant::now().duration_since(start)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expressions cost
|
||||||
|
let expressions = single_field_add * expressions.add as u32
|
||||||
|
+ single_field_mul * (expressions.mul + expressions.scale) as u32;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
transcript,
|
||||||
|
expressions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the total estimated time cost.
|
||||||
|
pub fn total(&self) -> Duration {
|
||||||
|
self.transcript + self.expressions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(super) struct ExpressionCost {
|
||||||
|
add: usize,
|
||||||
|
mul: usize,
|
||||||
|
scale: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use when multiplications and scalings have the same cost.
|
||||||
|
impl From<(usize, usize)> for ExpressionCost {
|
||||||
|
fn from((add, mul): (usize, usize)) -> Self {
|
||||||
|
Self { add, mul, scale: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(usize, usize, usize)> for ExpressionCost {
|
||||||
|
fn from((add, mul, scale): (usize, usize, usize)) -> Self {
|
||||||
|
Self { add, mul, scale }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for ExpressionCost {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
add: self.add + rhs.add,
|
||||||
|
mul: self.mul + rhs.mul,
|
||||||
|
scale: self.scale + rhs.scale,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Sum<&'a ExpressionCost> for ExpressionCost {
|
||||||
|
fn sum<I: Iterator<Item = &'a ExpressionCost>>(iter: I) -> Self {
|
||||||
|
iter.fold((0, 0, 0).into(), |acc, expr| acc + *expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct TimeContribution {
|
||||||
|
polynomial_commitments: usize,
|
||||||
|
expressions: Vec<ExpressionCost>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeContribution {
|
||||||
|
fn new<E>(polynomial_commitments: usize, expressions: impl Iterator<Item = E>) -> Self
|
||||||
|
where
|
||||||
|
ExpressionCost: From<E>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
polynomial_commitments,
|
||||||
|
expressions: expressions.map(ExpressionCost::from).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for TimeContribution {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, mut rhs: Self) -> Self::Output {
|
||||||
|
let mut expressions = self.expressions;
|
||||||
|
expressions.append(&mut rhs.expressions);
|
||||||
|
Self {
|
||||||
|
polynomial_commitments: self.polynomial_commitments + rhs.polynomial_commitments,
|
||||||
|
expressions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<usize> for TimeContribution {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, instances: usize) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
polynomial_commitments: self.polynomial_commitments * instances,
|
||||||
|
expressions: iter::repeat(self.expressions.into_iter())
|
||||||
|
.take(instances)
|
||||||
|
.flatten()
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sum for TimeContribution {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(
|
||||||
|
TimeContribution {
|
||||||
|
polynomial_commitments: 0,
|
||||||
|
expressions: vec![],
|
||||||
|
},
|
||||||
|
|acc, expr| acc + expr,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue