mirror of https://github.com/zcash/halo2.git
Modify MSM and Guard structs and methods
This commit is contained in:
parent
7255e085a4
commit
d41fcf842b
|
@ -70,10 +70,6 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a 128-bit verifier challenge.
|
/// This is a 128-bit verifier challenge.
|
||||||
///
|
|
||||||
/// The verifier samples its challenge here as u^2, i.e. the square of the
|
|
||||||
/// actual challenge. This is an optimisation that is documented in Section 6.3
|
|
||||||
/// of the [Halo](https://eprint.iacr.org/2019/1021) paper.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Challenge(pub(crate) u128);
|
pub struct Challenge(pub(crate) u128);
|
||||||
|
|
||||||
|
|
|
@ -264,11 +264,12 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the opening proof
|
// Verify the opening proof
|
||||||
let (challenges, mut guard) = self
|
let default_msm = MSM::default(¶ms);
|
||||||
|
let (challenges, guard) = self
|
||||||
.opening
|
.opening
|
||||||
.verify(
|
.verify(
|
||||||
params,
|
params,
|
||||||
&mut MSM::default(¶ms),
|
default_msm,
|
||||||
&mut transcript,
|
&mut transcript,
|
||||||
x_6,
|
x_6,
|
||||||
&f_commitment.to_affine(),
|
&f_commitment.to_affine(),
|
||||||
|
@ -276,8 +277,8 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let msm: MSM<C> = guard.use_challenges(challenges).unwrap();
|
let msm: &MSM<C> = &guard.use_challenges(params, challenges).unwrap();
|
||||||
|
|
||||||
msm.is_zero()
|
msm.is_zero(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,60 +27,89 @@ pub struct OpeningProof<C: CurveAffine> {
|
||||||
/// A multiscalar multiplication in the polynomial commitment scheme
|
/// A multiscalar multiplication in the polynomial commitment scheme
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MSM<C: CurveAffine> {
|
pub struct MSM<C: CurveAffine> {
|
||||||
/// Vector of random generators
|
/// TODO: documentation
|
||||||
pub g: Vec<C>,
|
pub g_scalars: Option<Vec<C::Scalar>>,
|
||||||
|
|
||||||
/// Random generator
|
/// TODO: documentation
|
||||||
pub h: C,
|
pub h_scalar: Option<C::Scalar>,
|
||||||
|
|
||||||
/// Scalars in the multiscalar multiplication
|
/// TODO: documentation
|
||||||
pub scalars: Vec<C::Scalar>,
|
pub other_scalars: Vec<C::Scalar>,
|
||||||
|
|
||||||
/// Points in the multiscalar multiplication
|
/// TODO: documentation
|
||||||
pub bases: Vec<C>,
|
pub other_bases: Vec<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CurveAffine> MSM<C> {
|
impl<'a, C: CurveAffine> MSM<C> {
|
||||||
/// Empty MSM
|
/// Empty MSM
|
||||||
pub fn default(params: &'a Params<C>) -> Self {
|
pub fn default(params: &Params<C>) -> Self {
|
||||||
let scalars: Vec<C::Scalar> =
|
let g_scalars = Some(vec![C::Scalar::one(); params.n as usize]);
|
||||||
Vec::with_capacity(params.k as usize * 2 + 4 + params.n as usize);
|
let h_scalar = Some(C::Scalar::one());
|
||||||
let bases: Vec<C> = Vec::with_capacity(params.k as usize * 2 + 4 + params.n as usize);
|
let other_scalars: Vec<C::Scalar> = Vec::with_capacity(params.k as usize * 2 + 3);
|
||||||
|
let other_bases: Vec<C> = Vec::with_capacity(params.k as usize * 2 + 3);
|
||||||
|
|
||||||
MSM {
|
MSM {
|
||||||
g: params.g.clone(),
|
g_scalars,
|
||||||
h: params.h.clone(),
|
h_scalar,
|
||||||
scalars,
|
other_scalars,
|
||||||
bases,
|
other_bases,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add arbitrary term (the scalar and the point)
|
/// Add arbitrary term (the scalar and the point)
|
||||||
pub fn add_term(&mut self, scalar: C::Scalar, point: C) {
|
pub fn add_term(&mut self, scalar: C::Scalar, point: C) {
|
||||||
&self.scalars.push(scalar);
|
&self.other_scalars.push(scalar);
|
||||||
&self.bases.push(point);
|
&self.other_bases.push(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add term to g
|
/// Add a vector of scalars to `g_scalars`
|
||||||
pub fn add_to_g(&mut self, point: C) {
|
pub fn add_to_g(&mut self, scalars: Vec<C::Scalar>) {
|
||||||
&self.g.push(point);
|
for (g_scalar, scalar) in self
|
||||||
|
.g_scalars
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.iter_mut()
|
||||||
|
.zip(scalars.iter())
|
||||||
|
{
|
||||||
|
*g_scalar += &scalar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add term to h
|
/// Add term to h
|
||||||
pub fn add_to_h(&mut self, point: C) {
|
pub fn add_to_h(&mut self, scalar: C::Scalar) {
|
||||||
self.h = self.h.add(point).to_affine();
|
self.h_scalar = Some(self.h_scalar.unwrap() + &scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scale by a random blinding factor
|
/// Scale all scalars in the MSM by a random blinding factor
|
||||||
pub fn scale(&mut self, factor: C::Scalar) {
|
pub fn scale(&mut self, factor: C::Scalar) {
|
||||||
for scalar in self.scalars.iter_mut() {
|
for g_scalar in self.g_scalars.as_mut().unwrap().iter_mut() {
|
||||||
*scalar *= &factor;
|
*g_scalar *= &factor;
|
||||||
}
|
}
|
||||||
|
for other_scalar in self.other_scalars.iter_mut() {
|
||||||
|
*other_scalar *= &factor;
|
||||||
|
}
|
||||||
|
self.h_scalar = Some(self.h_scalar.unwrap() * &factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform multiexp and check that it results in zero
|
/// Perform multiexp and check that it results in zero
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(&self, params: &'a Params<C>) -> bool {
|
||||||
bool::from(best_multiexp(&self.scalars, &self.bases).is_zero())
|
let mut scalars: Vec<C::Scalar> = vec![];
|
||||||
|
let mut bases: Vec<C> = vec![];
|
||||||
|
|
||||||
|
scalars.extend(&self.other_scalars);
|
||||||
|
bases.extend(&self.other_bases);
|
||||||
|
|
||||||
|
if let Some(h_scalar) = self.h_scalar {
|
||||||
|
scalars.push(h_scalar);
|
||||||
|
bases.push(params.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(g_scalars) = &self.g_scalars {
|
||||||
|
scalars.extend(g_scalars);
|
||||||
|
bases.extend(params.g.iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool::from(best_multiexp(&scalars, &bases).is_zero())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,90 +248,70 @@ impl<C: CurveAffine> Params<C> {
|
||||||
|
|
||||||
/// A guard returned by the verifier
|
/// A guard returned by the verifier
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Guard<'a, C: CurveAffine> {
|
pub struct Guard<C: CurveAffine> {
|
||||||
/// Vector of random generators
|
/// MSM
|
||||||
pub g: Vec<C>,
|
msm: MSM<C>,
|
||||||
|
|
||||||
/// Random generator
|
|
||||||
pub h: C,
|
|
||||||
|
|
||||||
/// Negation of z1 value in the OpeningProof
|
/// Negation of z1 value in the OpeningProof
|
||||||
pub neg_z1: C::Scalar,
|
neg_z1: C::Scalar,
|
||||||
|
|
||||||
/// Params that were used by the verifier
|
allinv: C::Scalar,
|
||||||
pub params: &'a Params<C>,
|
|
||||||
|
|
||||||
/// Scalars produced by the verifier for multiscalar multiplication
|
challenges_sq: Vec<C::Scalar>,
|
||||||
pub scalars: Vec<C::Scalar>,
|
|
||||||
|
|
||||||
/// Points produced by the verifier for multiscalar multiplication
|
|
||||||
pub bases: Vec<C>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: CurveAffine> Guard<'a, C> {
|
impl<C: CurveAffine> Guard<C> {
|
||||||
/// 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(
|
pub fn use_challenges(
|
||||||
&mut self,
|
mut self,
|
||||||
|
params: &Params<C>,
|
||||||
challenges_sq_packed: Vec<Challenge>,
|
challenges_sq_packed: Vec<Challenge>,
|
||||||
) -> Result<MSM<C>, Error> {
|
) -> Result<MSM<C>, Error> {
|
||||||
|
let mut scalars: Vec<C::Scalar> = vec![];
|
||||||
|
let mut bases: Vec<C> = vec![];
|
||||||
|
|
||||||
|
scalars.extend(&self.msm.other_scalars);
|
||||||
|
bases.extend(&self.msm.other_bases);
|
||||||
|
|
||||||
|
// - [z2] H
|
||||||
|
if let Some(h_scalar) = self.msm.h_scalar {
|
||||||
|
scalars.push(h_scalar);
|
||||||
|
bases.push(params.h);
|
||||||
|
}
|
||||||
|
|
||||||
// - [z1] G
|
// - [z1] G
|
||||||
let mut allinv = C::Scalar::one();
|
let mut allinv = C::Scalar::one();
|
||||||
let mut challenges_sq = Vec::with_capacity(self.params.k as usize);
|
let mut challenges_sq = Vec::with_capacity(params.k as usize);
|
||||||
|
|
||||||
for challenge_sq_packed in challenges_sq_packed {
|
for challenge_sq_packed in challenges_sq_packed.iter() {
|
||||||
let challenge_sq: C::Scalar = get_challenge_scalar(challenge_sq_packed);
|
let challenge_sq: C::Scalar = get_challenge_scalar(*challenge_sq_packed);
|
||||||
challenges_sq.push(challenge_sq);
|
challenges_sq.push(challenge_sq);
|
||||||
|
|
||||||
let challenge = challenge_sq.deterministic_sqrt();
|
let challenge = challenge_sq.deterministic_sqrt();
|
||||||
if challenge.is_none() {
|
|
||||||
// We didn't sample a square.
|
|
||||||
return Err(Error::OpeningError);
|
|
||||||
}
|
|
||||||
let challenge = challenge.unwrap();
|
let challenge = challenge.unwrap();
|
||||||
|
|
||||||
let challenge_inv = challenge.invert();
|
let challenge_inv = challenge.invert();
|
||||||
if bool::from(challenge_inv.is_none()) {
|
|
||||||
// We sampled zero for some reason, unlikely to happen by
|
|
||||||
// chance.
|
|
||||||
return Err(Error::OpeningError);
|
|
||||||
}
|
|
||||||
let challenge_inv = challenge_inv.unwrap();
|
let challenge_inv = challenge_inv.unwrap();
|
||||||
allinv *= &challenge_inv;
|
allinv *= &challenge_inv;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bases.extend(&self.g);
|
let s = compute_s(&challenges_sq, allinv * &self.neg_z1);
|
||||||
let mut s = compute_s(&challenges_sq, allinv);
|
scalars.extend(&s);
|
||||||
// TODO: parallelize
|
bases.extend(¶ms.g);
|
||||||
for s in &mut s {
|
|
||||||
*s *= &self.neg_z1;
|
|
||||||
}
|
|
||||||
self.scalars.extend(s);
|
|
||||||
|
|
||||||
Ok(MSM {
|
self.msm.g_scalars = Some(s);
|
||||||
g: self.g.clone(),
|
|
||||||
h: self.h.clone(),
|
Ok(self.msm)
|
||||||
scalars: self.scalars.clone(),
|
|
||||||
bases: self.bases.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lets caller supply the purported G point and simply appends it to
|
/// Lets caller supply the purported G point and simply appends it to
|
||||||
/// return an updated MSM.
|
/// return an updated MSM.
|
||||||
pub fn use_s(&mut self, g: Vec<C>, mut s: Vec<C::Scalar>) -> Result<MSM<C>, Error> {
|
pub fn use_g(mut self, g: C) -> Result<MSM<C>, Error> {
|
||||||
// - [z1] G
|
&self.msm.other_scalars.push(self.allinv * &self.neg_z1);
|
||||||
self.bases.extend(&g);
|
&self.msm.other_bases.push(g);
|
||||||
for s in &mut s {
|
|
||||||
*s *= &self.neg_z1;
|
|
||||||
}
|
|
||||||
self.scalars.extend(s);
|
|
||||||
|
|
||||||
Ok(MSM {
|
Ok(self.msm)
|
||||||
g: self.g.clone(),
|
|
||||||
h: self.h.clone(),
|
|
||||||
scalars: self.scalars.clone(),
|
|
||||||
bases: self.bases.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,20 +435,14 @@ fn test_opening_proof() {
|
||||||
} else {
|
} else {
|
||||||
let opening_proof = opening_proof.unwrap();
|
let opening_proof = opening_proof.unwrap();
|
||||||
// Verify the opening proof
|
// Verify the opening proof
|
||||||
let (challenges, mut guard) = opening_proof
|
let msm = MSM::default(¶ms);
|
||||||
.verify(
|
let (challenges, guard) = opening_proof
|
||||||
¶ms,
|
.verify(¶ms, msm, &mut transcript_dup, x, &p, v)
|
||||||
&mut MSM::default(¶ms),
|
|
||||||
&mut transcript_dup,
|
|
||||||
x,
|
|
||||||
&p,
|
|
||||||
v,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let msm = guard.use_challenges(challenges).unwrap();
|
let msm = guard.use_challenges(¶ms, challenges).unwrap();
|
||||||
|
|
||||||
assert!(msm.is_zero());
|
assert!(msm.is_zero(¶ms));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@ impl<C: CurveAffine> OpeningProof<C> {
|
||||||
pub fn verify<'a, H: Hasher<C::Base>>(
|
pub fn verify<'a, H: Hasher<C::Base>>(
|
||||||
&self,
|
&self,
|
||||||
params: &'a Params<C>,
|
params: &'a Params<C>,
|
||||||
msm: &mut MSM<C>,
|
mut msm: MSM<C>,
|
||||||
transcript: &mut H,
|
transcript: &mut H,
|
||||||
x: C::Scalar,
|
x: C::Scalar,
|
||||||
p: &C,
|
p: &C,
|
||||||
v: C::Scalar,
|
v: C::Scalar,
|
||||||
) -> Result<(Vec<Challenge>, Guard<'a, C>), Error> {
|
) -> Result<(Vec<Challenge>, Guard<C>), Error> {
|
||||||
// Check for well-formedness
|
// Check for well-formedness
|
||||||
if self.rounds.len() != params.k as usize {
|
if self.rounds.len() != params.k as usize {
|
||||||
return Err(Error::OpeningError);
|
return Err(Error::OpeningError);
|
||||||
|
@ -43,6 +43,7 @@ impl<C: CurveAffine> OpeningProof<C> {
|
||||||
let mut challenges_inv = Vec::with_capacity(self.rounds.len());
|
let mut challenges_inv = Vec::with_capacity(self.rounds.len());
|
||||||
let mut challenges_sq = Vec::with_capacity(self.rounds.len());
|
let mut challenges_sq = Vec::with_capacity(self.rounds.len());
|
||||||
let mut challenges_sq_packed: Vec<Challenge> = Vec::with_capacity(self.rounds.len());
|
let mut challenges_sq_packed: Vec<Challenge> = Vec::with_capacity(self.rounds.len());
|
||||||
|
let mut allinv = C::Scalar::one();
|
||||||
|
|
||||||
for round in &self.rounds {
|
for round in &self.rounds {
|
||||||
// Feed L and R into the transcript.
|
// Feed L and R into the transcript.
|
||||||
|
@ -74,13 +75,14 @@ impl<C: CurveAffine> OpeningProof<C> {
|
||||||
return Err(Error::OpeningError);
|
return Err(Error::OpeningError);
|
||||||
}
|
}
|
||||||
let challenge_inv = challenge_inv.unwrap();
|
let challenge_inv = challenge_inv.unwrap();
|
||||||
|
allinv *= &challenge_inv;
|
||||||
|
|
||||||
let challenge_sq_inv = challenge_inv.square();
|
let challenge_sq_inv = challenge_inv.square();
|
||||||
|
|
||||||
msm.scalars.push(challenge_sq);
|
msm.other_scalars.push(challenge_sq);
|
||||||
msm.bases.push(round.0);
|
msm.other_bases.push(round.0);
|
||||||
msm.scalars.push(challenge_sq_inv);
|
msm.other_scalars.push(challenge_sq_inv);
|
||||||
msm.bases.push(round.1);
|
msm.other_bases.push(round.1);
|
||||||
|
|
||||||
challenges.push(challenge);
|
challenges.push(challenge);
|
||||||
challenges_inv.push(challenge_inv);
|
challenges_inv.push(challenge_inv);
|
||||||
|
@ -106,7 +108,7 @@ impl<C: CurveAffine> OpeningProof<C> {
|
||||||
// [c] P + [c * v] U + [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) + delta - [z1] G - [z1 * b] U - [z2] H
|
// [c] P + [c * v] U + [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) + delta - [z1] G - [z1 * b] U - [z2] H
|
||||||
// = 0
|
// = 0
|
||||||
|
|
||||||
for scalar in &mut msm.scalars {
|
for scalar in &mut msm.other_scalars {
|
||||||
*scalar *= &c;
|
*scalar *= &c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,28 +117,25 @@ impl<C: CurveAffine> OpeningProof<C> {
|
||||||
let neg_z1 = -self.z1;
|
let neg_z1 = -self.z1;
|
||||||
|
|
||||||
// [c] P
|
// [c] P
|
||||||
msm.bases.push(*p);
|
msm.other_bases.push(*p);
|
||||||
msm.scalars.push(c);
|
msm.other_scalars.push(c);
|
||||||
|
|
||||||
// [c * v] U - [z1 * b] U
|
// [c * v] U - [z1 * b] U
|
||||||
msm.bases.push(u);
|
msm.other_bases.push(u);
|
||||||
msm.scalars.push((c * &v) + &(neg_z1 * &b));
|
msm.other_scalars.push((c * &v) + &(neg_z1 * &b));
|
||||||
|
|
||||||
// delta
|
// delta
|
||||||
msm.bases.push(self.delta);
|
msm.other_bases.push(self.delta);
|
||||||
msm.scalars.push(Field::one());
|
msm.other_scalars.push(Field::one());
|
||||||
|
|
||||||
// - [z2] H
|
// z2
|
||||||
msm.bases.push(msm.h);
|
msm.h_scalar = Some(-self.z2);
|
||||||
msm.scalars.push(-self.z2);
|
|
||||||
|
|
||||||
let guard = Guard::<'a, _> {
|
let guard = Guard {
|
||||||
g: msm.g.clone(),
|
msm,
|
||||||
h: msm.h.clone(),
|
|
||||||
neg_z1,
|
neg_z1,
|
||||||
params,
|
allinv,
|
||||||
scalars: msm.scalars.clone(),
|
challenges_sq,
|
||||||
bases: msm.bases.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((challenges_sq_packed, guard))
|
Ok((challenges_sq_packed, guard))
|
||||||
|
|
Loading…
Reference in New Issue