mirror of https://github.com/zcash/halo2.git
halo2_proofs: rename variables for consistency
This changes variable names in the multiopen and commitment opening implementations and the book's protocol description to keep names and indicies consistent with one another. Co-Authored-By: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
parent
b45180273e
commit
a4d3c328b9
|
@ -369,7 +369,7 @@ $$
|
|||
15. $\verifier$ responds with challenge $x_3$.
|
||||
16. $\prover$ sends $\mathbf{u} \in \field^{n_q}$ such that $\mathbf{u}_i = q_i(x_3)$ for all $i \in [0, n_q)$.
|
||||
17. $\verifier$ responds with challenge $x_4$.
|
||||
18. $\prover$ and $\verifier$ set $P = Q' + x_4 \sum\limits_{i=0}^{n_q - 1} [x_4^i] Q_i$ and $v = $
|
||||
18. $\verifier$ set $P = Q' + x_4 \sum\limits_{i=0}^{n_q - 1} [x_4^i] Q_i$ and $v = $
|
||||
$$
|
||||
\sum\limits_{i=0}^{n_q - 1}
|
||||
\left(
|
||||
|
@ -392,12 +392,12 @@ $$
|
|||
19. $\prover$ sets $p(X) = q'(X) + [x_4] \sum\limits_{i=0}^{n_q - 1} x_4^i q_i(X)$.
|
||||
20. $\prover$ samples a random polynomial $s(X)$ of degree $n - 1$ with a root at $x_3$ and sends a commitment $S = \innerprod{\mathbf{s}}{\mathbf{G}} + [\cdot] W$ where $\mathbf{s}$ defines the coefficients of $s(X)$.
|
||||
21. $\verifier$ responds with challenges $\xi, z$.
|
||||
22. $\prover$ and $\verifier$ set $P' = P - [v] \mathbf{G}_0 + [\xi] S$.
|
||||
23. $\prover$ sets $p'(X) = p(X) - v + \xi s(X)$.
|
||||
22. $\verifier$ sets $P' = P - [v] \mathbf{G}_0 + [\xi] S$.
|
||||
23. $\prover$ sets $p'(X) = p(X) - p(x_3) + \xi s(X)$ (where $p(x_3)$ should correspond with the verifier's computed value $v$).
|
||||
24. Initialize $\mathbf{p'}$ as the coefficients of $p'(X)$ and $\mathbf{G'} = \mathbf{G}$ and $\mathbf{b} = (x_3^0, x_3^1, ..., x_3^{n - 1})$. $\prover$ and $\verifier$ will interact in the following $k$ rounds, where in the $j$th round starting in round $j=0$ and ending in round $j=k-1$:
|
||||
* $\prover$ sends $L_j = \innerprod{\mathbf{p'}_\hi}{\mathbf{G'}_\lo} + [z \innerprod{\mathbf{p'}_\hi}{\mathbf{b}_\lo}] U + [\cdot] W$ and $R_j = \innerprod{\mathbf{p'}_\lo}{\mathbf{G'}_\hi} + [z \innerprod{\mathbf{p'}_\lo}{\mathbf{b}_\hi}] U + [\cdot] W$.
|
||||
* $\verifier$ responds with challenge $u_j$.
|
||||
* $\prover$ and $\verifier$ set $\mathbf{G'} := \mathbf{G'}_\lo + u_j \mathbf{G'}_\hi$ and $\mathbf{b} = \mathbf{b}_\lo + u_j \mathbf{b}_\hi$.
|
||||
* $\prover$ and $\verifier$ set $\mathbf{G'} := \mathbf{G'}_\lo + u_j \mathbf{G'}_\hi$ and $\mathbf{b} := \mathbf{b}_\lo + u_j \mathbf{b}_\hi$.
|
||||
* $\prover$ sets $\mathbf{p'} := \mathbf{p'}_\lo + u_j^{-1} \mathbf{p'}_\hi$.
|
||||
25. $\prover$ sends $c = \mathbf{p'}_0$ and synthetic blinding factor $f$.
|
||||
25. $\prover$ sends $c = \mathbf{p'}_0$ and synthetic blinding factor $f$ computed from the elided blinding factors.
|
||||
26. $\verifier$ accepts only if $\sum_{j=0}^{k - 1} [u_j^{-1}] L_j + P' + \sum_{j=0}^{k - 1} [u_j] R_j = [c] \mathbf{G'}_0 + [c \mathbf{b}_0 z] U + [f] W$.
|
||||
|
|
|
@ -30,7 +30,7 @@ pub struct Params<C: CurveAffine> {
|
|||
pub(crate) n: u64,
|
||||
pub(crate) g: Vec<C>,
|
||||
pub(crate) g_lagrange: Vec<C>,
|
||||
pub(crate) h: C,
|
||||
pub(crate) w: C,
|
||||
pub(crate) u: C,
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
};
|
||||
|
||||
let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters");
|
||||
let h = hasher(&[1]).to_affine();
|
||||
let w = hasher(&[1]).to_affine();
|
||||
let u = hasher(&[2]).to_affine();
|
||||
|
||||
Params {
|
||||
|
@ -110,7 +110,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
n,
|
||||
g,
|
||||
g_lagrange,
|
||||
h,
|
||||
w,
|
||||
u,
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
tmp_scalars.push(r.0);
|
||||
|
||||
tmp_bases.extend(self.g.iter());
|
||||
tmp_bases.push(self.h);
|
||||
tmp_bases.push(self.w);
|
||||
|
||||
best_multiexp::<C>(&tmp_scalars, &tmp_bases)
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
tmp_scalars.push(r.0);
|
||||
|
||||
tmp_bases.extend(self.g_lagrange.iter());
|
||||
tmp_bases.push(self.h);
|
||||
tmp_bases.push(self.w);
|
||||
|
||||
best_multiexp::<C>(&tmp_scalars, &tmp_bases)
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
for g_lagrange_element in &self.g_lagrange {
|
||||
writer.write_all(g_lagrange_element.to_bytes().as_ref())?;
|
||||
}
|
||||
writer.write_all(self.h.to_bytes().as_ref())?;
|
||||
writer.write_all(self.w.to_bytes().as_ref())?;
|
||||
writer.write_all(self.u.to_bytes().as_ref())?;
|
||||
|
||||
Ok(())
|
||||
|
@ -188,7 +188,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
|
||||
let g_lagrange: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
|
||||
|
||||
let h = C::read(reader)?;
|
||||
let w = C::read(reader)?;
|
||||
let u = C::read(reader)?;
|
||||
|
||||
Ok(Params {
|
||||
|
@ -196,7 +196,7 @@ impl<C: CurveAffine> Params<C> {
|
|||
n,
|
||||
g,
|
||||
g_lagrange,
|
||||
h,
|
||||
w,
|
||||
u,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use group::Group;
|
|||
pub struct MSM<'a, C: CurveAffine> {
|
||||
pub(crate) params: &'a Params<C>,
|
||||
g_scalars: Option<Vec<C::Scalar>>,
|
||||
h_scalar: Option<C::Scalar>,
|
||||
w_scalar: Option<C::Scalar>,
|
||||
u_scalar: Option<C::Scalar>,
|
||||
other_scalars: Vec<C::Scalar>,
|
||||
other_bases: Vec<C>,
|
||||
|
@ -18,7 +18,7 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
/// Create a new, empty MSM using the provided parameters.
|
||||
pub fn new(params: &'a Params<C>) -> Self {
|
||||
let g_scalars = None;
|
||||
let h_scalar = None;
|
||||
let w_scalar = None;
|
||||
let u_scalar = None;
|
||||
let other_scalars = vec![];
|
||||
let other_bases = vec![];
|
||||
|
@ -26,7 +26,7 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
MSM {
|
||||
params,
|
||||
g_scalars,
|
||||
h_scalar,
|
||||
w_scalar,
|
||||
u_scalar,
|
||||
other_scalars,
|
||||
other_bases,
|
||||
|
@ -42,8 +42,8 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
self.add_to_g_scalars(g_scalars);
|
||||
}
|
||||
|
||||
if let Some(h_scalar) = &other.h_scalar {
|
||||
self.add_to_h_scalar(*h_scalar);
|
||||
if let Some(w_scalar) = &other.w_scalar {
|
||||
self.add_to_w_scalar(*w_scalar);
|
||||
}
|
||||
|
||||
if let Some(u_scalar) = &other.u_scalar {
|
||||
|
@ -83,9 +83,9 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Add to `h_scalar`
|
||||
pub fn add_to_h_scalar(&mut self, scalar: C::Scalar) {
|
||||
self.h_scalar = self.h_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
|
||||
/// Add to `w_scalar`
|
||||
pub fn add_to_w_scalar(&mut self, scalar: C::Scalar) {
|
||||
self.w_scalar = self.w_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
|
||||
}
|
||||
|
||||
/// Add to `u_scalar`
|
||||
|
@ -111,14 +111,14 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
})
|
||||
}
|
||||
|
||||
self.h_scalar = self.h_scalar.map(|a| a * &factor);
|
||||
self.w_scalar = self.w_scalar.map(|a| a * &factor);
|
||||
self.u_scalar = self.u_scalar.map(|a| a * &factor);
|
||||
}
|
||||
|
||||
/// Perform multiexp and check that it results in zero
|
||||
pub fn eval(self) -> bool {
|
||||
let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0)
|
||||
+ self.h_scalar.map(|_| 1).unwrap_or(0)
|
||||
+ self.w_scalar.map(|_| 1).unwrap_or(0)
|
||||
+ self.u_scalar.map(|_| 1).unwrap_or(0)
|
||||
+ self.other_scalars.len();
|
||||
let mut scalars: Vec<C::Scalar> = Vec::with_capacity(len);
|
||||
|
@ -127,9 +127,9 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
|
|||
scalars.extend(&self.other_scalars);
|
||||
bases.extend(&self.other_bases);
|
||||
|
||||
if let Some(h_scalar) = self.h_scalar {
|
||||
scalars.push(h_scalar);
|
||||
bases.push(self.params.h);
|
||||
if let Some(w_scalar) = self.w_scalar {
|
||||
scalars.push(w_scalar);
|
||||
bases.push(self.params.w);
|
||||
}
|
||||
|
||||
if let Some(u_scalar) = self.u_scalar {
|
||||
|
|
|
@ -33,23 +33,23 @@ pub fn create_proof<
|
|||
params: &Params<C>,
|
||||
mut rng: R,
|
||||
transcript: &mut T,
|
||||
px: &Polynomial<C::Scalar, Coeff>,
|
||||
blind: Blind<C::Scalar>,
|
||||
p_poly: &Polynomial<C::Scalar, Coeff>,
|
||||
p_blind: Blind<C::Scalar>,
|
||||
x: C::Scalar,
|
||||
) -> io::Result<()> {
|
||||
// We're limited to polynomials of degree n - 1.
|
||||
assert!(px.len() <= params.n as usize);
|
||||
assert_eq!(p_poly.len(), params.n as usize);
|
||||
|
||||
// Sample a random polynomial (of same degree) that has a root at x, first
|
||||
// by setting all coefficients to random values.
|
||||
let mut s_poly = (*px).clone();
|
||||
let mut s_poly = (*p_poly).clone();
|
||||
for coeff in s_poly.iter_mut() {
|
||||
*coeff = C::Scalar::random(&mut rng);
|
||||
}
|
||||
// Evaluate the random polynomial at x
|
||||
let v_prime = eval_polynomial(&s_poly[..], x);
|
||||
let s_at_x = eval_polynomial(&s_poly[..], x);
|
||||
// Subtract constant coefficient to get a random polynomial with a root at x
|
||||
s_poly[0] = s_poly[0] - &v_prime;
|
||||
s_poly[0] = s_poly[0] - &s_at_x;
|
||||
// And sample a random blind
|
||||
let s_poly_blind = Blind(C::Scalar::random(&mut rng));
|
||||
|
||||
|
@ -60,27 +60,29 @@ pub fn create_proof<
|
|||
// Challenge that will ensure that the prover cannot change P but can only
|
||||
// witness a random polynomial commitment that agrees with P at x, with high
|
||||
// probability.
|
||||
let iota = *transcript.squeeze_challenge_scalar::<()>();
|
||||
let xi = *transcript.squeeze_challenge_scalar::<()>();
|
||||
|
||||
// Challenge that ensures that the prover did not interfere with the U term
|
||||
// in their commitments.
|
||||
let z = *transcript.squeeze_challenge_scalar::<()>();
|
||||
|
||||
// We'll be opening `s_poly_commitment * iota + P - [v] G_0` to ensure it
|
||||
// has a root at zero.
|
||||
let mut final_poly = s_poly * iota + px;
|
||||
let v = eval_polynomial(&final_poly, x);
|
||||
final_poly[0] = final_poly[0] - &v;
|
||||
let blind = s_poly_blind * Blind(iota) + blind;
|
||||
let mut blind = blind.0;
|
||||
// We'll be opening `P' = P - [v] G_0 + [\xi] S` to ensure it has a root at
|
||||
// zero.
|
||||
let mut p_prime_poly = s_poly * xi + p_poly;
|
||||
let v = eval_polynomial(&p_prime_poly, x);
|
||||
p_prime_poly[0] = p_prime_poly[0] - &v;
|
||||
let p_prime_blind = s_poly_blind * Blind(xi) + p_blind;
|
||||
|
||||
// Initialize the vector `a` as the coefficients of the polynomial,
|
||||
// rounding up to the parameters.
|
||||
let mut a = final_poly.values;
|
||||
a.resize(params.n as usize, C::Scalar::zero());
|
||||
// This accumulates the synthetic blinding factor `f` starting
|
||||
// with the blinding factor for `P'`.
|
||||
let mut f = p_prime_blind.0;
|
||||
|
||||
// Initialize the vector `p_prime` as the coefficients of the polynomial.
|
||||
let mut p_prime = p_prime_poly.values;
|
||||
assert_eq!(p_prime.len(), params.n as usize);
|
||||
|
||||
// Initialize the vector `b` as the powers of `x`. The inner product of
|
||||
// `a` and `b` is the evaluation of the polynomial at `x`.
|
||||
// `p_prime` and `b` is the evaluation of the polynomial at `x`.
|
||||
let mut b = Vec::with_capacity(1 << params.k);
|
||||
{
|
||||
let mut cur = C::Scalar::one();
|
||||
|
@ -90,60 +92,60 @@ pub fn create_proof<
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize the vector `G` from the URS. We'll be progressively collapsing
|
||||
// Initialize the vector `G'` from the URS. We'll be progressively collapsing
|
||||
// this vector into smaller and smaller vectors until it is of length 1.
|
||||
let mut g = params.g.clone();
|
||||
let mut g_prime = params.g.clone();
|
||||
|
||||
// Perform the inner product argument, round by round.
|
||||
for k in (1..=params.k).rev() {
|
||||
let half = 1 << (k - 1); // half the length of `a`, `b`, `G`
|
||||
for j in 0..params.k {
|
||||
let half = 1 << (params.k - j - 1); // half the length of `p_prime`, `b`, `G'`
|
||||
|
||||
// Compute L, R
|
||||
//
|
||||
// TODO: If we modify multiexp to take "extra" bases, we could speed
|
||||
// this piece up a bit by combining the multiexps.
|
||||
let l = best_multiexp(&a[half..], &g[0..half]);
|
||||
let r = best_multiexp(&a[0..half], &g[half..]);
|
||||
let value_l = compute_inner_product(&a[half..], &b[0..half]);
|
||||
let value_r = compute_inner_product(&a[0..half], &b[half..]);
|
||||
let l_randomness = C::Scalar::random(&mut rng);
|
||||
let r_randomness = C::Scalar::random(&mut rng);
|
||||
let l = l + &best_multiexp(&[value_l * &z, l_randomness], &[params.u, params.h]);
|
||||
let r = r + &best_multiexp(&[value_r * &z, r_randomness], &[params.u, params.h]);
|
||||
let l = l.to_affine();
|
||||
let r = r.to_affine();
|
||||
let l_j = best_multiexp(&p_prime[half..], &g_prime[0..half]);
|
||||
let r_j = best_multiexp(&p_prime[0..half], &g_prime[half..]);
|
||||
let value_l_j = compute_inner_product(&p_prime[half..], &b[0..half]);
|
||||
let value_r_j = compute_inner_product(&p_prime[0..half], &b[half..]);
|
||||
let l_j_randomness = C::Scalar::random(&mut rng);
|
||||
let r_j_randomness = C::Scalar::random(&mut rng);
|
||||
let l_j = l_j + &best_multiexp(&[value_l_j * &z, l_j_randomness], &[params.u, params.w]);
|
||||
let r_j = r_j + &best_multiexp(&[value_r_j * &z, r_j_randomness], &[params.u, params.w]);
|
||||
let l_j = l_j.to_affine();
|
||||
let r_j = r_j.to_affine();
|
||||
|
||||
// Feed L and R into the real transcript
|
||||
transcript.write_point(l)?;
|
||||
transcript.write_point(r)?;
|
||||
transcript.write_point(l_j)?;
|
||||
transcript.write_point(r_j)?;
|
||||
|
||||
let challenge = *transcript.squeeze_challenge_scalar::<()>();
|
||||
let challenge_inv = challenge.invert().unwrap(); // TODO, bubble this up
|
||||
let u_j = *transcript.squeeze_challenge_scalar::<()>();
|
||||
let u_j_inv = u_j.invert().unwrap(); // TODO, bubble this up
|
||||
|
||||
// Collapse `a` and `b`.
|
||||
// Collapse `p_prime` and `b`.
|
||||
// TODO: parallelize
|
||||
for i in 0..half {
|
||||
a[i] = a[i] + &(a[i + half] * &challenge_inv);
|
||||
b[i] = b[i] + &(b[i + half] * &challenge);
|
||||
p_prime[i] = p_prime[i] + &(p_prime[i + half] * &u_j_inv);
|
||||
b[i] = b[i] + &(b[i + half] * &u_j);
|
||||
}
|
||||
a.truncate(half);
|
||||
p_prime.truncate(half);
|
||||
b.truncate(half);
|
||||
|
||||
// Collapse `G`
|
||||
parallel_generator_collapse(&mut g, challenge);
|
||||
g.truncate(half);
|
||||
// Collapse `G'`
|
||||
parallel_generator_collapse(&mut g_prime, u_j);
|
||||
g_prime.truncate(half);
|
||||
|
||||
// Update randomness (the synthetic blinding factor at the end)
|
||||
blind += &(l_randomness * &challenge_inv);
|
||||
blind += &(r_randomness * &challenge);
|
||||
f += &(l_j_randomness * &u_j_inv);
|
||||
f += &(r_j_randomness * &u_j);
|
||||
}
|
||||
|
||||
// We have fully collapsed `a`, `b`, `G`
|
||||
assert_eq!(a.len(), 1);
|
||||
let a = a[0];
|
||||
// We have fully collapsed `p_prime`, `b`, `G'`
|
||||
assert_eq!(p_prime.len(), 1);
|
||||
let c = p_prime[0];
|
||||
|
||||
transcript.write_scalar(a)?;
|
||||
transcript.write_scalar(blind)?; // \xi
|
||||
transcript.write_scalar(c)?;
|
||||
transcript.write_scalar(f)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ use crate::arithmetic::{best_multiexp, CurveAffine};
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Guard<'a, C: CurveAffine, E: EncodedChallenge<C>> {
|
||||
msm: MSM<'a, C>,
|
||||
neg_a: C::Scalar,
|
||||
challenges: Vec<C::Scalar>,
|
||||
challenges_packed: Vec<E>,
|
||||
neg_c: C::Scalar,
|
||||
u: Vec<C::Scalar>,
|
||||
u_packed: Vec<E>,
|
||||
}
|
||||
|
||||
/// An accumulator instance consisting of an evaluation claim and a proof.
|
||||
|
@ -24,18 +24,18 @@ pub struct Accumulator<C: CurveAffine, E: EncodedChallenge<C>> {
|
|||
/// The claimed output of the linear-time polycommit opening protocol
|
||||
pub g: C,
|
||||
|
||||
/// A vector of 128-bit challenges sampled by the verifier, to be used in
|
||||
/// computing g.
|
||||
pub challenges_packed: Vec<E>,
|
||||
/// A vector of 128-bit challenges u_0, ..., u_{k - 1} sampled by the
|
||||
/// verifier, to be used in computing G'_0.
|
||||
pub u_packed: Vec<E>,
|
||||
}
|
||||
|
||||
impl<'a, C: CurveAffine, E: EncodedChallenge<C>> Guard<'a, C, E> {
|
||||
/// Lets caller supply the challenges and obtain an MSM with updated
|
||||
/// scalars and points.
|
||||
pub fn use_challenges(mut self) -> MSM<'a, C> {
|
||||
let s = compute_s(&self.challenges, self.neg_a);
|
||||
let s = compute_s(&self.u, self.neg_c);
|
||||
self.msm.add_to_g_scalars(&s);
|
||||
self.msm.add_to_h_scalar(self.neg_a);
|
||||
self.msm.add_to_w_scalar(self.neg_c);
|
||||
|
||||
self.msm
|
||||
}
|
||||
|
@ -43,22 +43,22 @@ impl<'a, C: CurveAffine, E: EncodedChallenge<C>> Guard<'a, C, E> {
|
|||
/// Lets caller supply the purported G point and simply appends
|
||||
/// [-a] G to return an updated MSM.
|
||||
pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator<C, E>) {
|
||||
self.msm.append_term(self.neg_a, g);
|
||||
self.msm.append_term(self.neg_c, g);
|
||||
|
||||
let accumulator = Accumulator {
|
||||
g,
|
||||
challenges_packed: self.challenges_packed,
|
||||
u_packed: self.u_packed,
|
||||
};
|
||||
|
||||
(self.msm, accumulator)
|
||||
}
|
||||
|
||||
/// Computes G + H, where G = ⟨s, params.g⟩ and H is used for blinding
|
||||
/// Computes G + W, where G = ⟨s, params.g⟩ and W is used for blinding
|
||||
pub fn compute_g(&self) -> C {
|
||||
let s = compute_s(&self.challenges, C::Scalar::one());
|
||||
let s = compute_s(&self.u, C::Scalar::one());
|
||||
|
||||
let mut tmp = best_multiexp(&s, &self.msm.params.g);
|
||||
tmp += self.msm.params.h;
|
||||
tmp += self.msm.params.w;
|
||||
tmp.to_affine()
|
||||
}
|
||||
}
|
||||
|
@ -75,14 +75,11 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRea
|
|||
) -> Result<Guard<'a, C, E>, Error> {
|
||||
let k = params.k as usize;
|
||||
|
||||
// P - [v] G_0 + S * iota
|
||||
// + \sum(L_i * u_i^2) + \sum(R_i * u_i^-2)
|
||||
msm.add_constant_term(-v);
|
||||
// P' = P - [v] G_0 + [\xi] S
|
||||
msm.add_constant_term(-v); // add [-v] G_0
|
||||
let s_poly_commitment = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
|
||||
let iota = *transcript.squeeze_challenge_scalar::<()>();
|
||||
|
||||
msm.append_term(iota, s_poly_commitment);
|
||||
let xi = *transcript.squeeze_challenge_scalar::<()>();
|
||||
msm.append_term(xi, s_poly_commitment);
|
||||
|
||||
let z = *transcript.squeeze_challenge_scalar::<()>();
|
||||
|
||||
|
@ -92,92 +89,89 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRea
|
|||
let l = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
let r = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
|
||||
let challenge_packed = transcript.squeeze_challenge();
|
||||
let challenge = *challenge_packed.as_challenge_scalar::<()>();
|
||||
let u_j_packed = transcript.squeeze_challenge();
|
||||
let u_j = *u_j_packed.as_challenge_scalar::<()>();
|
||||
|
||||
rounds.push((
|
||||
l,
|
||||
r,
|
||||
challenge,
|
||||
/* to be inverted */ challenge,
|
||||
challenge_packed,
|
||||
l, r, u_j, u_j, // to be inverted
|
||||
u_j_packed,
|
||||
));
|
||||
}
|
||||
|
||||
rounds
|
||||
.iter_mut()
|
||||
.map(|&mut (_, _, _, ref mut challenge, _)| challenge)
|
||||
.map(|&mut (_, _, _, ref mut u_j, _)| u_j)
|
||||
.batch_invert();
|
||||
|
||||
let mut challenges = Vec::with_capacity(k);
|
||||
let mut challenges_packed: Vec<E> = Vec::with_capacity(k);
|
||||
for (l, r, challenge, challenge_inv, challenge_packed) in rounds {
|
||||
msm.append_term(challenge_inv, l);
|
||||
msm.append_term(challenge, r);
|
||||
// This is the left hand side of the verifier equation.
|
||||
// P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
|
||||
let mut u = Vec::with_capacity(k);
|
||||
let mut u_packed: Vec<E> = Vec::with_capacity(k);
|
||||
for (l, r, u_j, u_j_inv, u_j_packed) in rounds {
|
||||
msm.append_term(u_j_inv, l);
|
||||
msm.append_term(u_j, r);
|
||||
|
||||
challenges.push(challenge);
|
||||
challenges_packed.push(challenge_packed);
|
||||
u.push(u_j);
|
||||
u_packed.push(u_j_packed);
|
||||
}
|
||||
|
||||
// Our goal is to open
|
||||
// msm - [v] G_0 + random_poly_commitment * iota
|
||||
// + \sum(L_i * u_i^2) + \sum(R_i * u_i^-2)
|
||||
// at x to 0, by asking the prover to supply (a, \xi) such that it equals
|
||||
// = [a] (G + [b * z] U) + [\xi] H
|
||||
// except that we wish for the prover to supply G as Commit(g(X); 1) so
|
||||
// we must substitute to get
|
||||
// = [a] ((G - H) + [b * z] U) + [\xi] H
|
||||
// = [a] G + [-a] H + [abz] U + [\xi] H
|
||||
// = [a] G + [abz] U + [\xi - a] H
|
||||
// but subtracting to get the desired equality
|
||||
// ... + [-a] G + [-abz] U + [a - \xi] H = 0
|
||||
// Our goal is to check that the left hand side of the verifier
|
||||
// equation
|
||||
// P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
|
||||
// equals (given the prover's values c, f) the right hand side
|
||||
// = [c] (G'_0 + [b * z] U) + [f] W
|
||||
// except that we wish for the prover to supply G'_0 as Commit(g(X); 1) so
|
||||
// we must substitute G'_0 with G'_0 - W to get
|
||||
// = [c] ((G'_0 - W) + [b * z] U) + [f] W
|
||||
// = [c] G'_0 + [-c] W + [cbz] U + [f] W
|
||||
// = [c] G'_0 + [cbz] U + [f - c] W
|
||||
// and then subtracting the right hand side from both sides
|
||||
// to get
|
||||
// P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
|
||||
// + [-c] G'_0 + [-cbz] U + [c - f] W
|
||||
// = 0
|
||||
|
||||
let a = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let neg_a = -a;
|
||||
let xi = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let b = compute_b(x, &challenges);
|
||||
let c = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let neg_c = -c;
|
||||
let f = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let b = compute_b(x, &u);
|
||||
|
||||
msm.add_to_u_scalar(neg_a * &b * &z);
|
||||
msm.add_to_h_scalar(a - &xi);
|
||||
msm.add_to_u_scalar(neg_c * &b * &z);
|
||||
msm.add_to_w_scalar(c - &f);
|
||||
|
||||
let guard = Guard {
|
||||
msm,
|
||||
neg_a,
|
||||
challenges,
|
||||
challenges_packed,
|
||||
neg_c,
|
||||
u,
|
||||
u_packed,
|
||||
};
|
||||
|
||||
Ok(guard)
|
||||
}
|
||||
|
||||
/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_i x^{2^i})$.
|
||||
fn compute_b<F: Field>(x: F, challenges: &[F]) -> F {
|
||||
/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} x^{2^i})$.
|
||||
fn compute_b<F: Field>(x: F, u: &[F]) -> F {
|
||||
let mut tmp = F::one();
|
||||
let mut cur = x;
|
||||
for challenge in challenges.iter().rev() {
|
||||
tmp *= F::one() + &(*challenge * &cur);
|
||||
for u_j in u.iter().rev() {
|
||||
tmp *= F::one() + &(*u_j * &cur);
|
||||
cur *= cur;
|
||||
}
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_i X^{2^i})$.
|
||||
fn compute_s<F: Field>(challenges: &[F], init: F) -> Vec<F> {
|
||||
assert!(!challenges.is_empty());
|
||||
let mut v = vec![F::zero(); 1 << challenges.len()];
|
||||
/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} X^{2^i})$.
|
||||
fn compute_s<F: Field>(u: &[F], init: F) -> Vec<F> {
|
||||
assert!(!u.is_empty());
|
||||
let mut v = vec![F::zero(); 1 << u.len()];
|
||||
v[0] = init;
|
||||
|
||||
for (len, challenge) in challenges
|
||||
.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.map(|(i, challenge)| (1 << i, challenge))
|
||||
{
|
||||
for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) {
|
||||
let (left, right) = v.split_at_mut(len);
|
||||
let right = &mut right[0..len];
|
||||
right.copy_from_slice(left);
|
||||
for v in right {
|
||||
*v *= challenge;
|
||||
*v *= u_j;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,10 +64,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let f_poly = point_sets
|
||||
let q_prime_poly = point_sets
|
||||
.iter()
|
||||
.zip(q_polys.iter())
|
||||
.fold(None, |f_poly, (points, poly)| {
|
||||
.fold(None, |q_prime_poly, (points, poly)| {
|
||||
let mut poly = points
|
||||
.iter()
|
||||
.fold(poly.clone().unwrap().values, |poly, point| {
|
||||
|
@ -79,43 +79,40 @@ where
|
|||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
if f_poly.is_none() {
|
||||
if q_prime_poly.is_none() {
|
||||
Some(poly)
|
||||
} else {
|
||||
f_poly.map(|f_poly| f_poly * *x_2 + &poly)
|
||||
q_prime_poly.map(|q_prime_poly| q_prime_poly * *x_2 + &poly)
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let f_blind = Blind(C::Scalar::random(&mut rng));
|
||||
let f_commitment = params.commit(&f_poly, f_blind).to_affine();
|
||||
let q_prime_blind = Blind(C::Scalar::random(&mut rng));
|
||||
let q_prime_commitment = params.commit(&q_prime_poly, q_prime_blind).to_affine();
|
||||
|
||||
transcript.write_point(f_commitment)?;
|
||||
transcript.write_point(q_prime_commitment)?;
|
||||
|
||||
let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
|
||||
|
||||
let q_evals: Vec<C::Scalar> = q_polys
|
||||
.iter()
|
||||
.map(|poly| eval_polynomial(poly.as_ref().unwrap(), *x_3))
|
||||
.collect();
|
||||
|
||||
for eval in q_evals.iter() {
|
||||
transcript.write_scalar(*eval)?;
|
||||
// Prover sends u_i for all i, which correspond to the evaluation
|
||||
// of each Q polynomial commitment at x_3.
|
||||
for q_i_poly in &q_polys {
|
||||
transcript.write_scalar(eval_polynomial(q_i_poly.as_ref().unwrap(), *x_3))?;
|
||||
}
|
||||
|
||||
let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
|
||||
|
||||
let (f_poly, f_blind_try) = q_polys.iter().zip(q_blinds.iter()).fold(
|
||||
(f_poly, f_blind),
|
||||
|(f_poly, f_blind), (poly, blind)| {
|
||||
let (p_poly, p_poly_blind) = q_polys.into_iter().zip(q_blinds.into_iter()).fold(
|
||||
(q_prime_poly, q_prime_blind),
|
||||
|(q_prime_poly, q_prime_blind), (poly, blind)| {
|
||||
(
|
||||
f_poly * *x_4 + poly.as_ref().unwrap(),
|
||||
Blind((f_blind.0 * &(*x_4)) + &blind.0),
|
||||
q_prime_poly * *x_4 + &poly.unwrap(),
|
||||
Blind((q_prime_blind.0 * &(*x_4)) + &blind.0),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
commitment::create_proof(params, rng, transcript, &f_poly, f_blind_try, *x_3)
|
||||
commitment::create_proof(params, rng, transcript, &p_poly, p_poly_blind, *x_3)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -77,23 +77,25 @@ where
|
|||
}
|
||||
|
||||
// Obtain the commitment to the multi-point quotient polynomial f(X).
|
||||
let f_commitment = transcript.read_point().map_err(|_| Error::SamplingError)?;
|
||||
let q_prime_commitment = transcript.read_point().map_err(|_| Error::SamplingError)?;
|
||||
|
||||
// Sample a challenge x_3 for checking that f(X) was committed to
|
||||
// correctly.
|
||||
let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
|
||||
|
||||
let mut q_evals = Vec::with_capacity(q_eval_sets.len());
|
||||
// u is a vector containing the evaluations of the Q polynomial
|
||||
// commitments at x_3
|
||||
let mut u = Vec::with_capacity(q_eval_sets.len());
|
||||
for _ in 0..q_eval_sets.len() {
|
||||
q_evals.push(transcript.read_scalar().map_err(|_| Error::SamplingError)?);
|
||||
u.push(transcript.read_scalar().map_err(|_| Error::SamplingError)?);
|
||||
}
|
||||
|
||||
// We can compute the expected msm_eval at x_3 using the q_evals provided
|
||||
// We can compute the expected msm_eval at x_3 using the u provided
|
||||
// by the prover and from x_2
|
||||
let msm_eval = point_sets
|
||||
.iter()
|
||||
.zip(q_eval_sets.iter())
|
||||
.zip(q_evals.iter())
|
||||
.zip(u.iter())
|
||||
.fold(
|
||||
C::Scalar::zero(),
|
||||
|msm_eval, ((points, evals), proof_eval)| {
|
||||
|
@ -111,8 +113,8 @@ where
|
|||
let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
|
||||
|
||||
// Compute the final commitment that has to be opened
|
||||
msm.append_term(C::Scalar::one(), f_commitment);
|
||||
let (msm, msm_eval) = q_commitments.into_iter().zip(q_evals.iter()).fold(
|
||||
msm.append_term(C::Scalar::one(), q_prime_commitment);
|
||||
let (msm, v) = q_commitments.into_iter().zip(u.iter()).fold(
|
||||
(msm, msm_eval),
|
||||
|(mut msm, msm_eval), (q_commitment, q_eval)| {
|
||||
msm.scale(*x_4);
|
||||
|
@ -122,7 +124,7 @@ where
|
|||
);
|
||||
|
||||
// Verify the opening proof
|
||||
super::commitment::verify_proof(params, msm, transcript, *x_3, msm_eval)
|
||||
super::commitment::verify_proof(params, msm, transcript, *x_3, v)
|
||||
}
|
||||
|
||||
impl<'a, 'b, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, 'b, C> {
|
||||
|
|
Loading…
Reference in New Issue