mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-06 20:20:34 +00:00
commit
a8e0a5565e
5 changed files with 305 additions and 217 deletions
|
|
@ -170,13 +170,8 @@ pub struct ConstraintSystem<F> {
|
||||||
pub(crate) rotations: BTreeMap<Rotation, PointIndex>,
|
pub(crate) rotations: BTreeMap<Rotation, PointIndex>,
|
||||||
|
|
||||||
// Vector of permutation arguments, where each corresponds to a set of wires
|
// Vector of permutation arguments, where each corresponds to a set of wires
|
||||||
// that are involved in a permutation argument, as well as the corresponding
|
// that are involved in a permutation argument.
|
||||||
// query index for each wire. As an example, we could have a permutation
|
pub(crate) permutations: Vec<Vec<AdviceWire>>,
|
||||||
// argument between wires (A, B, C) which allows copy constraints to be
|
|
||||||
// enforced between advice wire values in A, B and C, and another
|
|
||||||
// permutation between wires (B, C, D) which allows the same with D instead
|
|
||||||
// of A.
|
|
||||||
pub(crate) permutations: Vec<Vec<(AdviceWire, usize)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Default for ConstraintSystem<F> {
|
impl<F: Field> Default for ConstraintSystem<F> {
|
||||||
|
|
@ -202,16 +197,16 @@ impl<F: Field> ConstraintSystem<F> {
|
||||||
/// Add a permutation argument for some advice wires
|
/// Add a permutation argument for some advice wires
|
||||||
pub fn permutation(&mut self, wires: &[AdviceWire]) -> usize {
|
pub fn permutation(&mut self, wires: &[AdviceWire]) -> usize {
|
||||||
let index = self.permutations.len();
|
let index = self.permutations.len();
|
||||||
if index == 0 {
|
if self.permutations.is_empty() {
|
||||||
let at = Rotation(-1);
|
let at = Rotation(-1);
|
||||||
let len = self.rotations.len();
|
let len = self.rotations.len();
|
||||||
self.rotations.entry(at).or_insert(PointIndex(len));
|
self.rotations.entry(at).or_insert(PointIndex(len));
|
||||||
}
|
}
|
||||||
let wires = wires
|
|
||||||
.iter()
|
for wire in wires {
|
||||||
.map(|&wire| (wire, self.query_advice_index(wire, 0)))
|
self.query_advice_index(*wire, 0);
|
||||||
.collect();
|
}
|
||||||
self.permutations.push(wires);
|
self.permutations.push(wires.to_vec());
|
||||||
|
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +237,18 @@ impl<F: Field> ConstraintSystem<F> {
|
||||||
Expression::Fixed(self.query_fixed_index(wire, at))
|
Expression::Fixed(self.query_fixed_index(wire, at))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_advice_index(&mut self, wire: AdviceWire, at: i32) -> usize {
|
pub(crate) fn get_advice_query_index(&self, wire: AdviceWire, at: i32) -> usize {
|
||||||
|
let at = Rotation(at);
|
||||||
|
for (index, advice_query) in self.advice_queries.iter().enumerate() {
|
||||||
|
if advice_query == &(wire, at) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("get_advice_query_index called for non-existant query");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn query_advice_index(&mut self, wire: AdviceWire, at: i32) -> usize {
|
||||||
let at = Rotation(at);
|
let at = Rotation(at);
|
||||||
{
|
{
|
||||||
let len = self.rotations.len();
|
let len = self.rotations.len();
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let mut modified_advice = vec![C::Scalar::one(); params.n as usize];
|
let mut modified_advice = vec![C::Scalar::one(); params.n as usize];
|
||||||
|
|
||||||
// Iterate over each wire of the permutation
|
// Iterate over each wire of the permutation
|
||||||
for (&(wire, _), permuted_wire_values) in wires.iter().zip(permuted_values.iter()) {
|
for (&wire, permuted_wire_values) in wires.iter().zip(permuted_values.iter()) {
|
||||||
parallelize(&mut modified_advice, |modified_advice, start| {
|
parallelize(&mut modified_advice, |modified_advice, start| {
|
||||||
for ((modified_advice, advice_value), permuted_advice_value) in modified_advice
|
for ((modified_advice, advice_value), permuted_advice_value) in modified_advice
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
|
@ -219,7 +219,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// Iterate over each wire again, this time finishing the computation
|
// Iterate over each wire again, this time finishing the computation
|
||||||
// of the entire fraction by computing the numerators
|
// of the entire fraction by computing the numerators
|
||||||
let mut deltaomega = C::Scalar::one();
|
let mut deltaomega = C::Scalar::one();
|
||||||
for &(wire, _) in wires.iter() {
|
for &wire in wires.iter() {
|
||||||
let omega = domain.get_omega();
|
let omega = domain.get_omega();
|
||||||
parallelize(&mut modified_advice, |modified_advice, start| {
|
parallelize(&mut modified_advice, |modified_advice, start| {
|
||||||
let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]);
|
let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]);
|
||||||
|
|
@ -320,7 +320,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let mut left = permutation_product_cosets[permutation_index].clone();
|
let mut left = permutation_product_cosets[permutation_index].clone();
|
||||||
for (advice, permutation) in wires
|
for (advice, permutation) in wires
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(_, index)| &advice_cosets[index])
|
.map(|&wire| &advice_cosets[pk.vk.cs.get_advice_query_index(wire, 0)])
|
||||||
.zip(pk.permutation_cosets[permutation_index].iter())
|
.zip(pk.permutation_cosets[permutation_index].iter())
|
||||||
{
|
{
|
||||||
parallelize(&mut left, |left, start| {
|
parallelize(&mut left, |left, start| {
|
||||||
|
|
@ -337,7 +337,10 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let mut right = permutation_product_cosets_inv[permutation_index].clone();
|
let mut right = permutation_product_cosets_inv[permutation_index].clone();
|
||||||
let mut current_delta = x_0 * &C::Scalar::ZETA;
|
let mut current_delta = x_0 * &C::Scalar::ZETA;
|
||||||
let step = domain.get_extended_omega();
|
let step = domain.get_extended_omega();
|
||||||
for advice in wires.iter().map(|&(_, index)| &advice_cosets[index]) {
|
for advice in wires
|
||||||
|
.iter()
|
||||||
|
.map(|&wire| &advice_cosets[pk.vk.cs.get_advice_query_index(wire, 0)])
|
||||||
|
{
|
||||||
parallelize(&mut right, move |right, start| {
|
parallelize(&mut right, move |right, start| {
|
||||||
let mut beta_term = current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
|
let mut beta_term = current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
|
||||||
for (right, advice) in right.iter_mut().zip(advice[start..].iter()) {
|
for (right, advice) in right.iter_mut().zip(advice[start..].iter()) {
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,7 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
mut msm: MSM<'a, C>,
|
mut msm: MSM<'a, C>,
|
||||||
aux_commitments: &[C],
|
aux_commitments: &[C],
|
||||||
) -> Result<Guard<'a, C>, Error> {
|
) -> Result<Guard<'a, C>, Error> {
|
||||||
// Check that aux_commitments matches the expected number of aux_wires
|
self.check_lengths(vk, aux_commitments)?;
|
||||||
// and self.aux_evals
|
|
||||||
if aux_commitments.len() != vk.cs.num_aux_wires
|
|
||||||
|| self.aux_evals.len() != vk.cs.num_aux_wires
|
|
||||||
{
|
|
||||||
return Err(Error::IncompatibleParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale the MSM by a random factor to ensure that if the existing MSM
|
// Scale the MSM by a random factor to ensure that if the existing MSM
|
||||||
// has is_zero() == false then this argument won't be able to interfere
|
// has is_zero() == false then this argument won't be able to interfere
|
||||||
|
|
@ -63,7 +57,10 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
// Sample x_3 challenge, which is used to ensure the circuit is
|
// Sample x_3 challenge, which is used to ensure the circuit is
|
||||||
// satisfied with high probability.
|
// satisfied with high probability.
|
||||||
let x_3: 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()));
|
||||||
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
|
||||||
|
// This check ensures the circuit is satisfied so long as the polynomial
|
||||||
|
// commitments open to the correct values.
|
||||||
|
self.check_hx(params, vk, x_0, x_1, x_2, x_3)?;
|
||||||
|
|
||||||
// Hash together all the openings provided by the prover into a new
|
// Hash together all the openings provided by the prover into a new
|
||||||
// transcript on the scalar field.
|
// transcript on the scalar field.
|
||||||
|
|
@ -86,83 +83,6 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||||
transcript.absorb(transcript_scalar_point);
|
transcript.absorb(transcript_scalar_point);
|
||||||
|
|
||||||
// Evaluate the circuit using the custom gates provided
|
|
||||||
let mut h_eval = C::Scalar::zero();
|
|
||||||
for poly in vk.cs.gates.iter() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let evaluation: C::Scalar = poly.evaluate(
|
|
||||||
&|index| self.fixed_evals[index],
|
|
||||||
&|index| self.advice_evals[index],
|
|
||||||
&|index| self.aux_evals[index],
|
|
||||||
&|a, b| a + &b,
|
|
||||||
&|a, b| a * &b,
|
|
||||||
&|a, scalar| a * &scalar,
|
|
||||||
);
|
|
||||||
|
|
||||||
h_eval += &evaluation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First element in each permutation product should be 1
|
|
||||||
// l_0(X) * (1 - z(X)) = 0
|
|
||||||
{
|
|
||||||
// TODO: bubble this error up
|
|
||||||
let denominator = (x_3 - &C::Scalar::one()).invert().unwrap();
|
|
||||||
|
|
||||||
for eval in self.permutation_product_evals.iter() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let mut tmp = denominator; // 1 / (x_3 - 1)
|
|
||||||
tmp *= &(x_3n - &C::Scalar::one()); // (x_3^n - 1) / (x_3 - 1)
|
|
||||||
tmp *= &vk.domain.get_barycentric_weight(); // l_0(x_3)
|
|
||||||
tmp *= &(C::Scalar::one() - &eval); // l_0(X) * (1 - z(X))
|
|
||||||
|
|
||||||
h_eval += &tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
|
||||||
for (permutation_index, wires) in vk.cs.permutations.iter().enumerate() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let mut left = self.permutation_product_evals[permutation_index];
|
|
||||||
for (advice_eval, permutation_eval) in wires
|
|
||||||
.iter()
|
|
||||||
.map(|&(_, query_index)| self.advice_evals[query_index])
|
|
||||||
.zip(self.permutation_evals[permutation_index].iter())
|
|
||||||
{
|
|
||||||
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut right = self.permutation_product_inv_evals[permutation_index];
|
|
||||||
let mut current_delta = x_0 * &x_3;
|
|
||||||
for advice_eval in wires
|
|
||||||
.iter()
|
|
||||||
.map(|&(_, query_index)| self.advice_evals[query_index])
|
|
||||||
{
|
|
||||||
right *= &(advice_eval + ¤t_delta + &x_1);
|
|
||||||
current_delta *= &C::Scalar::DELTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
h_eval += &left;
|
|
||||||
h_eval -= &right;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
expected_h_eval += &(cur * eval);
|
|
||||||
cur *= &x_3n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) {
|
|
||||||
return Err(Error::ConstraintSystemFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are now convinced the circuit is satisfied so long as the
|
|
||||||
// polynomial commitments open to the correct values.
|
|
||||||
|
|
||||||
// Sample x_4 for compressing openings at the same points together
|
// Sample x_4 for compressing openings at the same points together
|
||||||
let x_4: 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()));
|
||||||
|
|
||||||
|
|
@ -293,4 +213,154 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
.verify(params, msm, &mut transcript, x_6, commitment_msm, msm_eval)
|
.verify(params, msm, &mut transcript, x_6, commitment_msm, msm_eval)
|
||||||
.map_err(|_| Error::OpeningError)
|
.map_err(|_| Error::OpeningError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks that the lengths of vectors are consistent with the constraint
|
||||||
|
/// system
|
||||||
|
fn check_lengths(&self, vk: &VerifyingKey<C>, aux_commitments: &[C]) -> Result<(), Error> {
|
||||||
|
// Check that aux_commitments matches the expected number of aux_wires
|
||||||
|
// and self.aux_evals
|
||||||
|
if aux_commitments.len() != vk.cs.num_aux_wires
|
||||||
|
|| self.aux_evals.len() != vk.cs.num_aux_wires
|
||||||
|
{
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.q_evals.len() != vk.cs.rotations.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check h_evals
|
||||||
|
|
||||||
|
if self.fixed_evals.len() != vk.cs.fixed_queries.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.advice_evals.len() != vk.cs.advice_queries.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.permutation_evals.len() != vk.cs.permutations.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (permutation_evals, permutation) in
|
||||||
|
self.permutation_evals.iter().zip(vk.cs.permutations.iter())
|
||||||
|
{
|
||||||
|
if permutation_evals.len() != permutation.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.permutation_product_inv_evals.len() != vk.cs.permutations.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.permutation_product_evals.len() != vk.cs.permutations.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.permutation_product_commitments.len() != vk.cs.permutations.len() {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check h_commitments
|
||||||
|
|
||||||
|
if self.advice_commitments.len() != vk.cs.num_advice_wires {
|
||||||
|
return Err(Error::IncompatibleParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that this proof's h_evals are correct, and thus that all of the
|
||||||
|
/// rules are satisfied.
|
||||||
|
fn check_hx(
|
||||||
|
&self,
|
||||||
|
params: &'a Params<C>,
|
||||||
|
vk: &VerifyingKey<C>,
|
||||||
|
x_0: C::Scalar,
|
||||||
|
x_1: C::Scalar,
|
||||||
|
x_2: C::Scalar,
|
||||||
|
x_3: C::Scalar,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// x_3^n
|
||||||
|
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
||||||
|
|
||||||
|
// TODO: bubble this error up
|
||||||
|
// l_0(x_3)
|
||||||
|
let l_0 = (x_3 - &C::Scalar::one()).invert().unwrap() // 1 / (x_3 - 1)
|
||||||
|
* &(x_3n - &C::Scalar::one()) // (x_3^n - 1) / (x_3 - 1)
|
||||||
|
* &vk.domain.get_barycentric_weight(); // l_0(x_3)
|
||||||
|
|
||||||
|
// Compute the expected value of h(x_3)
|
||||||
|
let expected_h_eval = std::iter::empty()
|
||||||
|
// Evaluate the circuit using the custom gates provided
|
||||||
|
.chain(vk.cs.gates.iter().map(|poly| {
|
||||||
|
poly.evaluate(
|
||||||
|
&|index| self.fixed_evals[index],
|
||||||
|
&|index| self.advice_evals[index],
|
||||||
|
&|index| self.aux_evals[index],
|
||||||
|
&|a, b| a + &b,
|
||||||
|
&|a, b| a * &b,
|
||||||
|
&|a, scalar| a * &scalar,
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
// l_0(X) * (1 - z(X)) = 0
|
||||||
|
.chain(
|
||||||
|
self.permutation_product_evals
|
||||||
|
.iter()
|
||||||
|
.map(|product_eval| l_0 * &(C::Scalar::one() - &product_eval)),
|
||||||
|
)
|
||||||
|
// z(X) \prod (p(X) + \beta s_i(X) + \gamma)
|
||||||
|
// - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
||||||
|
.chain(
|
||||||
|
vk.cs
|
||||||
|
.permutations
|
||||||
|
.iter()
|
||||||
|
.zip(self.permutation_evals.iter())
|
||||||
|
.zip(self.permutation_product_evals.iter())
|
||||||
|
.zip(self.permutation_product_inv_evals.iter())
|
||||||
|
.map(
|
||||||
|
|(((wires, permutation_evals), product_eval), product_inv_eval)| {
|
||||||
|
let mut left = *product_eval;
|
||||||
|
for (advice_eval, permutation_eval) in wires
|
||||||
|
.iter()
|
||||||
|
.map(|&wire| {
|
||||||
|
self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]
|
||||||
|
})
|
||||||
|
.zip(permutation_evals.iter())
|
||||||
|
{
|
||||||
|
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut right = *product_inv_eval;
|
||||||
|
let mut current_delta = x_0 * &x_3;
|
||||||
|
for advice_eval in wires.iter().map(|&wire| {
|
||||||
|
self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]
|
||||||
|
}) {
|
||||||
|
right *= &(advice_eval + ¤t_delta + &x_1);
|
||||||
|
current_delta *= &C::Scalar::DELTA;
|
||||||
|
}
|
||||||
|
|
||||||
|
left - &right
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.fold(C::Scalar::zero(), |h_eval, v| h_eval * &x_2 + &v);
|
||||||
|
|
||||||
|
// Compute h(x_3) from the prover
|
||||||
|
let (_, h_eval) = self
|
||||||
|
.h_evals
|
||||||
|
.iter()
|
||||||
|
.fold((C::Scalar::one(), C::Scalar::zero()), |(cur, acc), eval| {
|
||||||
|
(cur * &x_3n, acc + &(cur * eval))
|
||||||
|
});
|
||||||
|
|
||||||
|
// Did the prover commit to the correct polynomial?
|
||||||
|
if expected_h_eval != (h_eval * &(x_3n - &C::Scalar::one())) {
|
||||||
|
return Err(Error::ConstraintSystemFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,113 +8,13 @@ use crate::arithmetic::{best_fft, best_multiexp, parallelize, Curve, CurveAffine
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::Hasher;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
||||||
|
|
||||||
|
mod msm;
|
||||||
mod prover;
|
mod prover;
|
||||||
mod verifier;
|
mod verifier;
|
||||||
|
|
||||||
|
pub use msm::MSM;
|
||||||
pub use verifier::{Accumulator, Guard};
|
pub use verifier::{Accumulator, Guard};
|
||||||
|
|
||||||
/// This is a proof object for the polynomial commitment scheme opening.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Proof<C: CurveAffine> {
|
|
||||||
rounds: Vec<(C, C)>,
|
|
||||||
delta: C,
|
|
||||||
z1: C::Scalar,
|
|
||||||
z2: C::Scalar,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A multiscalar multiplication in the polynomial commitment scheme
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
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>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, C: CurveAffine> MSM<'a, C> {
|
|
||||||
/// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add arbitrary term (the scalar and the point)
|
|
||||||
pub fn add_term(&mut self, scalar: C::Scalar, point: C) {
|
|
||||||
self.other_scalars.push(scalar);
|
|
||||||
self.other_bases.push(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
pub fn add_to_g(&mut self, scalars: &[C::Scalar]) {
|
|
||||||
assert_eq!(scalars.len(), self.params.n as usize);
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add term to h
|
|
||||||
pub fn add_to_h(&mut self, scalar: C::Scalar) {
|
|
||||||
self.h_scalar = self.h_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Scale all scalars in the MSM by some scaling factor
|
|
||||||
// TODO: parallelize
|
|
||||||
pub fn scale(&mut self, factor: C::Scalar) {
|
|
||||||
if let Some(g_scalars) = &mut self.g_scalars {
|
|
||||||
for g_scalar in g_scalars.iter_mut() {
|
|
||||||
*g_scalar *= &factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: parallelize
|
|
||||||
for other_scalar in self.other_scalars.iter_mut() {
|
|
||||||
*other_scalar *= &factor;
|
|
||||||
}
|
|
||||||
self.h_scalar = self.h_scalar.map(|a| a * &factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform multiexp and check that it results in zero
|
|
||||||
pub fn eval(self) -> bool {
|
|
||||||
let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0)
|
|
||||||
+ self.h_scalar.map(|_| 1).unwrap_or(0)
|
|
||||||
+ self.other_scalars.len();
|
|
||||||
let mut scalars: Vec<C::Scalar> = Vec::with_capacity(len);
|
|
||||||
let mut bases: Vec<C> = Vec::with_capacity(len);
|
|
||||||
|
|
||||||
scalars.extend(&self.other_scalars);
|
|
||||||
bases.extend(&self.other_bases);
|
|
||||||
|
|
||||||
if let Some(h_scalar) = self.h_scalar {
|
|
||||||
scalars.push(h_scalar);
|
|
||||||
bases.push(self.params.h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(g_scalars) = &self.g_scalars {
|
|
||||||
scalars.extend(g_scalars);
|
|
||||||
bases.extend(self.params.g.iter());
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(scalars.len(), len);
|
|
||||||
|
|
||||||
bool::from(best_multiexp(&scalars, &bases).is_zero())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// These are the public parameters for the polynomial commitment scheme.
|
/// These are the public parameters for the polynomial commitment scheme.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Params<C: CurveAffine> {
|
pub struct Params<C: CurveAffine> {
|
||||||
|
|
@ -125,6 +25,15 @@ pub struct Params<C: CurveAffine> {
|
||||||
pub(crate) h: C,
|
pub(crate) h: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is a proof object for the polynomial commitment scheme opening.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Proof<C: CurveAffine> {
|
||||||
|
rounds: Vec<(C, C)>,
|
||||||
|
delta: C,
|
||||||
|
z1: C::Scalar,
|
||||||
|
z2: C::Scalar,
|
||||||
|
}
|
||||||
|
|
||||||
impl<C: CurveAffine> Params<C> {
|
impl<C: CurveAffine> Params<C> {
|
||||||
/// Initializes parameters for the curve, given a random oracle to draw
|
/// Initializes parameters for the curve, given a random oracle to draw
|
||||||
/// points from.
|
/// points from.
|
||||||
|
|
@ -250,18 +159,7 @@ impl<C: CurveAffine> Params<C> {
|
||||||
/// Generates an empty multiscalar multiplication struct using the
|
/// Generates an empty multiscalar multiplication struct using the
|
||||||
/// appropriate params.
|
/// appropriate params.
|
||||||
pub fn empty_msm(&self) -> MSM<C> {
|
pub fn empty_msm(&self) -> MSM<C> {
|
||||||
let g_scalars = None;
|
MSM::new(self)
|
||||||
let h_scalar = None;
|
|
||||||
let other_scalars = vec![];
|
|
||||||
let other_bases = vec![];
|
|
||||||
|
|
||||||
MSM {
|
|
||||||
params: &self,
|
|
||||||
g_scalars,
|
|
||||||
h_scalar,
|
|
||||||
other_scalars,
|
|
||||||
other_bases,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Getter for g generators
|
/// Getter for g generators
|
||||||
|
|
|
||||||
111
src/poly/commitment/msm.rs
Normal file
111
src/poly/commitment/msm.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
use super::Params;
|
||||||
|
use crate::arithmetic::{best_multiexp, Curve, CurveAffine};
|
||||||
|
|
||||||
|
/// A multiscalar multiplication in the polynomial commitment scheme
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MSM<'a, C: CurveAffine> {
|
||||||
|
pub(crate) params: &'a Params<C>,
|
||||||
|
g_scalars: Option<Vec<C::Scalar>>,
|
||||||
|
h_scalar: Option<C::Scalar>,
|
||||||
|
other_scalars: Vec<C::Scalar>,
|
||||||
|
other_bases: Vec<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C: CurveAffine> MSM<'a, C> {
|
||||||
|
/// Create a new, empty MSM using the provided parameters.
|
||||||
|
pub fn new(params: &'a Params<C>) -> Self {
|
||||||
|
let g_scalars = None;
|
||||||
|
let h_scalar = None;
|
||||||
|
let other_scalars = vec![];
|
||||||
|
let other_bases = vec![];
|
||||||
|
|
||||||
|
MSM {
|
||||||
|
params,
|
||||||
|
g_scalars,
|
||||||
|
h_scalar,
|
||||||
|
other_scalars,
|
||||||
|
other_bases,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add arbitrary term (the scalar and the point)
|
||||||
|
pub fn add_term(&mut self, scalar: C::Scalar, point: C) {
|
||||||
|
self.other_scalars.push(scalar);
|
||||||
|
self.other_bases.push(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
pub fn add_to_g(&mut self, scalars: &[C::Scalar]) {
|
||||||
|
assert_eq!(scalars.len(), self.params.n as usize);
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add term to h
|
||||||
|
pub fn add_to_h(&mut self, scalar: C::Scalar) {
|
||||||
|
self.h_scalar = self.h_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scale all scalars in the MSM by some scaling factor
|
||||||
|
// TODO: parallelize
|
||||||
|
pub fn scale(&mut self, factor: C::Scalar) {
|
||||||
|
if let Some(g_scalars) = &mut self.g_scalars {
|
||||||
|
for g_scalar in g_scalars.iter_mut() {
|
||||||
|
*g_scalar *= &factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: parallelize
|
||||||
|
for other_scalar in self.other_scalars.iter_mut() {
|
||||||
|
*other_scalar *= &factor;
|
||||||
|
}
|
||||||
|
self.h_scalar = self.h_scalar.map(|a| a * &factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform multiexp and check that it results in zero
|
||||||
|
pub fn eval(self) -> bool {
|
||||||
|
let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0)
|
||||||
|
+ self.h_scalar.map(|_| 1).unwrap_or(0)
|
||||||
|
+ self.other_scalars.len();
|
||||||
|
let mut scalars: Vec<C::Scalar> = Vec::with_capacity(len);
|
||||||
|
let mut bases: Vec<C> = Vec::with_capacity(len);
|
||||||
|
|
||||||
|
scalars.extend(&self.other_scalars);
|
||||||
|
bases.extend(&self.other_bases);
|
||||||
|
|
||||||
|
if let Some(h_scalar) = self.h_scalar {
|
||||||
|
scalars.push(h_scalar);
|
||||||
|
bases.push(self.params.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(g_scalars) = &self.g_scalars {
|
||||||
|
scalars.extend(g_scalars);
|
||||||
|
bases.extend(self.params.g.iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(scalars.len(), len);
|
||||||
|
|
||||||
|
bool::from(best_multiexp(&scalars, &bases).is_zero())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue