mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
(WIP) broken implementation of generalized PLONK
This commit is contained in:
parent
6051814c4b
commit
ad106f1119
7 changed files with 509 additions and 413 deletions
|
|
@ -313,6 +313,29 @@ pub fn compute_inner_product<F: Field>(a: &[F], b: &[F]) -> F {
|
|||
acc
|
||||
}
|
||||
|
||||
/// Divides polynomial `a` in `X` by `X - b` with
|
||||
/// no remainder.
|
||||
pub fn kate_division<'a, F: Field, I: IntoIterator<Item = &'a F>>(a: I, mut b: F) -> Vec<F>
|
||||
where
|
||||
I::IntoIter: DoubleEndedIterator + ExactSizeIterator,
|
||||
{
|
||||
b = -b;
|
||||
let a = a.into_iter();
|
||||
|
||||
let mut q = vec![F::zero(); a.len() - 1];
|
||||
|
||||
let mut tmp = F::zero();
|
||||
for (q, r) in q.iter_mut().rev().zip(a.rev()) {
|
||||
let mut lead_coeff = *r;
|
||||
lead_coeff.sub_assign(&tmp);
|
||||
*q = lead_coeff;
|
||||
tmp = lead_coeff;
|
||||
tmp.mul_assign(&b);
|
||||
}
|
||||
|
||||
q
|
||||
}
|
||||
|
||||
/// This simple utility function will parallelize an operation that is to be
|
||||
/// performed over a mutable slice.
|
||||
pub fn parallelize<T: Send, F: Fn(&mut [T], usize) + Send + Clone>(v: &mut [T], f: F) {
|
||||
|
|
|
|||
53
src/plonk.rs
53
src/plonk.rs
|
|
@ -23,28 +23,15 @@ pub use verifier::*;
|
|||
|
||||
use domain::EvaluationDomain;
|
||||
|
||||
// TODO: remove this
|
||||
const GATE_DEGREE: u32 = 3;
|
||||
|
||||
/// This is a structured reference string (SRS) that is (deterministically)
|
||||
/// computed from a specific circuit and parameters for the polynomial
|
||||
/// commitment scheme.
|
||||
#[derive(Debug)]
|
||||
pub struct SRS<C: CurveAffine> {
|
||||
sa: (Vec<C::Scalar>, Vec<C::Scalar>),
|
||||
sb: (Vec<C::Scalar>, Vec<C::Scalar>),
|
||||
sc: (Vec<C::Scalar>, Vec<C::Scalar>),
|
||||
sd: (Vec<C::Scalar>, Vec<C::Scalar>),
|
||||
sm: (Vec<C::Scalar>, Vec<C::Scalar>),
|
||||
sa_commitment: C,
|
||||
sb_commitment: C,
|
||||
sc_commitment: C,
|
||||
sd_commitment: C,
|
||||
sm_commitment: C,
|
||||
domain: EvaluationDomain<C::Scalar>,
|
||||
|
||||
fixed_commitments: Vec<C>,
|
||||
fixed_polys: Vec<(Vec<C::Scalar>, Vec<C::Scalar>)>,
|
||||
fixed_polys: Vec<Vec<C::Scalar>>,
|
||||
fixed_cosets: Vec<Vec<C::Scalar>>,
|
||||
meta: MetaCircuit<C::Scalar>,
|
||||
}
|
||||
|
||||
|
|
@ -52,22 +39,13 @@ pub struct SRS<C: CurveAffine> {
|
|||
// This structure must never allow points at infinity.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Proof<C: CurveAffine> {
|
||||
a_commitment: C,
|
||||
b_commitment: C,
|
||||
c_commitment: C,
|
||||
d_commitment: C,
|
||||
advice_commitments: Vec<C>,
|
||||
h_commitments: Vec<C>,
|
||||
a_eval_x: C::Scalar,
|
||||
b_eval_x: C::Scalar,
|
||||
c_eval_x: C::Scalar,
|
||||
d_eval_x: C::Scalar,
|
||||
sa_eval_x: C::Scalar,
|
||||
sb_eval_x: C::Scalar,
|
||||
sc_eval_x: C::Scalar,
|
||||
sd_eval_x: C::Scalar,
|
||||
sm_eval_x: C::Scalar,
|
||||
advice_evals_x: Vec<C::Scalar>,
|
||||
fixed_evals_x: Vec<C::Scalar>,
|
||||
h_evals_x: Vec<C::Scalar>,
|
||||
f_commitment: C,
|
||||
q_evals: Vec<C::Scalar>,
|
||||
opening: OpeningProof<C>,
|
||||
}
|
||||
|
||||
|
|
@ -167,30 +145,13 @@ fn test_proving() {
|
|||
cs: &mut impl ConstraintSystem<F>,
|
||||
config: MyConfig,
|
||||
) -> Result<(), Error> {
|
||||
for _ in 0..10 {
|
||||
let (_, _, _, _) = cs.multiply(|| {
|
||||
let a = self.a.ok_or(Error::SynthesisError)?;
|
||||
let a2 = a.square();
|
||||
Ok((a, a, a2))
|
||||
})?;
|
||||
//cs.copy(a, b);
|
||||
let (_, _, _, _) = cs.add(|| {
|
||||
let a = self.a.ok_or(Error::SynthesisError)?;
|
||||
let a2 = a.square();
|
||||
let a3 = a + a2;
|
||||
Ok((a, a2, a3))
|
||||
})?;
|
||||
//cs.copy(a, d);
|
||||
//cs.copy(c, e);
|
||||
}
|
||||
|
||||
// Similar to the above...
|
||||
let mut row = 0;
|
||||
for _ in 0..10 {
|
||||
cs.assign_advice(config.a, row, || self.a.ok_or(Error::SynthesisError))?;
|
||||
cs.assign_advice(config.b, row, || self.a.ok_or(Error::SynthesisError))?;
|
||||
let a_squared = self.a.map(|a| a.square());
|
||||
cs.assign_advice(config.c, row, || self.a.ok_or(Error::SynthesisError))?;
|
||||
cs.assign_advice(config.c, row, || a_squared.ok_or(Error::SynthesisError))?;
|
||||
// Multiplication gate
|
||||
cs.assign_fixed(config.sa, row, || Ok(Field::zero()))?;
|
||||
cs.assign_fixed(config.sb, row, || Ok(Field::zero()))?;
|
||||
|
|
|
|||
|
|
@ -5,20 +5,6 @@ use std::collections::HashMap;
|
|||
use super::Error;
|
||||
use crate::arithmetic::Field;
|
||||
|
||||
/// This represents a PLONK wire, which could be a fixed (selector) wire or an
|
||||
/// advice wire.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Wire {
|
||||
/// A wires
|
||||
A,
|
||||
/// B wires
|
||||
B,
|
||||
/// C wires
|
||||
C,
|
||||
/// D wires
|
||||
D,
|
||||
}
|
||||
|
||||
/// This represents a wire which has a fixed (permanent) value
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct FixedWire(pub usize);
|
||||
|
|
@ -27,10 +13,6 @@ pub struct FixedWire(pub usize);
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct AdviceWire(pub usize);
|
||||
|
||||
/// Represents a pointer to a value in the constraint system.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Variable(pub Wire, pub usize);
|
||||
|
||||
/// This trait allows a [`Circuit`] to direct some backend to assign a witness
|
||||
/// for a constraint system.
|
||||
pub trait ConstraintSystem<F: Field> {
|
||||
|
|
@ -50,39 +32,6 @@ pub trait ConstraintSystem<F: Field> {
|
|||
to: impl FnOnce() -> Result<F, Error>,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Creates a gate.
|
||||
fn create_gate(
|
||||
&mut self,
|
||||
sa: F,
|
||||
sb: F,
|
||||
sc: F,
|
||||
sd: F,
|
||||
sm: F,
|
||||
f: impl Fn() -> Result<(F, F, F, F), Error>,
|
||||
) -> Result<(Variable, Variable, Variable, Variable), Error>;
|
||||
|
||||
/// a * b - c = 0
|
||||
fn multiply(
|
||||
&mut self,
|
||||
f: impl Fn() -> Result<(F, F, F), Error>,
|
||||
) -> Result<(Variable, Variable, Variable, Variable), Error> {
|
||||
self.create_gate(F::zero(), F::zero(), F::one(), F::zero(), F::one(), || {
|
||||
let (a, b, c) = f()?;
|
||||
Ok((a, b, c, F::zero()))
|
||||
})
|
||||
}
|
||||
|
||||
/// a + b - c = 0
|
||||
fn add(
|
||||
&mut self,
|
||||
f: impl Fn() -> Result<(F, F, F), Error>,
|
||||
) -> Result<(Variable, Variable, Variable, Variable), Error> {
|
||||
self.create_gate(F::one(), F::one(), F::one(), F::zero(), F::zero(), || {
|
||||
let (a, b, c) = f()?;
|
||||
Ok((a, b, c, F::zero()))
|
||||
})
|
||||
}
|
||||
|
||||
// fn copy(&mut self, left: Wire, right: Wire);
|
||||
}
|
||||
|
||||
|
|
@ -111,9 +60,9 @@ pub trait Circuit<F: Field> {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Polynomial<F> {
|
||||
/// This is a fixed wire queried at a certain relative location
|
||||
Fixed(FixedWire, i32),
|
||||
Fixed(usize),
|
||||
/// This is an advice (witness) wire queried at a certain relative location
|
||||
Advice(AdviceWire, i32),
|
||||
Advice(usize),
|
||||
/// This is the sum of two polynomials
|
||||
Sum(Box<Polynomial<F>>, Box<Polynomial<F>>),
|
||||
/// This is the product of two polynomials
|
||||
|
|
@ -123,17 +72,19 @@ pub enum Polynomial<F> {
|
|||
}
|
||||
|
||||
impl<F: Field> Polynomial<F> {
|
||||
fn evaluate<T>(
|
||||
/// Evaluate the polynomial using the provided closures to perform the
|
||||
/// operations.
|
||||
pub fn evaluate<T>(
|
||||
&self,
|
||||
fixed_wire: &impl Fn(FixedWire, i32) -> T,
|
||||
advice_wire: &impl Fn(AdviceWire, i32) -> T,
|
||||
fixed_wire: &impl Fn(usize) -> T,
|
||||
advice_wire: &impl Fn(usize) -> T,
|
||||
sum: &impl Fn(T, T) -> T,
|
||||
product: &impl Fn(T, T) -> T,
|
||||
scaled: &impl Fn(T, F) -> T,
|
||||
) -> T {
|
||||
match self {
|
||||
Polynomial::Fixed(a, location) => fixed_wire(*a, *location),
|
||||
Polynomial::Advice(a, location) => advice_wire(*a, *location),
|
||||
Polynomial::Fixed(index) => fixed_wire(*index),
|
||||
Polynomial::Advice(index) => advice_wire(*index),
|
||||
Polynomial::Sum(a, b) => {
|
||||
let a = a.evaluate(fixed_wire, advice_wire, sum, product, scaled);
|
||||
let b = b.evaluate(fixed_wire, advice_wire, sum, product, scaled);
|
||||
|
|
@ -150,13 +101,12 @@ impl<F: Field> Polynomial<F> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> Polynomial<F> {
|
||||
fn degree(&self) -> usize {
|
||||
/// Compute the degree of this polynomial
|
||||
pub fn degree(&self) -> usize {
|
||||
match self {
|
||||
Polynomial::Fixed(_, _) => 1,
|
||||
Polynomial::Advice(_, _) => 1,
|
||||
Polynomial::Fixed(_) => 1,
|
||||
Polynomial::Advice(_) => 1,
|
||||
Polynomial::Sum(a, b) => max(a.degree(), b.degree()),
|
||||
Polynomial::Product(a, b) => a.degree() + b.degree(),
|
||||
Polynomial::Scaled(poly, _) => poly.degree(),
|
||||
|
|
@ -192,20 +142,24 @@ pub struct MetaCircuit<F> {
|
|||
pub(crate) num_fixed_wires: usize,
|
||||
pub(crate) num_advice_wires: usize,
|
||||
// permutations: Vec<Vec<Wire>>,
|
||||
gates: Vec<Polynomial<F>>,
|
||||
advice_queries: HashMap<(AdviceWire, i32), usize>,
|
||||
fixed_queries: HashMap<(FixedWire, i32), usize>,
|
||||
// num_queries: usize,
|
||||
pub(crate) gates: Vec<Polynomial<F>>,
|
||||
pub(crate) advice_queries: Vec<(AdviceWire, i32)>,
|
||||
pub(crate) fixed_queries: Vec<(FixedWire, i32)>,
|
||||
pub(crate) query_rows: HashMap<i32, usize>,
|
||||
}
|
||||
|
||||
impl<F: Field> Default for MetaCircuit<F> {
|
||||
fn default() -> MetaCircuit<F> {
|
||||
let mut query_rows = HashMap::new();
|
||||
query_rows.insert(0, 0);
|
||||
|
||||
MetaCircuit {
|
||||
num_fixed_wires: 0,
|
||||
num_advice_wires: 0,
|
||||
gates: vec![],
|
||||
fixed_queries: HashMap::new(),
|
||||
advice_queries: HashMap::new(),
|
||||
fixed_queries: Vec::new(),
|
||||
advice_queries: Vec::new(),
|
||||
query_rows,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -213,18 +167,30 @@ impl<F: Field> Default for MetaCircuit<F> {
|
|||
impl<F: Field> MetaCircuit<F> {
|
||||
/// Query a fixed wire at a relative position
|
||||
pub fn query_fixed(&mut self, wire: FixedWire, at: i32) -> Polynomial<F> {
|
||||
let len = self.fixed_queries.len();
|
||||
self.fixed_queries.entry((wire, at)).or_insert_with(|| len);
|
||||
{
|
||||
let len = self.query_rows.len();
|
||||
self.query_rows.entry(at).or_insert(len);
|
||||
}
|
||||
|
||||
Polynomial::Fixed(wire, at)
|
||||
// TODO: check for existing query so we don't make redundant queries
|
||||
let index = self.fixed_queries.len();
|
||||
self.fixed_queries.push((wire, at));
|
||||
|
||||
Polynomial::Fixed(index)
|
||||
}
|
||||
|
||||
/// Query an advice wire at a relative position
|
||||
pub fn query_advice(&mut self, wire: AdviceWire, at: i32) -> Polynomial<F> {
|
||||
let len = self.advice_queries.len();
|
||||
self.advice_queries.entry((wire, at)).or_insert_with(|| len);
|
||||
{
|
||||
let len = self.query_rows.len();
|
||||
self.query_rows.entry(at).or_insert(len);
|
||||
}
|
||||
|
||||
Polynomial::Advice(wire, at)
|
||||
// TODO: check for existing query so we don't make redundant queries
|
||||
let index = self.advice_queries.len();
|
||||
self.advice_queries.push((wire, at));
|
||||
|
||||
Polynomial::Advice(index)
|
||||
}
|
||||
|
||||
/// Create a new gate
|
||||
|
|
@ -239,6 +205,7 @@ impl<F: Field> MetaCircuit<F> {
|
|||
self.num_fixed_wires += 1;
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Allocate a new advice wire
|
||||
pub fn advice_wire(&mut self) -> AdviceWire {
|
||||
let tmp = AdviceWire(self.num_advice_wires);
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
Self::distribute_powers(&mut a, g);
|
||||
}
|
||||
a.resize(1 << self.extended_k, G::group_zero());
|
||||
a.resize(self.coset_len(), G::group_zero());
|
||||
best_fft(&mut a, self.extended_omega, self.extended_k);
|
||||
a
|
||||
}
|
||||
|
|
@ -149,7 +149,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// This function will panic if the provided vector is not the correct
|
||||
/// length.
|
||||
pub fn from_coset(&self, mut a: Vec<G>) -> Vec<G> {
|
||||
assert_eq!(a.len(), 1 << self.extended_k);
|
||||
assert_eq!(a.len(), self.coset_len());
|
||||
|
||||
// Inverse FFT
|
||||
Self::ifft(
|
||||
|
|
@ -174,7 +174,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// This divides the polynomial (in the coset domain) by the vanishing
|
||||
/// polynomial.
|
||||
pub fn divide_by_vanishing_poly(&self, mut h_poly: Vec<G>) -> Vec<G> {
|
||||
assert_eq!(h_poly.len(), 1 << self.extended_k);
|
||||
assert_eq!(h_poly.len(), self.coset_len());
|
||||
|
||||
// Divide to obtain the quotient polynomial in the coset evaluation
|
||||
// domain.
|
||||
|
|
@ -221,4 +221,16 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn coset_len(&self) -> usize {
|
||||
1 << self.extended_k
|
||||
}
|
||||
|
||||
pub fn get_omega(&self) -> G::Scalar {
|
||||
self.omega
|
||||
}
|
||||
|
||||
pub fn get_omega_inv(&self) -> G::Scalar {
|
||||
self.omega_inv
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use super::{
|
||||
circuit::{AdviceWire, Circuit, ConstraintSystem, FixedWire, MetaCircuit, Variable, Wire},
|
||||
circuit::{AdviceWire, Circuit, ConstraintSystem, FixedWire, MetaCircuit},
|
||||
hash_point, Error, Proof, SRS,
|
||||
};
|
||||
use crate::arithmetic::{
|
||||
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, Field,
|
||||
eval_polynomial, get_challenge_scalar, kate_division, parallelize, Challenge, Curve,
|
||||
CurveAffine, Field,
|
||||
};
|
||||
use crate::polycommit::Params;
|
||||
use crate::transcript::Hasher;
|
||||
|
|
@ -22,15 +23,6 @@ impl<C: CurveAffine> Proof<C> {
|
|||
circuit: &ConcreteCircuit,
|
||||
) -> Result<Self, Error> {
|
||||
struct WitnessCollection<F: Field> {
|
||||
a: Vec<F>,
|
||||
b: Vec<F>,
|
||||
c: Vec<F>,
|
||||
d: Vec<F>,
|
||||
sa: Vec<F>,
|
||||
sb: Vec<F>,
|
||||
sc: Vec<F>,
|
||||
sd: Vec<F>,
|
||||
sm: Vec<F>,
|
||||
advice: Vec<Vec<F>>,
|
||||
}
|
||||
|
||||
|
|
@ -60,52 +52,12 @@ impl<C: CurveAffine> Proof<C> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_gate(
|
||||
&mut self,
|
||||
sa: F,
|
||||
sb: F,
|
||||
sc: F,
|
||||
sd: F,
|
||||
sm: F,
|
||||
f: impl Fn() -> Result<(F, F, F, F), Error>,
|
||||
) -> Result<(Variable, Variable, Variable, Variable), Error> {
|
||||
let (a, b, c, d) = f()?;
|
||||
let tmp = Ok((
|
||||
Variable(Wire::A, self.a.len()),
|
||||
Variable(Wire::B, self.a.len()),
|
||||
Variable(Wire::C, self.a.len()),
|
||||
Variable(Wire::D, self.a.len()),
|
||||
));
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
self.d.push(d);
|
||||
self.sa.push(sa);
|
||||
self.sb.push(sb);
|
||||
self.sc.push(sc);
|
||||
self.sd.push(sd);
|
||||
self.sm.push(sm);
|
||||
tmp
|
||||
}
|
||||
// fn copy(&mut self, left: Wire, right: Wire) {
|
||||
// unimplemented!()
|
||||
// }
|
||||
}
|
||||
|
||||
let mut meta = MetaCircuit::default();
|
||||
let config = ConcreteCircuit::configure(&mut meta);
|
||||
|
||||
let mut witness = WitnessCollection {
|
||||
a: vec![],
|
||||
b: vec![],
|
||||
c: vec![],
|
||||
d: vec![],
|
||||
sa: vec![],
|
||||
sb: vec![],
|
||||
sc: vec![],
|
||||
sd: vec![],
|
||||
sm: vec![],
|
||||
advice: vec![vec![C::Scalar::zero(); params.n as usize]; meta.num_advice_wires],
|
||||
};
|
||||
|
||||
|
|
@ -115,34 +67,8 @@ impl<C: CurveAffine> Proof<C> {
|
|||
// Create a transcript for obtaining Fiat-Shamir challenges.
|
||||
let mut transcript = HBase::init(C::Base::one());
|
||||
|
||||
if witness.a.len() > params.n as usize {
|
||||
// The polynomial commitment does not support a high enough degree
|
||||
// polynomial to commit to our wires because this circuit has too
|
||||
// many gates.
|
||||
return Err(Error::IncompatibleParams);
|
||||
}
|
||||
|
||||
witness.a.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.b.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.c.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.d.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.sa.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.sb.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.sc.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.sd.resize(params.n as usize, C::Scalar::zero());
|
||||
witness.sm.resize(params.n as usize, C::Scalar::zero());
|
||||
|
||||
// Compute commitments to the various wire values
|
||||
let a_blind = C::Scalar::one(); // TODO: not random
|
||||
let b_blind = C::Scalar::one(); // TODO: not random
|
||||
let c_blind = C::Scalar::one(); // TODO: not random
|
||||
let d_blind = C::Scalar::one(); // TODO: not random
|
||||
let a_commitment = params.commit_lagrange(&witness.a, a_blind).to_affine();
|
||||
let b_commitment = params.commit_lagrange(&witness.b, b_blind).to_affine();
|
||||
let c_commitment = params.commit_lagrange(&witness.c, c_blind).to_affine();
|
||||
let d_commitment = params.commit_lagrange(&witness.d, d_blind).to_affine();
|
||||
|
||||
let advice_blinds = vec![C::Scalar::one(); witness.advice.len()]; // TODO: not random
|
||||
// Compute commitments to advice wire polynomials
|
||||
let advice_blinds: Vec<_> = witness.advice.iter().map(|_| C::Scalar::random()).collect();
|
||||
let advice_commitments = witness
|
||||
.advice
|
||||
.iter()
|
||||
|
|
@ -150,50 +76,77 @@ impl<C: CurveAffine> Proof<C> {
|
|||
.map(|(poly, blind)| params.commit_lagrange(poly, *blind).to_affine())
|
||||
.collect();
|
||||
|
||||
hash_point(&mut transcript, &a_commitment)?;
|
||||
hash_point(&mut transcript, &b_commitment)?;
|
||||
hash_point(&mut transcript, &c_commitment)?;
|
||||
hash_point(&mut transcript, &d_commitment)?;
|
||||
for commitment in &advice_commitments {
|
||||
hash_point(&mut transcript, commitment)?;
|
||||
}
|
||||
|
||||
let domain = &srs.domain;
|
||||
|
||||
let a_poly = domain.obtain_poly(witness.a);
|
||||
let b_poly = domain.obtain_poly(witness.b);
|
||||
let c_poly = domain.obtain_poly(witness.c);
|
||||
let d_poly = domain.obtain_poly(witness.d);
|
||||
|
||||
let a_coset = domain.obtain_coset(a_poly.clone(), 0);
|
||||
let b_coset = domain.obtain_coset(b_poly.clone(), 0);
|
||||
let c_coset = domain.obtain_coset(c_poly.clone(), 0);
|
||||
let d_coset = domain.obtain_coset(d_poly.clone(), 0);
|
||||
|
||||
let advice_polys: Vec<_> = witness
|
||||
.advice
|
||||
.into_iter()
|
||||
.map(|poly| {
|
||||
let poly = domain.obtain_poly(poly);
|
||||
let coset = domain.obtain_coset(poly.clone(), 0);
|
||||
(poly, coset)
|
||||
.map(|poly| domain.obtain_poly(poly))
|
||||
.collect();
|
||||
|
||||
let advice_cosets: Vec<_> = meta
|
||||
.advice_queries
|
||||
.iter()
|
||||
.map(|&(wire, at)| {
|
||||
let poly = advice_polys[wire.0].clone();
|
||||
domain.obtain_coset(poly, at)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// (a * sa) + (b * sb) + (a * sm * b) + (d * sd) - (c * sc)
|
||||
let mut h_poly = Vec::with_capacity(a_coset.len());
|
||||
for ((((((((a, b), c), d), sa), sb), sc), sd), sm) in a_coset
|
||||
.iter()
|
||||
.zip(b_coset.iter())
|
||||
.zip(c_coset.iter())
|
||||
.zip(d_coset.iter())
|
||||
.zip(srs.sa.0.iter())
|
||||
.zip(srs.sb.0.iter())
|
||||
.zip(srs.sc.0.iter())
|
||||
.zip(srs.sd.0.iter())
|
||||
.zip(srs.sm.0.iter())
|
||||
{
|
||||
h_poly.push((*a) * sa + &((*b) * sb) + &((*a) * sm * b) + &((*d) * sd) - &((*c) * sc));
|
||||
// Obtain challenge for keeping all separate gates linearly independent
|
||||
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
// Evaluate the circuit using the custom gates provided
|
||||
let mut h_poly = vec![C::Scalar::zero(); domain.coset_len()];
|
||||
for (i, poly) in meta.gates.iter().enumerate() {
|
||||
if i != 0 {
|
||||
for h in h_poly.iter_mut() {
|
||||
*h *= &x_2;
|
||||
}
|
||||
}
|
||||
|
||||
let evaluation: Vec<C::Scalar> = poly.evaluate(
|
||||
&|index| srs.fixed_cosets[index].clone(),
|
||||
&|index| advice_cosets[index].clone(),
|
||||
&|mut a, b| {
|
||||
parallelize(&mut a, |a, start| {
|
||||
for (a, b) in a.into_iter().zip(b[start..].iter()) {
|
||||
*a += b;
|
||||
}
|
||||
});
|
||||
a
|
||||
},
|
||||
&|mut a, b| {
|
||||
parallelize(&mut a, |a, start| {
|
||||
for (a, b) in a.into_iter().zip(b[start..].iter()) {
|
||||
*a *= b;
|
||||
}
|
||||
});
|
||||
a
|
||||
},
|
||||
&|mut a, scalar| {
|
||||
parallelize(&mut a, |a, _| {
|
||||
for a in a {
|
||||
*a *= &scalar;
|
||||
}
|
||||
});
|
||||
a
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(h_poly.len(), evaluation.len());
|
||||
|
||||
if i == 0 {
|
||||
h_poly = evaluation;
|
||||
} else {
|
||||
for (h, e) in h_poly.iter_mut().zip(evaluation.into_iter()) {
|
||||
*h += &e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divide by t(X) = X^{params.n} - 1.
|
||||
|
|
@ -208,7 +161,7 @@ impl<C: CurveAffine> Proof<C> {
|
|||
.map(|v| v.to_vec())
|
||||
.collect::<Vec<_>>();
|
||||
drop(h_poly);
|
||||
let h_blinds = vec![C::Scalar::one(); h_pieces.len()]; // TODO: not random
|
||||
let h_blinds: Vec<_> = h_pieces.iter().map(|_| C::Scalar::random()).collect();
|
||||
|
||||
// Compute commitments to each h(X) piece
|
||||
let h_commitments: Vec<_> = h_pieces
|
||||
|
|
@ -222,38 +175,59 @@ impl<C: CurveAffine> Proof<C> {
|
|||
hash_point(&mut transcript, c)?;
|
||||
}
|
||||
|
||||
let x: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
// Evaluate polynomials at x
|
||||
let a_eval_x = eval_polynomial(&a_poly, x);
|
||||
let b_eval_x = eval_polynomial(&b_poly, x);
|
||||
let c_eval_x = eval_polynomial(&c_poly, x);
|
||||
let d_eval_x = eval_polynomial(&d_poly, x);
|
||||
let sa_eval_x = eval_polynomial(&srs.sa.1, x);
|
||||
let sb_eval_x = eval_polynomial(&srs.sb.1, x);
|
||||
let sc_eval_x = eval_polynomial(&srs.sc.1, x);
|
||||
let sd_eval_x = eval_polynomial(&srs.sd.1, x);
|
||||
let sm_eval_x = eval_polynomial(&srs.sm.1, x);
|
||||
// Evaluate polynomials at omega^i x_3
|
||||
let advice_evals_x: Vec<_> = meta
|
||||
.advice_queries
|
||||
.iter()
|
||||
.map(|&(wire, at)| {
|
||||
let mut point = x_3;
|
||||
if at >= 0 {
|
||||
point *= &domain.get_omega().pow(&[at as u64, 0, 0, 0]);
|
||||
} else {
|
||||
point *= &domain.get_omega_inv().pow(&[at.abs() as u64, 0, 0, 0]);
|
||||
}
|
||||
|
||||
eval_polynomial(&advice_polys[wire.0], point)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let fixed_evals_x: Vec<_> = meta
|
||||
.fixed_queries
|
||||
.iter()
|
||||
.map(|&(wire, at)| {
|
||||
let mut point = x_3;
|
||||
if at >= 0 {
|
||||
point *= &domain.get_omega().pow(&[at as u64, 0, 0, 0]);
|
||||
} else {
|
||||
point *= &domain.get_omega_inv().pow(&[at.abs() as u64, 0, 0, 0]);
|
||||
}
|
||||
|
||||
eval_polynomial(&srs.fixed_polys[wire.0], point)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let h_evals_x: Vec<_> = h_pieces
|
||||
.iter()
|
||||
.map(|poly| eval_polynomial(poly, x))
|
||||
.map(|poly| eval_polynomial(poly, x_3))
|
||||
.collect();
|
||||
|
||||
// We set up a second transcript on the scalar field to hash in openings of
|
||||
// our polynomial commitments.
|
||||
let mut transcript_scalar = HScalar::init(C::Scalar::one());
|
||||
transcript_scalar.absorb(a_eval_x);
|
||||
transcript_scalar.absorb(b_eval_x);
|
||||
transcript_scalar.absorb(c_eval_x);
|
||||
transcript_scalar.absorb(d_eval_x);
|
||||
transcript_scalar.absorb(sa_eval_x);
|
||||
transcript_scalar.absorb(sb_eval_x);
|
||||
transcript_scalar.absorb(sc_eval_x);
|
||||
transcript_scalar.absorb(sd_eval_x);
|
||||
transcript_scalar.absorb(sm_eval_x);
|
||||
|
||||
// Hash each h(x) piece
|
||||
// Hash each advice evaluation
|
||||
for eval in advice_evals_x.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
// Hash each fixed evaluation
|
||||
for eval in fixed_evals_x.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
// Hash each h(x) piece evaluation
|
||||
for eval in h_evals_x.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
|
@ -262,62 +236,164 @@ impl<C: CurveAffine> Proof<C> {
|
|||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||
transcript.absorb(transcript_scalar_point);
|
||||
|
||||
let y: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
let mut q_commitment = h_commitments[0].clone().to_projective();
|
||||
let mut q_poly = h_pieces[0].clone();
|
||||
let mut q_blind = h_blinds[0];
|
||||
// Collapse openings at same points together into single openings using
|
||||
// x_4 challenge.
|
||||
let mut q_polys: Vec<Option<Vec<_>>> = vec![None; meta.query_rows.len()];
|
||||
let mut q_blinds = vec![C::Scalar::zero(); meta.query_rows.len()];
|
||||
let mut q_evals: Vec<_> = vec![C::Scalar::zero(); meta.query_rows.len()];
|
||||
{
|
||||
let mut accumulate = |poly: &[_], blind: &C::Scalar, commitment: C| {
|
||||
for (a, q) in poly.iter().zip(q_poly.iter_mut()) {
|
||||
*q = (*q * &y) + a;
|
||||
}
|
||||
q_commitment = (q_commitment * y) + &commitment.to_projective();
|
||||
q_blind = (q_blind * &y) + blind;
|
||||
};
|
||||
for (i, &(wire, ref at)) in meta.advice_queries.iter().enumerate() {
|
||||
let query_row = *meta.query_rows.get(at).unwrap();
|
||||
|
||||
for ((poly, blind), commitment) in h_pieces
|
||||
.iter()
|
||||
.zip(h_blinds.iter())
|
||||
.zip(h_commitments.iter())
|
||||
.skip(1)
|
||||
{
|
||||
accumulate(&poly, blind, *commitment);
|
||||
if q_polys[query_row].is_none() {
|
||||
q_polys[query_row] = Some(advice_polys[wire.0].clone());
|
||||
q_blinds[query_row] = advice_blinds[wire.0];
|
||||
q_evals[query_row] = advice_evals_x[i];
|
||||
} else {
|
||||
parallelize(q_polys[query_row].as_mut().unwrap(), |q, start| {
|
||||
for (q, a) in q.iter_mut().zip(advice_polys[wire.0][start..].iter()) {
|
||||
*q *= &x_4;
|
||||
*q += a;
|
||||
}
|
||||
});
|
||||
q_blinds[query_row] *= &x_4;
|
||||
q_blinds[query_row] += &advice_blinds[wire.0];
|
||||
q_evals[query_row] *= &x_4;
|
||||
q_evals[query_row] += &advice_evals_x[i];
|
||||
}
|
||||
}
|
||||
|
||||
accumulate(&a_poly, &a_blind, a_commitment);
|
||||
accumulate(&b_poly, &b_blind, b_commitment);
|
||||
accumulate(&c_poly, &c_blind, c_commitment);
|
||||
accumulate(&d_poly, &d_blind, d_commitment);
|
||||
accumulate(&srs.sa.1, &Field::one(), srs.sa_commitment);
|
||||
accumulate(&srs.sb.1, &Field::one(), srs.sb_commitment);
|
||||
accumulate(&srs.sc.1, &Field::one(), srs.sc_commitment);
|
||||
accumulate(&srs.sd.1, &Field::one(), srs.sd_commitment);
|
||||
accumulate(&srs.sm.1, &Field::one(), srs.sm_commitment);
|
||||
for (i, &(wire, ref at)) in meta.fixed_queries.iter().enumerate() {
|
||||
let query_row = *meta.query_rows.get(at).unwrap();
|
||||
|
||||
if q_polys[query_row].is_none() {
|
||||
q_polys[query_row] = Some(srs.fixed_polys[wire.0].clone());
|
||||
q_blinds[query_row] = C::Scalar::one();
|
||||
q_evals[query_row] = fixed_evals_x[i];
|
||||
} else {
|
||||
parallelize(q_polys[query_row].as_mut().unwrap(), |q, start| {
|
||||
for (q, a) in q.iter_mut().zip(srs.fixed_polys[wire.0][start..].iter()) {
|
||||
*q *= &x_4;
|
||||
*q += a;
|
||||
}
|
||||
});
|
||||
q_blinds[query_row] *= &x_4;
|
||||
q_blinds[query_row] += &C::Scalar::one();
|
||||
q_evals[query_row] *= &x_4;
|
||||
q_evals[query_row] += &fixed_evals_x[i];
|
||||
}
|
||||
}
|
||||
|
||||
for ((h_poly, h_blind), h_eval) in h_pieces
|
||||
.into_iter()
|
||||
.zip(h_blinds.iter())
|
||||
.zip(h_evals_x.iter())
|
||||
{
|
||||
// We query the h(X) polynomial at x_3
|
||||
let cur_row = *meta.query_rows.get(&0).unwrap();
|
||||
|
||||
if q_polys[cur_row].is_none() {
|
||||
q_polys[cur_row] = Some(h_poly);
|
||||
q_blinds[cur_row] = *h_blind;
|
||||
q_evals[cur_row] = *h_eval;
|
||||
} else {
|
||||
parallelize(q_polys[cur_row].as_mut().unwrap(), |q, start| {
|
||||
for (q, a) in q.iter_mut().zip(h_poly[start..].iter()) {
|
||||
*q *= &x_4;
|
||||
*q += a;
|
||||
}
|
||||
});
|
||||
q_blinds[cur_row] *= &x_4;
|
||||
q_blinds[cur_row] += h_blind;
|
||||
q_evals[cur_row] *= &x_4;
|
||||
q_evals[cur_row] += h_eval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
let mut f_poly = None;
|
||||
for (&row, &col) in meta.query_rows.iter() {
|
||||
let mut poly = q_polys[col].as_ref().unwrap().clone();
|
||||
let mut point = x_3;
|
||||
if row >= 0 {
|
||||
point *= &domain.get_omega().pow_vartime(&[row as u64, 0, 0, 0]);
|
||||
} else {
|
||||
point *= &domain
|
||||
.get_omega_inv()
|
||||
.pow_vartime(&[row.abs() as u64, 0, 0, 0]);
|
||||
}
|
||||
poly[0] -= &q_evals[col];
|
||||
let mut poly = kate_division(&poly, point);
|
||||
poly.push(C::Scalar::zero());
|
||||
|
||||
if f_poly.is_none() {
|
||||
f_poly = Some(poly);
|
||||
} else {
|
||||
parallelize(f_poly.as_mut().unwrap(), |q, start| {
|
||||
for (q, a) in q.iter_mut().zip(poly[start..].iter()) {
|
||||
*q *= &x_5;
|
||||
*q += a;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
let mut f_poly = f_poly.unwrap();
|
||||
let mut f_blind = C::Scalar::random();
|
||||
|
||||
let f_commitment = params.commit(&f_poly, f_blind).to_affine();
|
||||
|
||||
hash_point(&mut transcript, &f_commitment)?;
|
||||
|
||||
let x_6: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
let mut q_evals = vec![];
|
||||
|
||||
for (_, &col) in meta.query_rows.iter() {
|
||||
q_evals.push(eval_polynomial(&q_polys[col].as_ref().unwrap(), x_6));
|
||||
}
|
||||
|
||||
for eval in q_evals.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
let transcript_scalar_point =
|
||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||
transcript.absorb(transcript_scalar_point);
|
||||
|
||||
let x_7: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
for (_, &col) in meta.query_rows.iter() {
|
||||
f_blind *= &x_7;
|
||||
f_blind += &q_blinds[col];
|
||||
|
||||
parallelize(&mut f_poly, |f, start| {
|
||||
for (f, a) in f
|
||||
.iter_mut()
|
||||
.zip(q_polys[col].as_ref().unwrap()[start..].iter())
|
||||
{
|
||||
*f *= &x_7;
|
||||
*f += a;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Let's prove that the q_commitment opens at x to the expected value.
|
||||
let opening = params
|
||||
.create_proof(&mut transcript, &q_poly, q_blind, x)
|
||||
.create_proof(&mut transcript, &f_poly, f_blind, x_6)
|
||||
.map_err(|_| Error::ConstraintSystemFailure)?;
|
||||
|
||||
Ok(Proof {
|
||||
a_commitment,
|
||||
b_commitment,
|
||||
c_commitment,
|
||||
d_commitment,
|
||||
advice_commitments,
|
||||
h_commitments,
|
||||
a_eval_x,
|
||||
b_eval_x,
|
||||
c_eval_x,
|
||||
d_eval_x,
|
||||
sa_eval_x,
|
||||
sb_eval_x,
|
||||
sc_eval_x,
|
||||
sd_eval_x,
|
||||
sm_eval_x,
|
||||
advice_evals_x,
|
||||
fixed_evals_x,
|
||||
h_evals_x,
|
||||
f_commitment,
|
||||
q_evals,
|
||||
opening,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
103
src/plonk/srs.rs
103
src/plonk/srs.rs
|
|
@ -1,7 +1,7 @@
|
|||
use super::{
|
||||
circuit::{AdviceWire, Circuit, ConstraintSystem, FixedWire, MetaCircuit, Variable, Wire},
|
||||
circuit::{AdviceWire, Circuit, ConstraintSystem, FixedWire, MetaCircuit},
|
||||
domain::EvaluationDomain,
|
||||
Error, GATE_DEGREE, SRS,
|
||||
Error, SRS,
|
||||
};
|
||||
use crate::arithmetic::{Curve, CurveAffine, Field};
|
||||
use crate::polycommit::Params;
|
||||
|
|
@ -14,11 +14,6 @@ impl<C: CurveAffine> SRS<C> {
|
|||
circuit: &ConcreteCircuit,
|
||||
) -> Result<Self, Error> {
|
||||
struct Assembly<F: Field> {
|
||||
sa: Vec<F>,
|
||||
sb: Vec<F>,
|
||||
sc: Vec<F>,
|
||||
sd: Vec<F>,
|
||||
sm: Vec<F>,
|
||||
fixed: Vec<Vec<F>>,
|
||||
}
|
||||
|
||||
|
|
@ -47,113 +42,51 @@ impl<C: CurveAffine> SRS<C> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_gate(
|
||||
&mut self,
|
||||
sa: F,
|
||||
sb: F,
|
||||
sc: F,
|
||||
sd: F,
|
||||
sm: F,
|
||||
_: impl Fn() -> Result<(F, F, F, F), Error>,
|
||||
) -> Result<(Variable, Variable, Variable, Variable), Error> {
|
||||
let tmp = Ok((
|
||||
Variable(Wire::A, self.sa.len()),
|
||||
Variable(Wire::B, self.sa.len()),
|
||||
Variable(Wire::C, self.sa.len()),
|
||||
Variable(Wire::D, self.sa.len()),
|
||||
));
|
||||
self.sa.push(sa);
|
||||
self.sb.push(sb);
|
||||
self.sc.push(sc);
|
||||
self.sd.push(sd);
|
||||
self.sm.push(sm);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
|
||||
let mut meta = MetaCircuit::default();
|
||||
let config = ConcreteCircuit::configure(&mut meta);
|
||||
|
||||
let mut assembly: Assembly<C::Scalar> = Assembly {
|
||||
sa: vec![],
|
||||
sb: vec![],
|
||||
sc: vec![],
|
||||
sd: vec![],
|
||||
sm: vec![],
|
||||
fixed: vec![vec![C::Scalar::zero(); params.n as usize]; meta.num_fixed_wires],
|
||||
};
|
||||
|
||||
// Synthesize the circuit to obtain SRS
|
||||
circuit.synthesize(&mut assembly, config)?;
|
||||
|
||||
assembly.sa.resize(params.n as usize, C::Scalar::zero());
|
||||
assembly.sb.resize(params.n as usize, C::Scalar::zero());
|
||||
assembly.sc.resize(params.n as usize, C::Scalar::zero());
|
||||
assembly.sd.resize(params.n as usize, C::Scalar::zero());
|
||||
assembly.sm.resize(params.n as usize, C::Scalar::zero());
|
||||
|
||||
// Compute commitments to the fixed wire values
|
||||
let sa_commitment = params
|
||||
.commit_lagrange(&assembly.sa, C::Scalar::one())
|
||||
.to_affine();
|
||||
let sb_commitment = params
|
||||
.commit_lagrange(&assembly.sb, C::Scalar::one())
|
||||
.to_affine();
|
||||
let sc_commitment = params
|
||||
.commit_lagrange(&assembly.sc, C::Scalar::one())
|
||||
.to_affine();
|
||||
let sd_commitment = params
|
||||
.commit_lagrange(&assembly.sd, C::Scalar::one())
|
||||
.to_affine();
|
||||
let sm_commitment = params
|
||||
.commit_lagrange(&assembly.sm, C::Scalar::one())
|
||||
.to_affine();
|
||||
|
||||
let fixed_commitments = assembly
|
||||
.fixed
|
||||
.iter()
|
||||
.map(|poly| params.commit_lagrange(poly, C::Scalar::one()).to_affine())
|
||||
.collect();
|
||||
|
||||
let domain = EvaluationDomain::new(GATE_DEGREE, params.k);
|
||||
let mut degree = 1;
|
||||
for poly in meta.gates.iter() {
|
||||
degree = std::cmp::max(degree, poly.degree());
|
||||
}
|
||||
|
||||
let sa_poly = domain.obtain_poly(assembly.sa);
|
||||
let sb_poly = domain.obtain_poly(assembly.sb);
|
||||
let sc_poly = domain.obtain_poly(assembly.sc);
|
||||
let sd_poly = domain.obtain_poly(assembly.sd);
|
||||
let sm_poly = domain.obtain_poly(assembly.sm);
|
||||
let sa_coset = domain.obtain_coset(sa_poly.clone(), 0);
|
||||
let sb_coset = domain.obtain_coset(sb_poly.clone(), 0);
|
||||
let sc_coset = domain.obtain_coset(sc_poly.clone(), 0);
|
||||
let sd_coset = domain.obtain_coset(sd_poly.clone(), 0);
|
||||
let sm_coset = domain.obtain_coset(sm_poly.clone(), 0);
|
||||
let domain = EvaluationDomain::new(degree as u32, params.k);
|
||||
|
||||
let fixed_polys = assembly
|
||||
let fixed_polys: Vec<_> = assembly
|
||||
.fixed
|
||||
.into_iter()
|
||||
.map(|poly| {
|
||||
let coeffs = domain.obtain_poly(poly);
|
||||
let coset = domain.obtain_coset(coeffs.clone(), 0);
|
||||
(coeffs, coset)
|
||||
.map(|poly| domain.obtain_poly(poly))
|
||||
.collect();
|
||||
|
||||
let fixed_cosets = meta
|
||||
.fixed_queries
|
||||
.iter()
|
||||
.map(|&(wire, at)| {
|
||||
let poly = fixed_polys[wire.0].clone();
|
||||
domain.obtain_coset(poly, at)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(SRS {
|
||||
sa: (sa_coset, sa_poly),
|
||||
sb: (sb_coset, sb_poly),
|
||||
sc: (sc_coset, sc_poly),
|
||||
sd: (sd_coset, sd_poly),
|
||||
sm: (sm_coset, sm_poly),
|
||||
sa_commitment,
|
||||
sb_commitment,
|
||||
sc_commitment,
|
||||
sd_commitment,
|
||||
sm_commitment,
|
||||
domain,
|
||||
|
||||
fixed_commitments,
|
||||
fixed_polys,
|
||||
fixed_cosets,
|
||||
meta,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,48 +13,178 @@ impl<C: CurveAffine> Proof<C> {
|
|||
// Create a transcript for obtaining Fiat-Shamir challenges.
|
||||
let mut transcript = HBase::init(C::Base::one());
|
||||
|
||||
hash_point(&mut transcript, &self.a_commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
hash_point(&mut transcript, &self.b_commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
hash_point(&mut transcript, &self.c_commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
hash_point(&mut transcript, &self.d_commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
|
||||
for commitment in &self.advice_commitments {
|
||||
hash_point(&mut transcript, commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
}
|
||||
|
||||
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
for c in &self.h_commitments {
|
||||
hash_point(&mut transcript, c).expect("proof cannot contain points at infinity");
|
||||
}
|
||||
|
||||
let x: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
// We set up a second transcript on the scalar field to hash in openings of
|
||||
// our polynomial commitments.
|
||||
let mut transcript_scalar = HScalar::init(C::Scalar::one());
|
||||
transcript_scalar.absorb(self.a_eval_x);
|
||||
transcript_scalar.absorb(self.b_eval_x);
|
||||
transcript_scalar.absorb(self.c_eval_x);
|
||||
transcript_scalar.absorb(self.d_eval_x);
|
||||
transcript_scalar.absorb(self.sa_eval_x);
|
||||
transcript_scalar.absorb(self.sb_eval_x);
|
||||
transcript_scalar.absorb(self.sc_eval_x);
|
||||
transcript_scalar.absorb(self.sd_eval_x);
|
||||
transcript_scalar.absorb(self.sm_eval_x);
|
||||
|
||||
for eval in self.advice_evals_x.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
for eval in self.fixed_evals_x.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
for eval in &self.h_evals_x {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
// Evaluate the circuit using the custom gates provided
|
||||
let mut h_eval = C::Scalar::zero();
|
||||
for poly in srs.meta.gates.iter() {
|
||||
h_eval *= &x_2;
|
||||
|
||||
let evaluation: C::Scalar = poly.evaluate(
|
||||
&|index| self.fixed_evals_x[index],
|
||||
&|index| self.advice_evals_x[index],
|
||||
&|a, b| a + &b,
|
||||
&|a, b| a * &b,
|
||||
&|a, scalar| a * &scalar,
|
||||
);
|
||||
|
||||
h_eval += &evaluation;
|
||||
}
|
||||
let xn = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
||||
h_eval *= &(xn - &C::Scalar::one());
|
||||
|
||||
// Compute the expected h(x) value
|
||||
let mut expected_h_eval = C::Scalar::zero();
|
||||
let mut cur = C::Scalar::one();
|
||||
for eval in &self.h_evals_x {
|
||||
expected_h_eval += &(cur * eval);
|
||||
cur *= &xn;
|
||||
}
|
||||
|
||||
if h_eval != expected_h_eval {
|
||||
return false;
|
||||
}
|
||||
|
||||
let transcript_scalar_point =
|
||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||
transcript.absorb(transcript_scalar_point);
|
||||
|
||||
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
let mut q_commitments: Vec<_> = vec![None; srs.meta.query_rows.len()];
|
||||
let mut q_evals: Vec<_> = vec![C::Scalar::zero(); srs.meta.query_rows.len()];
|
||||
|
||||
{
|
||||
for (i, &(wire, ref at)) in srs.meta.advice_queries.iter().enumerate() {
|
||||
let query_row = *srs.meta.query_rows.get(at).unwrap();
|
||||
|
||||
if q_commitments[query_row].is_none() {
|
||||
q_commitments[query_row] =
|
||||
Some(self.advice_commitments[wire.0].to_projective());
|
||||
q_evals[query_row] = self.advice_evals_x[i];
|
||||
} else {
|
||||
q_commitments[query_row].as_mut().map(|commitment| {
|
||||
*commitment *= x_4;
|
||||
*commitment += self.advice_commitments[wire.0];
|
||||
});
|
||||
q_evals[query_row] *= &x_4;
|
||||
q_evals[query_row] += &self.advice_evals_x[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i, &(wire, ref at)) in srs.meta.fixed_queries.iter().enumerate() {
|
||||
let query_row = *srs.meta.query_rows.get(at).unwrap();
|
||||
|
||||
if q_commitments[query_row].is_none() {
|
||||
q_commitments[query_row] = Some(srs.fixed_commitments[wire.0].to_projective());
|
||||
q_evals[query_row] = self.fixed_evals_x[i];
|
||||
} else {
|
||||
q_commitments[query_row].as_mut().map(|commitment| {
|
||||
*commitment *= x_4;
|
||||
*commitment += srs.fixed_commitments[wire.0];
|
||||
});
|
||||
q_evals[query_row] *= &x_4;
|
||||
q_evals[query_row] += &self.fixed_evals_x[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (h_commitment, h_eval) in self.h_commitments.iter().zip(self.h_evals_x.iter()) {
|
||||
// We query the h(X) polynomial at x_3
|
||||
let cur_row = *srs.meta.query_rows.get(&0).unwrap();
|
||||
|
||||
if q_commitments[cur_row].is_none() {
|
||||
q_commitments[cur_row] = Some(h_commitment.to_projective());
|
||||
q_evals[cur_row] = *h_eval;
|
||||
} else {
|
||||
q_commitments[cur_row].as_mut().map(|commitment| {
|
||||
*commitment *= x_4;
|
||||
*commitment += *h_commitment;
|
||||
});
|
||||
q_evals[cur_row] *= &x_4;
|
||||
q_evals[cur_row] += h_eval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
hash_point(&mut transcript, &self.f_commitment)
|
||||
.expect("proof cannot contain points at infinity");
|
||||
|
||||
let x_6: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
// We can compute the expected f_eval from x_5
|
||||
let mut f_eval = C::Scalar::zero();
|
||||
for (&row, &col) in srs.meta.query_rows.iter() {
|
||||
let mut eval: C::Scalar = self.q_evals[col].clone();
|
||||
let mut point = x_3;
|
||||
if row >= 0 {
|
||||
point *= &srs.domain.get_omega().pow_vartime(&[row as u64, 0, 0, 0]);
|
||||
} else {
|
||||
point *= &srs
|
||||
.domain
|
||||
.get_omega_inv()
|
||||
.pow_vartime(&[row.abs() as u64, 0, 0, 0]);
|
||||
}
|
||||
eval = eval - &q_evals[col];
|
||||
eval = eval * &(x_6 - &point).invert().unwrap();
|
||||
|
||||
f_eval *= &x_5;
|
||||
f_eval += &eval;
|
||||
}
|
||||
|
||||
for eval in self.q_evals.iter() {
|
||||
transcript_scalar.absorb(*eval);
|
||||
}
|
||||
|
||||
let transcript_scalar_point =
|
||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||
transcript.absorb(transcript_scalar_point);
|
||||
|
||||
let y: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
let x_7: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||
|
||||
let mut f_commitment: C::Projective = self.f_commitment.to_projective();
|
||||
for (_, &col) in srs.meta.query_rows.iter() {
|
||||
f_commitment *= x_7;
|
||||
f_commitment = f_commitment + &q_commitments[col].as_ref().unwrap();
|
||||
f_eval *= &x_7;
|
||||
f_eval += &self.q_evals[col];
|
||||
}
|
||||
|
||||
params.verify_proof(
|
||||
&self.opening,
|
||||
&mut transcript,
|
||||
x_6,
|
||||
&f_commitment.to_affine(),
|
||||
f_eval,
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
let mut q_commitment = self.h_commitments[0].clone().to_projective();
|
||||
let mut expected_opening = self.h_evals_x[0];
|
||||
|
|
@ -102,12 +232,6 @@ impl<C: CurveAffine> Proof<C> {
|
|||
return false;
|
||||
}
|
||||
|
||||
params.verify_proof(
|
||||
&self.opening,
|
||||
&mut transcript,
|
||||
x,
|
||||
&q_commitment,
|
||||
expected_opening,
|
||||
)
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue