2020-09-07 09:22:25 -07:00
|
|
|
//! This module contains an implementation of the polynomial commitment scheme
|
|
|
|
//! described in the [Halo][halo] paper.
|
|
|
|
//!
|
|
|
|
//! [halo]: https://eprint.iacr.org/2019/1021
|
|
|
|
|
2020-09-12 11:55:48 -07:00
|
|
|
use super::{Coeff, LagrangeCoeff, Polynomial};
|
2020-09-09 06:00:36 -07:00
|
|
|
use crate::arithmetic::{
|
2020-09-12 09:45:11 -07:00
|
|
|
best_fft, best_multiexp, parallelize, Challenge, Curve, CurveAffine, Field,
|
2020-09-09 06:00:36 -07:00
|
|
|
};
|
2020-09-07 09:22:25 -07:00
|
|
|
use crate::transcript::Hasher;
|
|
|
|
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
|
|
|
|
|
|
|
mod prover;
|
|
|
|
mod verifier;
|
|
|
|
|
|
|
|
/// This is a proof object for the polynomial commitment scheme opening.
|
|
|
|
#[derive(Debug, Clone)]
|
2020-09-25 08:39:32 -07:00
|
|
|
pub struct Proof<C: CurveAffine> {
|
2020-09-07 09:22:25 -07:00
|
|
|
rounds: Vec<(C, C)>,
|
|
|
|
delta: C,
|
|
|
|
z1: C::Scalar,
|
|
|
|
z2: C::Scalar,
|
|
|
|
}
|
|
|
|
|
2020-09-12 21:31:29 -07:00
|
|
|
/// An accumulator instance consisting of an evaluation claim and a proof.
|
2020-09-12 20:37:10 -07:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Accumulator<C: CurveAffine> {
|
2020-09-12 21:31:29 -07:00
|
|
|
/// The claimed output of the linear-time polycommit opening protocol
|
2020-09-12 20:37:10 -07:00
|
|
|
pub g: C,
|
|
|
|
|
2020-09-12 21:31:29 -07:00
|
|
|
/// A vector of 128-bit challenges sampled by the verifier, to be used in
|
|
|
|
/// computing g.
|
2020-09-12 20:37:10 -07:00
|
|
|
pub challenges_sq_packed: Vec<Challenge>,
|
|
|
|
}
|
|
|
|
|
2020-09-09 06:00:36 -07:00
|
|
|
/// A multiscalar multiplication in the polynomial commitment scheme
|
2020-09-12 20:33:44 -07:00
|
|
|
#[derive(Debug, Clone)]
|
2020-09-12 11:55:48 -07:00
|
|
|
pub struct MSM<'a, C: CurveAffine> {
|
|
|
|
params: &'a Params<C>,
|
|
|
|
g_scalars: Option<Vec<C::Scalar>>,
|
|
|
|
h_scalar: Option<C::Scalar>,
|
|
|
|
other_scalars: Vec<C::Scalar>,
|
|
|
|
other_bases: Vec<C>,
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
|
|
|
|
2020-09-12 11:55:48 -07:00
|
|
|
impl<'a, C: CurveAffine> MSM<'a, C> {
|
2020-09-15 16:32:39 -07:00
|
|
|
/// Add another multiexp into this one
|
|
|
|
pub fn add_msm(&mut self, other: &Self) {
|
|
|
|
self.other_scalars.extend(other.other_scalars.iter());
|
|
|
|
self.other_bases.extend(other.other_bases.iter());
|
|
|
|
|
|
|
|
if let Some(g_scalars) = &other.g_scalars {
|
|
|
|
self.add_to_g(&g_scalars);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(h_scalar) = &other.h_scalar {
|
|
|
|
self.add_to_h(*h_scalar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-09 06:00:36 -07:00
|
|
|
/// Add arbitrary term (the scalar and the point)
|
|
|
|
pub fn add_term(&mut self, scalar: C::Scalar, point: C) {
|
2020-09-20 12:09:03 -07:00
|
|
|
self.other_scalars.push(scalar);
|
|
|
|
self.other_bases.push(point);
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
2020-09-10 04:50:02 -07:00
|
|
|
|
2020-09-13 08:10:37 -07:00
|
|
|
/// Add a vector of scalars to `g_scalars`. This function will panic if the
|
|
|
|
/// caller provides a slice of scalars that is not of length `params.n`.
|
|
|
|
// TODO: parallelize
|
2020-09-12 11:55:48 -07:00
|
|
|
pub fn add_to_g(&mut self, scalars: &[C::Scalar]) {
|
2020-09-13 08:10:37 -07:00
|
|
|
assert_eq!(scalars.len(), self.params.n as usize);
|
2020-09-12 11:55:48 -07:00
|
|
|
if let Some(g_scalars) = &mut self.g_scalars {
|
|
|
|
for (g_scalar, scalar) in g_scalars.iter_mut().zip(scalars.iter()) {
|
|
|
|
*g_scalar += &scalar;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.g_scalars = Some(scalars.to_vec());
|
2020-09-10 22:42:11 -07:00
|
|
|
}
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
2020-09-10 04:50:02 -07:00
|
|
|
|
2020-09-09 06:00:36 -07:00
|
|
|
/// Add term to h
|
2020-09-10 22:42:11 -07:00
|
|
|
pub fn add_to_h(&mut self, scalar: C::Scalar) {
|
2020-09-12 11:55:48 -07:00
|
|
|
self.h_scalar = self.h_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
2020-09-10 04:50:02 -07:00
|
|
|
|
2020-09-13 09:17:00 -07:00
|
|
|
/// Scale all scalars in the MSM by some scaling factor
|
2020-09-13 08:10:37 -07:00
|
|
|
// TODO: parallelize
|
2020-09-10 04:50:02 -07:00
|
|
|
pub fn scale(&mut self, factor: C::Scalar) {
|
2020-09-12 11:55:48 -07:00
|
|
|
if let Some(g_scalars) = &mut self.g_scalars {
|
|
|
|
for g_scalar in g_scalars.iter_mut() {
|
|
|
|
*g_scalar *= &factor;
|
|
|
|
}
|
2020-09-10 22:42:11 -07:00
|
|
|
}
|
2020-09-12 11:55:48 -07:00
|
|
|
|
2020-09-13 08:10:37 -07:00
|
|
|
// TODO: parallelize
|
2020-09-10 22:42:11 -07:00
|
|
|
for other_scalar in self.other_scalars.iter_mut() {
|
|
|
|
*other_scalar *= &factor;
|
2020-09-10 04:50:02 -07:00
|
|
|
}
|
2020-09-12 11:55:48 -07:00
|
|
|
self.h_scalar = self.h_scalar.map(|a| a * &factor);
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
2020-09-10 04:50:02 -07:00
|
|
|
|
2020-09-09 06:00:36 -07:00
|
|
|
/// Perform multiexp and check that it results in zero
|
2020-09-20 12:09:03 -07:00
|
|
|
pub fn eval(self) -> bool {
|
2020-09-12 11:55:48 -07:00
|
|
|
let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0)
|
|
|
|
+ self.h_scalar.map(|_| 1).unwrap_or(0)
|
|
|
|
+ self.other_scalars.len();
|
|
|
|
let mut scalars: Vec<C::Scalar> = Vec::with_capacity(len);
|
|
|
|
let mut bases: Vec<C> = Vec::with_capacity(len);
|
2020-09-10 22:42:11 -07:00
|
|
|
|
|
|
|
scalars.extend(&self.other_scalars);
|
|
|
|
bases.extend(&self.other_bases);
|
|
|
|
|
|
|
|
if let Some(h_scalar) = self.h_scalar {
|
|
|
|
scalars.push(h_scalar);
|
2020-09-12 11:55:48 -07:00
|
|
|
bases.push(self.params.h);
|
2020-09-10 22:42:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(g_scalars) = &self.g_scalars {
|
|
|
|
scalars.extend(g_scalars);
|
2020-09-12 11:55:48 -07:00
|
|
|
bases.extend(self.params.g.iter());
|
2020-09-10 22:42:11 -07:00
|
|
|
}
|
|
|
|
|
2020-09-13 09:14:32 -07:00
|
|
|
assert_eq!(scalars.len(), len);
|
|
|
|
|
2020-09-10 22:42:11 -07:00
|
|
|
bool::from(best_multiexp(&scalars, &bases).is_zero())
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-07 09:22:25 -07:00
|
|
|
/// These are the public parameters for the polynomial commitment scheme.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Params<C: CurveAffine> {
|
|
|
|
pub(crate) k: u32,
|
|
|
|
pub(crate) n: u64,
|
|
|
|
pub(crate) g: Vec<C>,
|
|
|
|
pub(crate) g_lagrange: Vec<C>,
|
|
|
|
pub(crate) h: C,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: CurveAffine> Params<C> {
|
|
|
|
/// Initializes parameters for the curve, given a random oracle to draw
|
|
|
|
/// points from.
|
|
|
|
pub fn new<H: Hasher<C::Base>>(k: u32) -> Self {
|
|
|
|
// This is usually a limitation on the curve, but we also want 32-bit
|
|
|
|
// architectures to be supported.
|
|
|
|
assert!(k < 32);
|
|
|
|
// No goofy hardware please.
|
|
|
|
assert!(core::mem::size_of::<usize>() >= 4);
|
|
|
|
|
|
|
|
let n: u64 = 1 << k;
|
|
|
|
|
|
|
|
let g = {
|
|
|
|
let hasher = &H::init(C::Base::zero());
|
|
|
|
|
|
|
|
let mut g = Vec::with_capacity(n as usize);
|
|
|
|
g.resize(n as usize, C::zero());
|
|
|
|
|
|
|
|
parallelize(&mut g, move |g, start| {
|
|
|
|
let mut cur_value = C::Base::from(start as u64);
|
|
|
|
for g in g.iter_mut() {
|
|
|
|
let mut hasher = hasher.clone();
|
|
|
|
hasher.absorb(cur_value);
|
|
|
|
cur_value += &C::Base::one();
|
|
|
|
loop {
|
|
|
|
let x = hasher.squeeze().to_bytes();
|
|
|
|
let p = C::from_bytes(&x);
|
|
|
|
if bool::from(p.is_some()) {
|
|
|
|
*g = p.unwrap();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
g
|
|
|
|
};
|
|
|
|
|
|
|
|
// Let's evaluate all of the Lagrange basis polynomials
|
|
|
|
// using an inverse FFT.
|
|
|
|
let mut alpha_inv = C::Scalar::ROOT_OF_UNITY_INV;
|
|
|
|
for _ in k..C::Scalar::S {
|
|
|
|
alpha_inv = alpha_inv.square();
|
|
|
|
}
|
|
|
|
let mut g_lagrange_projective = g.iter().map(|g| g.to_projective()).collect::<Vec<_>>();
|
|
|
|
best_fft(&mut g_lagrange_projective, alpha_inv, k);
|
|
|
|
let minv = C::Scalar::TWO_INV.pow_vartime(&[k as u64, 0, 0, 0]);
|
|
|
|
parallelize(&mut g_lagrange_projective, |g, _| {
|
|
|
|
for g in g.iter_mut() {
|
|
|
|
*g *= minv;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let g_lagrange = {
|
|
|
|
let mut g_lagrange = vec![C::zero(); n as usize];
|
|
|
|
parallelize(&mut g_lagrange, |g_lagrange, starts| {
|
|
|
|
C::Projective::batch_to_affine(
|
|
|
|
&g_lagrange_projective[starts..(starts + g_lagrange.len())],
|
|
|
|
g_lagrange,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
drop(g_lagrange_projective);
|
|
|
|
g_lagrange
|
|
|
|
};
|
|
|
|
|
|
|
|
let h = {
|
|
|
|
let mut hasher = H::init(C::Base::zero());
|
|
|
|
hasher.absorb(-C::Base::one());
|
|
|
|
let x = hasher.squeeze().to_bytes();
|
|
|
|
let p = C::from_bytes(&x);
|
|
|
|
p.unwrap()
|
|
|
|
};
|
|
|
|
|
|
|
|
Params {
|
|
|
|
k,
|
|
|
|
n,
|
|
|
|
g,
|
|
|
|
g_lagrange,
|
|
|
|
h,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This computes a commitment to a polynomial described by the provided
|
|
|
|
/// slice of coefficients. The commitment will be blinded by the blinding
|
|
|
|
/// factor `r`.
|
|
|
|
pub fn commit(
|
|
|
|
&self,
|
|
|
|
poly: &Polynomial<C::Scalar, Coeff>,
|
|
|
|
r: Blind<C::Scalar>,
|
|
|
|
) -> C::Projective {
|
|
|
|
let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
|
|
|
|
let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
|
|
|
|
|
|
|
|
tmp_scalars.extend(poly.iter());
|
|
|
|
tmp_scalars.push(r.0);
|
|
|
|
|
|
|
|
tmp_bases.extend(self.g.iter());
|
|
|
|
tmp_bases.push(self.h);
|
|
|
|
|
|
|
|
best_multiexp::<C>(&tmp_scalars, &tmp_bases)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This commits to a polynomial using its evaluations over the $2^k$ size
|
|
|
|
/// evaluation domain. The commitment will be blinded by the blinding factor
|
|
|
|
/// `r`.
|
|
|
|
pub fn commit_lagrange(
|
|
|
|
&self,
|
|
|
|
poly: &Polynomial<C::Scalar, LagrangeCoeff>,
|
|
|
|
r: Blind<C::Scalar>,
|
|
|
|
) -> C::Projective {
|
|
|
|
let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
|
|
|
|
let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
|
|
|
|
|
|
|
|
tmp_scalars.extend(poly.iter());
|
|
|
|
tmp_scalars.push(r.0);
|
|
|
|
|
|
|
|
tmp_bases.extend(self.g_lagrange.iter());
|
|
|
|
tmp_bases.push(self.h);
|
|
|
|
|
|
|
|
best_multiexp::<C>(&tmp_scalars, &tmp_bases)
|
|
|
|
}
|
2020-09-12 11:55:48 -07:00
|
|
|
|
|
|
|
/// Generates an empty multiscalar multiplication struct using the
|
|
|
|
/// appropriate params.
|
2020-09-13 08:07:05 -07:00
|
|
|
pub fn empty_msm(&self) -> MSM<C> {
|
2020-09-12 11:55:48 -07:00
|
|
|
let g_scalars = None;
|
|
|
|
let h_scalar = None;
|
|
|
|
let other_scalars = vec![];
|
|
|
|
let other_bases = vec![];
|
|
|
|
|
|
|
|
MSM {
|
|
|
|
params: &self,
|
|
|
|
g_scalars,
|
|
|
|
h_scalar,
|
|
|
|
other_scalars,
|
|
|
|
other_bases,
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 09:44:56 -07:00
|
|
|
|
|
|
|
/// Getter for g generators
|
|
|
|
pub fn get_g(&self) -> Vec<C> {
|
|
|
|
self.g.clone()
|
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
}
|
|
|
|
|
2020-09-09 06:00:36 -07:00
|
|
|
/// A guard returned by the verifier
|
2020-09-12 20:33:44 -07:00
|
|
|
#[derive(Debug, Clone)]
|
2020-09-12 11:55:48 -07:00
|
|
|
pub struct Guard<'a, C: CurveAffine> {
|
|
|
|
msm: MSM<'a, C>,
|
2020-09-10 22:42:11 -07:00
|
|
|
neg_z1: C::Scalar,
|
|
|
|
allinv: C::Scalar,
|
|
|
|
challenges_sq: Vec<C::Scalar>,
|
2020-09-12 09:45:11 -07:00
|
|
|
challenges_sq_packed: Vec<Challenge>,
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
|
|
|
|
2020-09-12 11:55:48 -07:00
|
|
|
impl<'a, C: CurveAffine> Guard<'a, C> {
|
2020-09-09 06:00:36 -07:00
|
|
|
/// Lets caller supply the challenges and obtain an MSM with updated
|
|
|
|
/// scalars and points.
|
2020-09-12 11:55:48 -07:00
|
|
|
pub fn use_challenges(mut self) -> MSM<'a, C> {
|
2020-09-13 09:14:32 -07:00
|
|
|
let s = compute_s(&self.challenges_sq, self.allinv * &self.neg_z1);
|
|
|
|
self.msm.add_to_g(&s);
|
2020-09-10 22:42:11 -07:00
|
|
|
|
2020-09-12 11:55:48 -07:00
|
|
|
self.msm
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Lets caller supply the purported G point and simply appends it to
|
|
|
|
/// return an updated MSM.
|
2020-09-12 20:37:10 -07:00
|
|
|
pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator<C>) {
|
2020-09-20 12:09:03 -07:00
|
|
|
self.msm.add_term(self.neg_z1, g);
|
2020-09-10 22:42:11 -07:00
|
|
|
|
2020-09-12 20:37:10 -07:00
|
|
|
let accumulator = Accumulator {
|
|
|
|
g,
|
|
|
|
challenges_sq_packed: self.challenges_sq_packed,
|
|
|
|
};
|
|
|
|
|
|
|
|
(self.msm, accumulator)
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
2020-09-12 20:47:21 -07:00
|
|
|
|
|
|
|
/// Computes the g value when given a potential scalar as input.
|
2020-09-13 09:14:32 -07:00
|
|
|
pub fn compute_g(&self) -> C {
|
|
|
|
let s = compute_s(&self.challenges_sq, self.allinv);
|
2020-09-13 08:10:37 -07:00
|
|
|
best_multiexp(&s, &self.msm.params.g).to_affine()
|
2020-09-12 20:47:21 -07:00
|
|
|
}
|
2020-09-09 06:00:36 -07:00
|
|
|
}
|
|
|
|
|
2020-09-07 09:22:25 -07:00
|
|
|
/// Wrapper type around a blinding factor.
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
|
|
pub struct Blind<F>(pub F);
|
|
|
|
|
|
|
|
impl<F: Field> Default for Blind<F> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Blind(F::one())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> Add for Blind<F> {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, rhs: Blind<F>) -> Self {
|
|
|
|
Blind(self.0 + rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> Mul for Blind<F> {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn mul(self, rhs: Blind<F>) -> Self {
|
|
|
|
Blind(self.0 * rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> AddAssign for Blind<F> {
|
|
|
|
fn add_assign(&mut self, rhs: Blind<F>) {
|
|
|
|
self.0 += rhs.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> MulAssign for Blind<F> {
|
|
|
|
fn mul_assign(&mut self, rhs: Blind<F>) {
|
|
|
|
self.0 *= rhs.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> AddAssign<F> for Blind<F> {
|
|
|
|
fn add_assign(&mut self, rhs: F) {
|
|
|
|
self.0 += rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> MulAssign<F> for Blind<F> {
|
|
|
|
fn mul_assign(&mut self, rhs: F) {
|
|
|
|
self.0 *= rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_commit_lagrange() {
|
|
|
|
const K: u32 = 6;
|
|
|
|
|
|
|
|
use crate::arithmetic::{EpAffine, Fp, Fq};
|
|
|
|
use crate::transcript::DummyHash;
|
|
|
|
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
|
|
|
let domain = super::EvaluationDomain::new(1, K);
|
|
|
|
|
|
|
|
let mut a = domain.empty_lagrange();
|
|
|
|
|
|
|
|
for (i, a) in a.iter_mut().enumerate() {
|
|
|
|
*a = Fq::from(i as u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
let b = domain.lagrange_to_coeff(a.clone());
|
|
|
|
|
|
|
|
let alpha = Blind(Fq::random());
|
|
|
|
|
|
|
|
assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_opening_proof() {
|
|
|
|
const K: u32 = 6;
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
commitment::{Blind, Params},
|
|
|
|
EvaluationDomain,
|
|
|
|
};
|
|
|
|
use crate::arithmetic::{
|
|
|
|
eval_polynomial, get_challenge_scalar, Challenge, Curve, EpAffine, Field, Fp, Fq,
|
|
|
|
};
|
|
|
|
use crate::transcript::{DummyHash, Hasher};
|
|
|
|
|
|
|
|
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
|
|
|
let domain = EvaluationDomain::new(1, K);
|
|
|
|
|
|
|
|
let mut px = domain.empty_coeff();
|
|
|
|
|
|
|
|
for (i, a) in px.iter_mut().enumerate() {
|
|
|
|
*a = Fq::from(i as u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
let blind = Blind(Fq::random());
|
|
|
|
|
|
|
|
let p = params.commit(&px, blind).to_affine();
|
|
|
|
|
|
|
|
let mut transcript = DummyHash::init(Field::one());
|
|
|
|
let (p_x, p_y) = p.get_xy().unwrap();
|
|
|
|
transcript.absorb(p_x);
|
|
|
|
transcript.absorb(p_y);
|
|
|
|
let x_packed = transcript.squeeze().get_lower_128();
|
|
|
|
let x: Fq = get_challenge_scalar(Challenge(x_packed));
|
|
|
|
|
|
|
|
// Evaluate the polynomial
|
|
|
|
let v = eval_polynomial(&px, x);
|
|
|
|
|
|
|
|
transcript.absorb(Fp::from_bytes(&v.to_bytes()).unwrap()); // unlikely to fail since p ~ q
|
|
|
|
|
|
|
|
loop {
|
2020-09-13 08:10:37 -07:00
|
|
|
let transcript_dup = transcript.clone();
|
2020-09-07 09:22:25 -07:00
|
|
|
|
2020-09-25 08:39:32 -07:00
|
|
|
let opening_proof = Proof::create(¶ms, &mut transcript, &px, blind, x);
|
2020-09-07 09:22:25 -07:00
|
|
|
if opening_proof.is_err() {
|
|
|
|
transcript = transcript_dup;
|
|
|
|
transcript.absorb(Field::one());
|
|
|
|
} else {
|
|
|
|
let opening_proof = opening_proof.unwrap();
|
2020-09-09 06:00:36 -07:00
|
|
|
// Verify the opening proof
|
2020-09-15 16:42:02 -07:00
|
|
|
let mut commitment_msm = params.empty_msm();
|
|
|
|
commitment_msm.add_term(Field::one(), p);
|
2020-09-12 09:45:11 -07:00
|
|
|
let guard = opening_proof
|
2020-09-15 16:42:02 -07:00
|
|
|
.verify(
|
|
|
|
¶ms,
|
|
|
|
params.empty_msm(),
|
|
|
|
&mut transcript_dup.clone(),
|
|
|
|
x,
|
|
|
|
commitment_msm,
|
|
|
|
v,
|
|
|
|
)
|
2020-09-13 08:10:37 -07:00
|
|
|
.unwrap();
|
|
|
|
|
2020-09-13 09:17:00 -07:00
|
|
|
// Test guard behavior prior to checking another proof
|
|
|
|
{
|
|
|
|
// Test use_challenges()
|
|
|
|
let msm_challenges = guard.clone().use_challenges();
|
2020-09-20 12:09:03 -07:00
|
|
|
assert!(msm_challenges.eval());
|
2020-09-13 09:17:00 -07:00
|
|
|
|
|
|
|
// Test use_g()
|
|
|
|
let g = guard.compute_g();
|
|
|
|
let (msm_g, _accumulator) = guard.clone().use_g(g);
|
2020-09-20 12:09:03 -07:00
|
|
|
assert!(msm_g.eval());
|
2020-09-13 09:17:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check another proof to populate `msm.g_scalars`
|
2020-09-15 16:42:02 -07:00
|
|
|
let msm = guard.use_challenges();
|
|
|
|
let mut commitment_msm = params.empty_msm();
|
|
|
|
commitment_msm.add_term(Field::one(), p);
|
2020-09-13 09:17:00 -07:00
|
|
|
let guard = opening_proof
|
2020-09-15 16:42:02 -07:00
|
|
|
.verify(
|
|
|
|
¶ms,
|
|
|
|
msm,
|
|
|
|
&mut transcript_dup.clone(),
|
|
|
|
x,
|
|
|
|
commitment_msm,
|
|
|
|
v,
|
|
|
|
)
|
2020-09-09 06:00:36 -07:00
|
|
|
.unwrap();
|
|
|
|
|
2020-09-12 20:47:21 -07:00
|
|
|
// Test use_challenges()
|
2020-09-13 09:17:00 -07:00
|
|
|
let msm_challenges = guard.clone().use_challenges();
|
2020-09-20 12:09:03 -07:00
|
|
|
assert!(msm_challenges.eval());
|
2020-09-12 20:47:21 -07:00
|
|
|
|
|
|
|
// Test use_g()
|
2020-09-13 09:17:00 -07:00
|
|
|
let g = guard.compute_g();
|
|
|
|
let (msm_g, _accumulator) = guard.clone().use_g(g);
|
2020-09-20 12:09:03 -07:00
|
|
|
assert!(msm_g.eval());
|
2020-09-09 06:00:36 -07:00
|
|
|
|
2020-09-07 09:22:25 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-09 06:00:36 -07:00
|
|
|
|
|
|
|
// TODO: parallelize
|
|
|
|
fn compute_s<F: Field>(challenges_sq: &[F], allinv: F) -> Vec<F> {
|
|
|
|
let lg_n = challenges_sq.len();
|
|
|
|
let n = 1 << lg_n;
|
|
|
|
|
|
|
|
let mut s = Vec::with_capacity(n);
|
|
|
|
s.push(allinv);
|
|
|
|
for i in 1..n {
|
|
|
|
let lg_i = (32 - 1 - (i as u32).leading_zeros()) as usize;
|
|
|
|
let k = 1 << lg_i;
|
|
|
|
let u_lg_i_sq = challenges_sq[(lg_n - 1) - lg_i];
|
|
|
|
s.push(s[i - k] * u_lg_i_sq);
|
|
|
|
}
|
|
|
|
|
|
|
|
s
|
|
|
|
}
|