Reuse evaluations when computing proofs (#647)
* Reuse precomputed evaluations instead of evaluation polynomial for each proof * kzgrs benchmarks * Clippy happy
This commit is contained in:
parent
cbce61ed9d
commit
a2e3015037
|
@ -94,13 +94,15 @@ impl DaEncoder {
|
|||
|
||||
fn compute_rows_proofs(
|
||||
polynomials: &[Polynomial],
|
||||
evals: &[Evaluations],
|
||||
proof_count: usize,
|
||||
) -> Result<Vec<Vec<Proof>>, KzgRsError> {
|
||||
polynomials
|
||||
.iter()
|
||||
.map(|poly| {
|
||||
.zip(evals)
|
||||
.map(|(poly, eval)| {
|
||||
(0..proof_count)
|
||||
.map(|i| generate_element_proof(i, poly, &GLOBAL_PARAMETERS, *DOMAIN))
|
||||
.map(|i| generate_element_proof(i, poly, eval, &GLOBAL_PARAMETERS, *DOMAIN))
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
|
@ -136,10 +138,11 @@ impl DaEncoder {
|
|||
|
||||
fn compute_aggregated_column_proofs(
|
||||
polynomial: &Polynomial,
|
||||
evals: &Evaluations,
|
||||
proof_count: usize,
|
||||
) -> Result<Vec<Proof>, KzgRsError> {
|
||||
(0..proof_count)
|
||||
.map(|i| generate_element_proof(i, polynomial, &GLOBAL_PARAMETERS, *DOMAIN))
|
||||
.map(|i| generate_element_proof(i, polynomial, evals, &GLOBAL_PARAMETERS, *DOMAIN))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -164,18 +167,23 @@ impl DaEncoder {
|
|||
Self::compute_kzg_row_commitments(&chunked_data)?
|
||||
.into_iter()
|
||||
.unzip();
|
||||
let extended_data =
|
||||
Self::evals_to_chunk_matrix(Self::rs_encode_rows(&row_polynomials).as_ref());
|
||||
let encoded_evaluations = Self::rs_encode_rows(&row_polynomials);
|
||||
let extended_data = Self::evals_to_chunk_matrix(&encoded_evaluations);
|
||||
let row_polynomials: Vec<_> = row_polynomials.into_iter().map(|(_, p)| p).collect();
|
||||
let rows_proofs = Self::compute_rows_proofs(&row_polynomials, self.params.column_count)?;
|
||||
let rows_proofs = Self::compute_rows_proofs(
|
||||
&row_polynomials,
|
||||
&encoded_evaluations,
|
||||
self.params.column_count,
|
||||
)?;
|
||||
let (_column_polynomials, column_commitments): (Vec<_>, Vec<_>) =
|
||||
Self::compute_kzg_column_commitments(&extended_data)?
|
||||
.into_iter()
|
||||
.unzip();
|
||||
let ((_aggregated_evals, aggregated_polynomial), aggregated_column_commitment) =
|
||||
let ((aggregated_evals, aggregated_polynomial), aggregated_column_commitment) =
|
||||
Self::compute_aggregated_column_commitment(&extended_data, &column_commitments)?;
|
||||
let aggregated_column_proofs = Self::compute_aggregated_column_proofs(
|
||||
&aggregated_polynomial,
|
||||
&aggregated_evals,
|
||||
column_commitments.len(),
|
||||
)?;
|
||||
Ok(EncodedData {
|
||||
|
@ -291,13 +299,18 @@ pub mod test {
|
|||
.unwrap()
|
||||
.into_iter()
|
||||
.unzip();
|
||||
let extended_rows = DaEncoder::rs_encode_rows(&poly_data);
|
||||
let (_evals, polynomials): (Vec<_>, Vec<_>) = poly_data.into_iter().unzip();
|
||||
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_rows);
|
||||
let extended_evaluations = DaEncoder::rs_encode_rows(&poly_data);
|
||||
let (evals, polynomials): (Vec<_>, Vec<_>) = poly_data.into_iter().unzip();
|
||||
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_evaluations);
|
||||
let original_proofs =
|
||||
DaEncoder::compute_rows_proofs(&polynomials, PARAMS.column_count.div(2)).unwrap();
|
||||
let extended_proofs =
|
||||
DaEncoder::compute_rows_proofs(&polynomials, PARAMS.column_count).unwrap();
|
||||
DaEncoder::compute_rows_proofs(&polynomials, &evals, PARAMS.column_count.div(2))
|
||||
.unwrap();
|
||||
let extended_proofs = DaEncoder::compute_rows_proofs(
|
||||
&polynomials,
|
||||
&extended_evaluations,
|
||||
PARAMS.column_count,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let checks = izip!(matrix.iter(), &commitments, &original_proofs);
|
||||
for (row, commitment, proofs) in checks {
|
||||
|
@ -359,8 +372,9 @@ pub mod test {
|
|||
.unwrap()
|
||||
.into_iter()
|
||||
.unzip();
|
||||
let ((_, polynomial), _aggregated_commitment) =
|
||||
let ((evals, polynomial), _aggregated_commitment) =
|
||||
DaEncoder::compute_aggregated_column_commitment(&matrix, &commitments).unwrap();
|
||||
DaEncoder::compute_aggregated_column_proofs(&polynomial, commitments.len()).unwrap();
|
||||
DaEncoder::compute_aggregated_column_proofs(&polynomial, &evals, commitments.len())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ mod test {
|
|||
bytes_to_polynomial::<BYTES_PER_FIELD_ELEMENT>(column.as_bytes().as_slice(), *DOMAIN)
|
||||
.unwrap();
|
||||
let column_commitment = commit_polynomial(&column_poly, &GLOBAL_PARAMETERS).unwrap();
|
||||
let (_, aggregated_poly) = bytes_to_polynomial::<
|
||||
let (aggregated_evals, aggregated_poly) = bytes_to_polynomial::<
|
||||
{ DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE },
|
||||
>(
|
||||
hash_column_and_commitment::<{ DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE }>(
|
||||
|
@ -192,8 +192,14 @@ mod test {
|
|||
.unwrap();
|
||||
let aggregated_commitment =
|
||||
commit_polynomial(&aggregated_poly, &GLOBAL_PARAMETERS).unwrap();
|
||||
let column_proof =
|
||||
generate_element_proof(0, &aggregated_poly, &GLOBAL_PARAMETERS, *DOMAIN).unwrap();
|
||||
let column_proof = generate_element_proof(
|
||||
0,
|
||||
&aggregated_poly,
|
||||
&aggregated_evals,
|
||||
&GLOBAL_PARAMETERS,
|
||||
*DOMAIN,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(DaVerifier::verify_column(
|
||||
&column,
|
||||
&column_commitment,
|
||||
|
|
|
@ -17,4 +17,11 @@ ark-serialize = { version = "0.4" }
|
|||
num-bigint = "0.4.4"
|
||||
thiserror = "1.0.58"
|
||||
num-traits = "0.2.18"
|
||||
rand = "0.8.5"
|
||||
rand = "0.8.5"
|
||||
|
||||
[dev-dependencies]
|
||||
divan = "0.1"
|
||||
|
||||
[[bench]]
|
||||
name = "kzg"
|
||||
harness = false
|
|
@ -0,0 +1,90 @@
|
|||
use ark_bls12_381::{Bls12_381, Fr};
|
||||
use ark_poly::univariate::DensePolynomial;
|
||||
use ark_poly::{EvaluationDomain, GeneralEvaluationDomain};
|
||||
use ark_poly_commit::kzg10::{UniversalParams, KZG10};
|
||||
use divan::counter::ItemsCount;
|
||||
use divan::{black_box, counter::BytesCount, AllocProfiler, Bencher};
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::RngCore;
|
||||
|
||||
use kzgrs::{common::bytes_to_polynomial_unchecked, kzg::*};
|
||||
|
||||
fn main() {
|
||||
divan::main()
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOC: AllocProfiler = AllocProfiler::system();
|
||||
|
||||
static GLOBAL_PARAMETERS: Lazy<UniversalParams<Bls12_381>> = Lazy::new(|| {
|
||||
let mut rng = rand::thread_rng();
|
||||
KZG10::<Bls12_381, DensePolynomial<Fr>>::setup(1024, true, &mut rng).unwrap()
|
||||
});
|
||||
|
||||
static DOMAIN: Lazy<GeneralEvaluationDomain<Fr>> =
|
||||
Lazy::new(|| GeneralEvaluationDomain::new(1024).unwrap());
|
||||
|
||||
fn rand_data_elements(elements_count: usize, chunk_size: usize) -> Vec<u8> {
|
||||
let mut buff = vec![0u8; elements_count * chunk_size];
|
||||
rand::thread_rng().fill_bytes(&mut buff);
|
||||
buff
|
||||
}
|
||||
|
||||
const CHUNK_SIZE: usize = 31;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[divan::bench(args = [10, 100, 1000])]
|
||||
fn commit_polynomial_with_element_count(bencher: Bencher, element_count: usize) {
|
||||
bencher
|
||||
.with_inputs(|| {
|
||||
let data = rand_data_elements(element_count, CHUNK_SIZE);
|
||||
bytes_to_polynomial_unchecked::<CHUNK_SIZE>(&data, *DOMAIN)
|
||||
})
|
||||
.input_counter(move |(_evals, _poly)| BytesCount::new(element_count * CHUNK_SIZE))
|
||||
.bench_refs(|(_evals, poly)| black_box(commit_polynomial(poly, &GLOBAL_PARAMETERS)));
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[divan::bench]
|
||||
fn compute_single_proof(bencher: Bencher) {
|
||||
bencher
|
||||
.with_inputs(|| {
|
||||
let data = rand_data_elements(10, CHUNK_SIZE);
|
||||
bytes_to_polynomial_unchecked::<CHUNK_SIZE>(&data, *DOMAIN)
|
||||
})
|
||||
.input_counter(|_| ItemsCount::new(1usize))
|
||||
.bench_refs(|(evals, poly)| {
|
||||
black_box(generate_element_proof(
|
||||
7,
|
||||
poly,
|
||||
evals,
|
||||
&GLOBAL_PARAMETERS,
|
||||
*DOMAIN,
|
||||
))
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[divan::bench]
|
||||
fn verify_single_proof(bencher: Bencher) {
|
||||
bencher
|
||||
.with_inputs(|| {
|
||||
let data = rand_data_elements(10, CHUNK_SIZE);
|
||||
let (eval, poly) = bytes_to_polynomial_unchecked::<CHUNK_SIZE>(&data, *DOMAIN);
|
||||
let commitment = commit_polynomial(&poly, &GLOBAL_PARAMETERS).unwrap();
|
||||
let proof =
|
||||
generate_element_proof(0, &poly, &eval, &GLOBAL_PARAMETERS, *DOMAIN).unwrap();
|
||||
(0usize, eval.evals[0], commitment, proof)
|
||||
})
|
||||
.input_counter(|_| ItemsCount::new(1usize))
|
||||
.bench_refs(|(index, elemnent, commitment, proof)| {
|
||||
black_box(verify_element_proof(
|
||||
index.clone(),
|
||||
elemnent,
|
||||
commitment,
|
||||
proof,
|
||||
*DOMAIN,
|
||||
&GLOBAL_PARAMETERS,
|
||||
))
|
||||
});
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use crate::common::KzgRsError;
|
||||
use crate::Evaluations;
|
||||
use ark_bls12_381::{Bls12_381, Fr};
|
||||
use ark_ec::pairing::Pairing;
|
||||
use ark_poly::univariate::DensePolynomial;
|
||||
use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain, Polynomial};
|
||||
use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain};
|
||||
use ark_poly_commit::kzg10::{Commitment, Powers, Proof, UniversalParams, KZG10};
|
||||
use num_traits::One;
|
||||
use std::borrow::Cow;
|
||||
|
@ -27,11 +28,14 @@ pub fn commit_polynomial(
|
|||
pub fn generate_element_proof(
|
||||
element_index: usize,
|
||||
polynomial: &DensePolynomial<Fr>,
|
||||
evaluations: &Evaluations,
|
||||
global_parameters: &UniversalParams<Bls12_381>,
|
||||
domain: GeneralEvaluationDomain<Fr>,
|
||||
) -> Result<Proof<Bls12_381>, KzgRsError> {
|
||||
let u = domain.element(element_index);
|
||||
let v = polynomial.evaluate(&u);
|
||||
// Instead of evaluating over the polynomial, we can reuse the evaluation points from the rs encoding
|
||||
// let v = polynomial.evaluate(&u);
|
||||
let v = evaluations.evals[element_index];
|
||||
let f_x_v = polynomial + &DensePolynomial::<Fr>::from_coefficients_vec(vec![-v]);
|
||||
let x_u = DensePolynomial::<Fr>::from_coefficients_vec(vec![-u, Fr::one()]);
|
||||
let witness_polynomial: DensePolynomial<_> = &f_x_v / &x_u;
|
||||
|
@ -100,10 +104,10 @@ mod test {
|
|||
let mut rng = thread_rng();
|
||||
bytes.try_fill(&mut rng).unwrap();
|
||||
let evaluations = bytes_to_evaluations::<31>(&bytes, *DOMAIN).evals;
|
||||
let (_, poly) = bytes_to_polynomial::<31>(&bytes, *DOMAIN).unwrap();
|
||||
let (eval, poly) = bytes_to_polynomial::<31>(&bytes, *DOMAIN).unwrap();
|
||||
let commitment = commit_polynomial(&poly, &GLOBAL_PARAMETERS).unwrap();
|
||||
let proofs: Vec<_> = (0..10)
|
||||
.map(|i| generate_element_proof(i, &poly, &GLOBAL_PARAMETERS, *DOMAIN).unwrap())
|
||||
.map(|i| generate_element_proof(i, &poly, &eval, &GLOBAL_PARAMETERS, *DOMAIN).unwrap())
|
||||
.collect();
|
||||
for (i, (element, proof)) in evaluations.iter().zip(proofs.iter()).enumerate() {
|
||||
// verifying works
|
||||
|
|
Loading…
Reference in New Issue