mirror of
https://github.com/arnaucube/hyperplonk.git
synced 2026-01-10 16:11:29 +01:00
optimize uni poly interpolation (#19)
This commit is contained in:
@@ -26,8 +26,8 @@ path = "benches/bench.rs"
|
|||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# default = [ "parallel", "print-trace" ]
|
default = [ "parallel", "print-trace" ]
|
||||||
default = [ "parallel" ]
|
# default = [ "parallel" ]
|
||||||
parallel = [
|
parallel = [
|
||||||
"rayon",
|
"rayon",
|
||||||
"ark-std/parallel",
|
"ark-std/parallel",
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
self.max_degree + 1
|
self.max_degree + 1
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Ok(interpolate_uni_poly::<F>(&evaluations, challenge))
|
interpolate_uni_poly::<F>(&evaluations, challenge)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
self.max_degree + 1
|
self.max_degree + 1
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Ok(interpolate_uni_poly::<F>(&evaluations, challenge))
|
interpolate_uni_poly::<F>(&evaluations, challenge)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
||||||
// insert the asserted_sum to the first position of the expected vector
|
// insert the asserted_sum to the first position of the expected vector
|
||||||
@@ -162,23 +162,75 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Interpolate a uni-variate degree-`p_i.len()-1` polynomial and evaluate this
|
/// Interpolate a uni-variate degree-`p_i.len()-1` polynomial and evaluate this
|
||||||
/// polynomial at `eval_at`.
|
/// polynomial at `eval_at`:
|
||||||
pub(crate) fn interpolate_uni_poly<F: PrimeField>(p_i: &[F], eval_at: F) -> F {
|
/// \sum_{i=0}^len p_i * (\prod_{j!=i} (eval_at - j)/(i-j) )
|
||||||
let start = start_timer!(|| "sum check interpolate uni poly");
|
/// This implementation is linear in number of inputs in terms of field
|
||||||
let mut result = F::zero();
|
/// operations. It also has a quadratic term in primitive operations which is
|
||||||
let mut i = F::zero();
|
/// negligible compared to field operations.
|
||||||
for term in p_i.iter() {
|
pub(crate) fn interpolate_uni_poly<F: PrimeField>(
|
||||||
let mut term = *term;
|
p_i: &[F],
|
||||||
let mut j = F::zero();
|
eval_at: F,
|
||||||
for _ in 0..p_i.len() {
|
) -> Result<F, PolyIOPErrors> {
|
||||||
if j != i {
|
let start = start_timer!(|| "sum check interpolate uni poly opt");
|
||||||
term = term * (eval_at - j) / (i - j)
|
|
||||||
}
|
let mut res = F::zero();
|
||||||
j += F::one();
|
|
||||||
}
|
// prod = \prod_{j!=i} (eval_at - j)
|
||||||
i += F::one();
|
let mut evals = vec![];
|
||||||
result += term;
|
let len = p_i.len();
|
||||||
|
let mut prod = eval_at;
|
||||||
|
evals.push(eval_at);
|
||||||
|
|
||||||
|
for e in 1..len {
|
||||||
|
let tmp = eval_at - F::from(e as u64);
|
||||||
|
evals.push(tmp);
|
||||||
|
prod *= tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 0..len {
|
||||||
|
let divisor = get_divisor(i, len)?;
|
||||||
|
let divisor_f = {
|
||||||
|
if divisor < 0 {
|
||||||
|
-F::from((-divisor) as u128)
|
||||||
|
} else {
|
||||||
|
F::from(divisor as u128)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
res += p_i[i] * prod / (divisor_f * evals[i]);
|
||||||
|
}
|
||||||
|
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
result
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute \prod_{j!=i)^len (i-j). This function takes O(n^2) number of
|
||||||
|
/// primitive operations which is negligible compared to field operations.
|
||||||
|
// We know
|
||||||
|
// - factorial(20) ~ 2^61
|
||||||
|
// - factorial(33) ~ 2^123
|
||||||
|
// so we will be able to store the result for len<=20 with i64;
|
||||||
|
// for len<=33 with i128; and we do not currently support len>33.
|
||||||
|
#[inline]
|
||||||
|
fn get_divisor(i: usize, len: usize) -> Result<i128, PolyIOPErrors> {
|
||||||
|
if len <= 20 {
|
||||||
|
let mut res = 1i64;
|
||||||
|
for j in 0..len {
|
||||||
|
if j != i {
|
||||||
|
res *= i as i64 - j as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(res as i128)
|
||||||
|
} else if len <= 33 {
|
||||||
|
let mut res = 1i128;
|
||||||
|
for j in 0..len {
|
||||||
|
if j != i {
|
||||||
|
res *= i as i128 - j as i128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
Err(PolyIOPErrors::InvalidParameters(
|
||||||
|
"Do not support number variable > 33".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ impl<F: PrimeField> VirtualPolynomial<F> {
|
|||||||
num_products: usize,
|
num_products: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self, F), PolyIOPErrors> {
|
) -> Result<(Self, F), PolyIOPErrors> {
|
||||||
let start = start_timer!("sample random virtual polynomial");
|
let start = start_timer!(|| "sample random virtual polynomial");
|
||||||
|
|
||||||
let mut sum = F::zero();
|
let mut sum = F::zero();
|
||||||
let mut poly = VirtualPolynomial::new(nv);
|
let mut poly = VirtualPolynomial::new(nv);
|
||||||
@@ -252,7 +252,7 @@ fn random_mle_list<F: PrimeField, R: RngCore>(
|
|||||||
degree: usize,
|
degree: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (Vec<Rc<DenseMultilinearExtension<F>>>, F) {
|
) -> (Vec<Rc<DenseMultilinearExtension<F>>>, F) {
|
||||||
let start = start_timer!("sample random mle list");
|
let start = start_timer!(|| "sample random mle list");
|
||||||
let mut multiplicands = Vec::with_capacity(degree);
|
let mut multiplicands = Vec::with_capacity(degree);
|
||||||
for _ in 0..degree {
|
for _ in 0..degree {
|
||||||
multiplicands.push(Vec::with_capacity(1 << nv))
|
multiplicands.push(Vec::with_capacity(1 << nv))
|
||||||
@@ -285,7 +285,7 @@ pub fn random_zero_mle_list<F: PrimeField, R: RngCore>(
|
|||||||
degree: usize,
|
degree: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Vec<Rc<DenseMultilinearExtension<F>>> {
|
) -> Vec<Rc<DenseMultilinearExtension<F>>> {
|
||||||
let start = start_timer!("sample random zero mle list");
|
let start = start_timer!(|| "sample random zero mle list");
|
||||||
|
|
||||||
let mut multiplicands = Vec::with_capacity(degree);
|
let mut multiplicands = Vec::with_capacity(degree);
|
||||||
for _ in 0..degree {
|
for _ in 0..degree {
|
||||||
|
|||||||
Reference in New Issue
Block a user