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:
Sean Bowe 2022-02-09 13:36:49 -07:00
parent b45180273e
commit a4d3c328b9
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
7 changed files with 171 additions and 176 deletions

View File

@ -369,7 +369,7 @@ $$
15. $\verifier$ responds with challenge $x_3$. 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)$. 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$. 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} \sum\limits_{i=0}^{n_q - 1}
\left( \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)$. 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)$. 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$. 21. $\verifier$ responds with challenges $\xi, z$.
22. $\prover$ and $\verifier$ set $P' = P - [v] \mathbf{G}_0 + [\xi] S$. 22. $\verifier$ sets $P' = P - [v] \mathbf{G}_0 + [\xi] S$.
23. $\prover$ sets $p'(X) = p(X) - v + \xi s(X)$. 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$: 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$. * $\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$. * $\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$. * $\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$. 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$.

View File

@ -30,7 +30,7 @@ pub struct Params<C: CurveAffine> {
pub(crate) n: u64, pub(crate) n: u64,
pub(crate) g: Vec<C>, pub(crate) g: Vec<C>,
pub(crate) g_lagrange: Vec<C>, pub(crate) g_lagrange: Vec<C>,
pub(crate) h: C, pub(crate) w: C,
pub(crate) u: C, pub(crate) u: C,
} }
@ -102,7 +102,7 @@ impl<C: CurveAffine> Params<C> {
}; };
let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters"); 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(); let u = hasher(&[2]).to_affine();
Params { Params {
@ -110,7 +110,7 @@ impl<C: CurveAffine> Params<C> {
n, n,
g, g,
g_lagrange, g_lagrange,
h, w,
u, u,
} }
} }
@ -126,7 +126,7 @@ impl<C: CurveAffine> Params<C> {
tmp_scalars.push(r.0); tmp_scalars.push(r.0);
tmp_bases.extend(self.g.iter()); tmp_bases.extend(self.g.iter());
tmp_bases.push(self.h); tmp_bases.push(self.w);
best_multiexp::<C>(&tmp_scalars, &tmp_bases) best_multiexp::<C>(&tmp_scalars, &tmp_bases)
} }
@ -146,7 +146,7 @@ impl<C: CurveAffine> Params<C> {
tmp_scalars.push(r.0); tmp_scalars.push(r.0);
tmp_bases.extend(self.g_lagrange.iter()); tmp_bases.extend(self.g_lagrange.iter());
tmp_bases.push(self.h); tmp_bases.push(self.w);
best_multiexp::<C>(&tmp_scalars, &tmp_bases) best_multiexp::<C>(&tmp_scalars, &tmp_bases)
} }
@ -171,7 +171,7 @@ impl<C: CurveAffine> Params<C> {
for g_lagrange_element in &self.g_lagrange { for g_lagrange_element in &self.g_lagrange {
writer.write_all(g_lagrange_element.to_bytes().as_ref())?; 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())?; writer.write_all(self.u.to_bytes().as_ref())?;
Ok(()) Ok(())
@ -188,7 +188,7 @@ impl<C: CurveAffine> Params<C> {
let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?; let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
let g_lagrange: 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)?; let u = C::read(reader)?;
Ok(Params { Ok(Params {
@ -196,7 +196,7 @@ impl<C: CurveAffine> Params<C> {
n, n,
g, g,
g_lagrange, g_lagrange,
h, w,
u, u,
}) })
} }

View File

@ -8,7 +8,7 @@ use group::Group;
pub struct MSM<'a, C: CurveAffine> { pub struct MSM<'a, C: CurveAffine> {
pub(crate) params: &'a Params<C>, pub(crate) params: &'a Params<C>,
g_scalars: Option<Vec<C::Scalar>>, g_scalars: Option<Vec<C::Scalar>>,
h_scalar: Option<C::Scalar>, w_scalar: Option<C::Scalar>,
u_scalar: Option<C::Scalar>, u_scalar: Option<C::Scalar>,
other_scalars: Vec<C::Scalar>, other_scalars: Vec<C::Scalar>,
other_bases: Vec<C>, other_bases: Vec<C>,
@ -18,7 +18,7 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
/// Create a new, empty MSM using the provided parameters. /// Create a new, empty MSM using the provided parameters.
pub fn new(params: &'a Params<C>) -> Self { pub fn new(params: &'a Params<C>) -> Self {
let g_scalars = None; let g_scalars = None;
let h_scalar = None; let w_scalar = None;
let u_scalar = None; let u_scalar = None;
let other_scalars = vec![]; let other_scalars = vec![];
let other_bases = vec![]; let other_bases = vec![];
@ -26,7 +26,7 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
MSM { MSM {
params, params,
g_scalars, g_scalars,
h_scalar, w_scalar,
u_scalar, u_scalar,
other_scalars, other_scalars,
other_bases, other_bases,
@ -42,8 +42,8 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
self.add_to_g_scalars(g_scalars); self.add_to_g_scalars(g_scalars);
} }
if let Some(h_scalar) = &other.h_scalar { if let Some(w_scalar) = &other.w_scalar {
self.add_to_h_scalar(*h_scalar); self.add_to_w_scalar(*w_scalar);
} }
if let Some(u_scalar) = &other.u_scalar { if let Some(u_scalar) = &other.u_scalar {
@ -83,9 +83,9 @@ impl<'a, C: CurveAffine> MSM<'a, C> {
} }
} }
/// Add to `h_scalar` /// Add to `w_scalar`
pub fn add_to_h_scalar(&mut self, scalar: C::Scalar) { pub fn add_to_w_scalar(&mut self, scalar: C::Scalar) {
self.h_scalar = self.h_scalar.map_or(Some(scalar), |a| Some(a + &scalar)); self.w_scalar = self.w_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
} }
/// Add to `u_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); self.u_scalar = self.u_scalar.map(|a| a * &factor);
} }
/// Perform multiexp and check that it results in zero /// Perform multiexp and check that it results in zero
pub fn eval(self) -> bool { pub fn eval(self) -> bool {
let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0) 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.u_scalar.map(|_| 1).unwrap_or(0)
+ self.other_scalars.len(); + self.other_scalars.len();
let mut scalars: Vec<C::Scalar> = Vec::with_capacity(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); scalars.extend(&self.other_scalars);
bases.extend(&self.other_bases); bases.extend(&self.other_bases);
if let Some(h_scalar) = self.h_scalar { if let Some(w_scalar) = self.w_scalar {
scalars.push(h_scalar); scalars.push(w_scalar);
bases.push(self.params.h); bases.push(self.params.w);
} }
if let Some(u_scalar) = self.u_scalar { if let Some(u_scalar) = self.u_scalar {

View File

@ -33,23 +33,23 @@ pub fn create_proof<
params: &Params<C>, params: &Params<C>,
mut rng: R, mut rng: R,
transcript: &mut T, transcript: &mut T,
px: &Polynomial<C::Scalar, Coeff>, p_poly: &Polynomial<C::Scalar, Coeff>,
blind: Blind<C::Scalar>, p_blind: Blind<C::Scalar>,
x: C::Scalar, x: C::Scalar,
) -> io::Result<()> { ) -> io::Result<()> {
// We're limited to polynomials of degree n - 1. // 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 // Sample a random polynomial (of same degree) that has a root at x, first
// by setting all coefficients to random values. // 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() { for coeff in s_poly.iter_mut() {
*coeff = C::Scalar::random(&mut rng); *coeff = C::Scalar::random(&mut rng);
} }
// Evaluate the random polynomial at x // 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 // 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 // And sample a random blind
let s_poly_blind = Blind(C::Scalar::random(&mut rng)); 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 // 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 // witness a random polynomial commitment that agrees with P at x, with high
// probability. // 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 // Challenge that ensures that the prover did not interfere with the U term
// in their commitments. // in their commitments.
let z = *transcript.squeeze_challenge_scalar::<()>(); let z = *transcript.squeeze_challenge_scalar::<()>();
// We'll be opening `s_poly_commitment * iota + P - [v] G_0` to ensure it // We'll be opening `P' = P - [v] G_0 + [\xi] S` to ensure it has a root at
// has a root at zero. // zero.
let mut final_poly = s_poly * iota + px; let mut p_prime_poly = s_poly * xi + p_poly;
let v = eval_polynomial(&final_poly, x); let v = eval_polynomial(&p_prime_poly, x);
final_poly[0] = final_poly[0] - &v; p_prime_poly[0] = p_prime_poly[0] - &v;
let blind = s_poly_blind * Blind(iota) + blind; let p_prime_blind = s_poly_blind * Blind(xi) + p_blind;
let mut blind = blind.0;
// Initialize the vector `a` as the coefficients of the polynomial, // This accumulates the synthetic blinding factor `f` starting
// rounding up to the parameters. // with the blinding factor for `P'`.
let mut a = final_poly.values; let mut f = p_prime_blind.0;
a.resize(params.n as usize, C::Scalar::zero());
// 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 // 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 b = Vec::with_capacity(1 << params.k);
{ {
let mut cur = C::Scalar::one(); 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. // 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. // Perform the inner product argument, round by round.
for k in (1..=params.k).rev() { for j in 0..params.k {
let half = 1 << (k - 1); // half the length of `a`, `b`, `G` let half = 1 << (params.k - j - 1); // half the length of `p_prime`, `b`, `G'`
// Compute L, R // Compute L, R
// //
// TODO: If we modify multiexp to take "extra" bases, we could speed // TODO: If we modify multiexp to take "extra" bases, we could speed
// this piece up a bit by combining the multiexps. // this piece up a bit by combining the multiexps.
let l = best_multiexp(&a[half..], &g[0..half]); let l_j = best_multiexp(&p_prime[half..], &g_prime[0..half]);
let r = best_multiexp(&a[0..half], &g[half..]); let r_j = best_multiexp(&p_prime[0..half], &g_prime[half..]);
let value_l = compute_inner_product(&a[half..], &b[0..half]); let value_l_j = compute_inner_product(&p_prime[half..], &b[0..half]);
let value_r = compute_inner_product(&a[0..half], &b[half..]); let value_r_j = compute_inner_product(&p_prime[0..half], &b[half..]);
let l_randomness = C::Scalar::random(&mut rng); let l_j_randomness = C::Scalar::random(&mut rng);
let r_randomness = C::Scalar::random(&mut rng); let r_j_randomness = C::Scalar::random(&mut rng);
let l = l + &best_multiexp(&[value_l * &z, l_randomness], &[params.u, params.h]); let l_j = l_j + &best_multiexp(&[value_l_j * &z, l_j_randomness], &[params.u, params.w]);
let r = r + &best_multiexp(&[value_r * &z, r_randomness], &[params.u, params.h]); let r_j = r_j + &best_multiexp(&[value_r_j * &z, r_j_randomness], &[params.u, params.w]);
let l = l.to_affine(); let l_j = l_j.to_affine();
let r = r.to_affine(); let r_j = r_j.to_affine();
// Feed L and R into the real transcript // Feed L and R into the real transcript
transcript.write_point(l)?; transcript.write_point(l_j)?;
transcript.write_point(r)?; transcript.write_point(r_j)?;
let challenge = *transcript.squeeze_challenge_scalar::<()>(); let u_j = *transcript.squeeze_challenge_scalar::<()>();
let challenge_inv = challenge.invert().unwrap(); // TODO, bubble this up let u_j_inv = u_j.invert().unwrap(); // TODO, bubble this up
// Collapse `a` and `b`. // Collapse `p_prime` and `b`.
// TODO: parallelize // TODO: parallelize
for i in 0..half { for i in 0..half {
a[i] = a[i] + &(a[i + half] * &challenge_inv); p_prime[i] = p_prime[i] + &(p_prime[i + half] * &u_j_inv);
b[i] = b[i] + &(b[i + half] * &challenge); b[i] = b[i] + &(b[i + half] * &u_j);
} }
a.truncate(half); p_prime.truncate(half);
b.truncate(half); b.truncate(half);
// Collapse `G` // Collapse `G'`
parallel_generator_collapse(&mut g, challenge); parallel_generator_collapse(&mut g_prime, u_j);
g.truncate(half); g_prime.truncate(half);
// Update randomness (the synthetic blinding factor at the end) // Update randomness (the synthetic blinding factor at the end)
blind += &(l_randomness * &challenge_inv); f += &(l_j_randomness * &u_j_inv);
blind += &(r_randomness * &challenge); f += &(r_j_randomness * &u_j);
} }
// We have fully collapsed `a`, `b`, `G` // We have fully collapsed `p_prime`, `b`, `G'`
assert_eq!(a.len(), 1); assert_eq!(p_prime.len(), 1);
let a = a[0]; let c = p_prime[0];
transcript.write_scalar(a)?; transcript.write_scalar(c)?;
transcript.write_scalar(blind)?; // \xi transcript.write_scalar(f)?;
Ok(()) Ok(())
} }

View File

@ -13,9 +13,9 @@ use crate::arithmetic::{best_multiexp, CurveAffine};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Guard<'a, C: CurveAffine, E: EncodedChallenge<C>> { pub struct Guard<'a, C: CurveAffine, E: EncodedChallenge<C>> {
msm: MSM<'a, C>, msm: MSM<'a, C>,
neg_a: C::Scalar, neg_c: C::Scalar,
challenges: Vec<C::Scalar>, u: Vec<C::Scalar>,
challenges_packed: Vec<E>, u_packed: Vec<E>,
} }
/// An accumulator instance consisting of an evaluation claim and a proof. /// 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 /// The claimed output of the linear-time polycommit opening protocol
pub g: C, pub g: C,
/// A vector of 128-bit challenges sampled by the verifier, to be used in /// A vector of 128-bit challenges u_0, ..., u_{k - 1} sampled by the
/// computing g. /// verifier, to be used in computing G'_0.
pub challenges_packed: Vec<E>, pub u_packed: Vec<E>,
} }
impl<'a, C: CurveAffine, E: EncodedChallenge<C>> Guard<'a, C, E> { impl<'a, C: CurveAffine, E: EncodedChallenge<C>> Guard<'a, C, E> {
/// Lets caller supply the challenges and obtain an MSM with updated /// Lets caller supply the challenges and obtain an MSM with updated
/// scalars and points. /// scalars and points.
pub fn use_challenges(mut self) -> MSM<'a, C> { 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_g_scalars(&s);
self.msm.add_to_h_scalar(self.neg_a); self.msm.add_to_w_scalar(self.neg_c);
self.msm 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 /// Lets caller supply the purported G point and simply appends
/// [-a] G to return an updated MSM. /// [-a] G to return an updated MSM.
pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator<C, E>) { 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 { let accumulator = Accumulator {
g, g,
challenges_packed: self.challenges_packed, u_packed: self.u_packed,
}; };
(self.msm, accumulator) (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 { 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); let mut tmp = best_multiexp(&s, &self.msm.params.g);
tmp += self.msm.params.h; tmp += self.msm.params.w;
tmp.to_affine() 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> { ) -> Result<Guard<'a, C, E>, Error> {
let k = params.k as usize; let k = params.k as usize;
// P - [v] G_0 + S * iota // P' = P - [v] G_0 + [\xi] S
// + \sum(L_i * u_i^2) + \sum(R_i * u_i^-2) msm.add_constant_term(-v); // add [-v] G_0
msm.add_constant_term(-v);
let s_poly_commitment = transcript.read_point().map_err(|_| Error::OpeningError)?; let s_poly_commitment = transcript.read_point().map_err(|_| Error::OpeningError)?;
let xi = *transcript.squeeze_challenge_scalar::<()>();
let iota = *transcript.squeeze_challenge_scalar::<()>(); msm.append_term(xi, s_poly_commitment);
msm.append_term(iota, s_poly_commitment);
let z = *transcript.squeeze_challenge_scalar::<()>(); 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 l = transcript.read_point().map_err(|_| Error::OpeningError)?;
let r = transcript.read_point().map_err(|_| Error::OpeningError)?; let r = transcript.read_point().map_err(|_| Error::OpeningError)?;
let challenge_packed = transcript.squeeze_challenge(); let u_j_packed = transcript.squeeze_challenge();
let challenge = *challenge_packed.as_challenge_scalar::<()>(); let u_j = *u_j_packed.as_challenge_scalar::<()>();
rounds.push(( rounds.push((
l, l, r, u_j, u_j, // to be inverted
r, u_j_packed,
challenge,
/* to be inverted */ challenge,
challenge_packed,
)); ));
} }
rounds rounds
.iter_mut() .iter_mut()
.map(|&mut (_, _, _, ref mut challenge, _)| challenge) .map(|&mut (_, _, _, ref mut u_j, _)| u_j)
.batch_invert(); .batch_invert();
let mut challenges = Vec::with_capacity(k); // This is the left hand side of the verifier equation.
let mut challenges_packed: Vec<E> = Vec::with_capacity(k); // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
for (l, r, challenge, challenge_inv, challenge_packed) in rounds { let mut u = Vec::with_capacity(k);
msm.append_term(challenge_inv, l); let mut u_packed: Vec<E> = Vec::with_capacity(k);
msm.append_term(challenge, r); 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); u.push(u_j);
challenges_packed.push(challenge_packed); u_packed.push(u_j_packed);
} }
// Our goal is to open // Our goal is to check that the left hand side of the verifier
// msm - [v] G_0 + random_poly_commitment * iota // equation
// + \sum(L_i * u_i^2) + \sum(R_i * u_i^-2) // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
// at x to 0, by asking the prover to supply (a, \xi) such that it equals // equals (given the prover's values c, f) the right hand side
// = [a] (G + [b * z] U) + [\xi] H // = [c] (G'_0 + [b * z] U) + [f] W
// except that we wish for the prover to supply G as Commit(g(X); 1) so // except that we wish for the prover to supply G'_0 as Commit(g(X); 1) so
// we must substitute to get // we must substitute G'_0 with G'_0 - W to get
// = [a] ((G - H) + [b * z] U) + [\xi] H // = [c] ((G'_0 - W) + [b * z] U) + [f] W
// = [a] G + [-a] H + [abz] U + [\xi] H // = [c] G'_0 + [-c] W + [cbz] U + [f] W
// = [a] G + [abz] U + [\xi - a] H // = [c] G'_0 + [cbz] U + [f - c] W
// but subtracting to get the desired equality // and then subtracting the right hand side from both sides
// ... + [-a] G + [-abz] U + [a - \xi] H = 0 // 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 c = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
let neg_a = -a; let neg_c = -c;
let xi = transcript.read_scalar().map_err(|_| Error::SamplingError)?; let f = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
let b = compute_b(x, &challenges); let b = compute_b(x, &u);
msm.add_to_u_scalar(neg_a * &b * &z); msm.add_to_u_scalar(neg_c * &b * &z);
msm.add_to_h_scalar(a - &xi); msm.add_to_w_scalar(c - &f);
let guard = Guard { let guard = Guard {
msm, msm,
neg_a, neg_c,
challenges, u,
challenges_packed, u_packed,
}; };
Ok(guard) Ok(guard)
} }
/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_i x^{2^i})$. /// Computes $\prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} x^{2^i})$.
fn compute_b<F: Field>(x: F, challenges: &[F]) -> F { fn compute_b<F: Field>(x: F, u: &[F]) -> F {
let mut tmp = F::one(); let mut tmp = F::one();
let mut cur = x; let mut cur = x;
for challenge in challenges.iter().rev() { for u_j in u.iter().rev() {
tmp *= F::one() + &(*challenge * &cur); tmp *= F::one() + &(*u_j * &cur);
cur *= cur; cur *= cur;
} }
tmp tmp
} }
/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_i X^{2^i})$. /// 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>(challenges: &[F], init: F) -> Vec<F> { fn compute_s<F: Field>(u: &[F], init: F) -> Vec<F> {
assert!(!challenges.is_empty()); assert!(!u.is_empty());
let mut v = vec![F::zero(); 1 << challenges.len()]; let mut v = vec![F::zero(); 1 << u.len()];
v[0] = init; v[0] = init;
for (len, challenge) in challenges for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) {
.iter()
.rev()
.enumerate()
.map(|(i, challenge)| (1 << i, challenge))
{
let (left, right) = v.split_at_mut(len); let (left, right) = v.split_at_mut(len);
let right = &mut right[0..len]; let right = &mut right[0..len];
right.copy_from_slice(left); right.copy_from_slice(left);
for v in right { for v in right {
*v *= challenge; *v *= u_j;
} }
} }

View File

@ -64,10 +64,10 @@ where
} }
} }
let f_poly = point_sets let q_prime_poly = point_sets
.iter() .iter()
.zip(q_polys.iter()) .zip(q_polys.iter())
.fold(None, |f_poly, (points, poly)| { .fold(None, |q_prime_poly, (points, poly)| {
let mut poly = points let mut poly = points
.iter() .iter()
.fold(poly.clone().unwrap().values, |poly, point| { .fold(poly.clone().unwrap().values, |poly, point| {
@ -79,43 +79,40 @@ where
_marker: PhantomData, _marker: PhantomData,
}; };
if f_poly.is_none() { if q_prime_poly.is_none() {
Some(poly) Some(poly)
} else { } 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(); .unwrap();
let f_blind = Blind(C::Scalar::random(&mut rng)); let q_prime_blind = Blind(C::Scalar::random(&mut rng));
let f_commitment = params.commit(&f_poly, f_blind).to_affine(); 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 x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
let q_evals: Vec<C::Scalar> = q_polys // Prover sends u_i for all i, which correspond to the evaluation
.iter() // of each Q polynomial commitment at x_3.
.map(|poly| eval_polynomial(poly.as_ref().unwrap(), *x_3)) for q_i_poly in &q_polys {
.collect(); transcript.write_scalar(eval_polynomial(q_i_poly.as_ref().unwrap(), *x_3))?;
for eval in q_evals.iter() {
transcript.write_scalar(*eval)?;
} }
let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar(); let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
let (f_poly, f_blind_try) = q_polys.iter().zip(q_blinds.iter()).fold( let (p_poly, p_poly_blind) = q_polys.into_iter().zip(q_blinds.into_iter()).fold(
(f_poly, f_blind), (q_prime_poly, q_prime_blind),
|(f_poly, f_blind), (poly, blind)| { |(q_prime_poly, q_prime_blind), (poly, blind)| {
( (
f_poly * *x_4 + poly.as_ref().unwrap(), q_prime_poly * *x_4 + &poly.unwrap(),
Blind((f_blind.0 * &(*x_4)) + &blind.0), 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)] #[doc(hidden)]

View File

@ -77,23 +77,25 @@ where
} }
// Obtain the commitment to the multi-point quotient polynomial f(X). // 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 // Sample a challenge x_3 for checking that f(X) was committed to
// correctly. // correctly.
let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar(); 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() { 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 // by the prover and from x_2
let msm_eval = point_sets let msm_eval = point_sets
.iter() .iter()
.zip(q_eval_sets.iter()) .zip(q_eval_sets.iter())
.zip(q_evals.iter()) .zip(u.iter())
.fold( .fold(
C::Scalar::zero(), C::Scalar::zero(),
|msm_eval, ((points, evals), proof_eval)| { |msm_eval, ((points, evals), proof_eval)| {
@ -111,8 +113,8 @@ where
let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar(); let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
// Compute the final commitment that has to be opened // Compute the final commitment that has to be opened
msm.append_term(C::Scalar::one(), f_commitment); msm.append_term(C::Scalar::one(), q_prime_commitment);
let (msm, msm_eval) = q_commitments.into_iter().zip(q_evals.iter()).fold( let (msm, v) = q_commitments.into_iter().zip(u.iter()).fold(
(msm, msm_eval), (msm, msm_eval),
|(mut msm, msm_eval), (q_commitment, q_eval)| { |(mut msm, msm_eval), (q_commitment, q_eval)| {
msm.scale(*x_4); msm.scale(*x_4);
@ -122,7 +124,7 @@ where
); );
// Verify the opening proof // 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> { impl<'a, 'b, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, 'b, C> {