1mod batching;
10pub(crate) mod srs;
11pub(crate) mod util;
12
13use crate::{
14 prelude::{Commitment, UnivariateUniversalParams},
15 univariate_kzg::UnivariateKzgProof,
16 PCSError, PolynomialCommitmentScheme, StructuredReferenceString,
17};
18#[cfg(target_has_atomic = "ptr")]
19use alloc::sync::Arc;
20use ark_ec::{
21 pairing::Pairing,
22 scalar_mul::{fixed_base::FixedBase, variable_base::VariableBaseMSM},
23 AffineRepr, CurveGroup,
24};
25use ark_ff::PrimeField;
26use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
27use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
28use ark_std::{
29 borrow::Borrow,
30 end_timer, format,
31 marker::PhantomData,
32 rand::{CryptoRng, RngCore},
33 start_timer,
34 string::ToString,
35 vec,
36 vec::Vec,
37 One, Zero,
38};
39use batching::{batch_open_internal, batch_verify_internal};
40use srs::{MultilinearProverParam, MultilinearUniversalParams, MultilinearVerifierParam};
41use util::merge_polynomials;
42
43type Srs<E> = (MultilinearUniversalParams<E>, UnivariateUniversalParams<E>);
45type ProverParam<E> = <Srs<E> as StructuredReferenceString>::ProverParam;
46type VerifierParam<E> = <Srs<E> as StructuredReferenceString>::VerifierParam;
47
48pub struct MultilinearKzgPCS<E: Pairing> {
50 #[doc(hidden)]
51 phantom: PhantomData<E>,
52}
53
54#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq, Eq)]
55#[derivative(Hash)]
56pub struct MultilinearKzgProof<E: Pairing> {
58 pub proofs: Vec<E::G1Affine>,
60}
61
62#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq, Eq)]
63pub struct MultilinearKzgBatchProof<E: Pairing> {
65 pub proof: MultilinearKzgProof<E>,
67 pub q_x_commit: Commitment<E>,
71 pub q_x_opens: Vec<UnivariateKzgProof<E>>,
73}
74
75#[cfg(target_has_atomic = "ptr")]
81pub type MLE<F> = Arc<DenseMultilinearExtension<F>>;
82#[cfg(not(target_has_atomic = "ptr"))]
83pub type MLE<F> = DenseMultilinearExtension<F>;
84
85impl<E: Pairing> PolynomialCommitmentScheme for MultilinearKzgPCS<E> {
86 type SRS = Srs<E>;
88 type Polynomial = MLE<E::ScalarField>;
90 type Point = Vec<E::ScalarField>;
91 type Evaluation = E::ScalarField;
92 type Commitment = Commitment<E>;
94 type BatchCommitment = Commitment<E>;
95 type Proof = MultilinearKzgProof<E>;
96 type BatchProof = MultilinearKzgBatchProof<E>;
97
98 fn trim(
102 srs: impl Borrow<Self::SRS>,
103 supported_log_degree: usize,
104 supported_num_vars: Option<usize>,
105 ) -> Result<(ProverParam<E>, VerifierParam<E>), PCSError> {
106 let supported_num_vars = match supported_num_vars {
107 Some(p) => p,
108 None => {
109 return Err(PCSError::InvalidParameters(
110 "multilinear should receive a num_var param".to_string(),
111 ))
112 },
113 };
114 let (uni_ck, uni_vk) = srs.borrow().1.trim(supported_log_degree)?;
115 let (ml_ck, ml_vk) = srs.borrow().0.trim(supported_num_vars)?;
116
117 Ok(((ml_ck, uni_ck), (ml_vk, uni_vk)))
118 }
119
120 fn commit(
125 prover_param: impl Borrow<ProverParam<E>>,
126 poly: &Self::Polynomial,
127 ) -> Result<Self::Commitment, PCSError> {
128 let prover_param = prover_param.borrow();
129 let commit_timer = start_timer!(|| "commit");
130 if prover_param.0.num_vars < poly.num_vars {
131 return Err(PCSError::InvalidParameters(format!(
132 "Poly length ({}) exceeds param limit ({})",
133 poly.num_vars, prover_param.0.num_vars
134 )));
135 }
136 let ignored = prover_param.0.num_vars - poly.num_vars;
137 let scalars: Vec<_> = poly
138 .to_evaluations()
139 .into_iter()
140 .map(|x| x.into_bigint())
141 .collect();
142 let commitment = E::G1::msm_bigint(
143 &prover_param.0.powers_of_g[ignored].evals,
144 scalars.as_slice(),
145 )
146 .into_affine();
147
148 end_timer!(commit_timer);
149 Ok(Commitment(commitment))
150 }
151
152 fn batch_commit(
157 prover_param: impl Borrow<ProverParam<E>>,
158 polys: &[Self::Polynomial],
159 ) -> Result<Self::Commitment, PCSError> {
160 let prover_param = prover_param.borrow();
161 let commit_timer = start_timer!(|| "multi commit");
162 let poly = merge_polynomials(polys)?;
163
164 let scalars: Vec<_> = poly
165 .to_evaluations()
166 .iter()
167 .map(|x| x.into_bigint())
168 .collect();
169
170 let commitment =
171 E::G1::msm_bigint(&prover_param.0.powers_of_g[0].evals, scalars.as_slice())
172 .into_affine();
173
174 end_timer!(commit_timer);
175 Ok(Commitment(commitment))
176 }
177
178 fn open(
188 prover_param: impl Borrow<ProverParam<E>>,
189 polynomial: &Self::Polynomial,
190 point: &Self::Point,
191 ) -> Result<(Self::Proof, Self::Evaluation), PCSError> {
192 open_internal(&prover_param.borrow().0, polynomial, point)
193 }
194
195 fn batch_open(
227 prover_param: impl Borrow<ProverParam<E>>,
228 batch_commitment: &Self::BatchCommitment,
229 polynomials: &[Self::Polynomial],
230 points: &[Self::Point],
231 ) -> Result<(Self::BatchProof, Vec<Self::Evaluation>), PCSError> {
232 batch_open_internal::<E>(
233 &prover_param.borrow().1,
234 &prover_param.borrow().0,
235 polynomials,
236 batch_commitment,
237 points,
238 )
239 }
240
241 fn verify(
248 verifier_param: &VerifierParam<E>,
249 commitment: &Self::Commitment,
250 point: &Self::Point,
251 value: &E::ScalarField,
252 proof: &Self::Proof,
253 ) -> Result<bool, PCSError> {
254 verify_internal(&verifier_param.0, commitment, point, value, proof)
255 }
256
257 fn batch_verify<R: RngCore + CryptoRng>(
269 verifier_param: &VerifierParam<E>,
270 batch_commitment: &Self::BatchCommitment,
271 points: &[Self::Point],
272 values: &[E::ScalarField],
273 batch_proof: &Self::BatchProof,
274 _rng: &mut R,
275 ) -> Result<bool, PCSError> {
276 batch_verify_internal(
277 &verifier_param.1,
278 &verifier_param.0,
279 batch_commitment,
280 points,
281 values,
282 batch_proof,
283 )
284 }
285}
286
287fn open_internal<E: Pairing>(
296 prover_param: &MultilinearProverParam<E>,
297 polynomial: &DenseMultilinearExtension<E::ScalarField>,
298 point: &[E::ScalarField],
299) -> Result<(MultilinearKzgProof<E>, E::ScalarField), PCSError> {
300 let open_timer = start_timer!(|| format!("open mle with {} variable", polynomial.num_vars));
301
302 if polynomial.num_vars() > prover_param.num_vars {
303 return Err(PCSError::InvalidParameters(format!(
304 "Polynomial num_vars {} exceed the limit {}",
305 polynomial.num_vars, prover_param.num_vars
306 )));
307 }
308
309 if polynomial.num_vars() != point.len() {
310 return Err(PCSError::InvalidParameters(format!(
311 "Polynomial num_vars {} does not match point len {}",
312 polynomial.num_vars,
313 point.len()
314 )));
315 }
316
317 let nv = polynomial.num_vars();
318 let ignored = prover_param.num_vars - nv + 1;
320
321 let mut f = polynomial.to_evaluations();
322
323 let mut proofs = Vec::new();
324
325 for (i, (&point_at_k, gi)) in point
326 .iter()
327 .zip(prover_param.powers_of_g[ignored..ignored + nv].iter())
328 .enumerate()
329 {
330 let ith_round = start_timer!(|| format!("{}-th round", i));
331
332 let k = nv - 1 - i;
333 let cur_dim = 1 << k;
334 let mut q = vec![E::ScalarField::zero(); cur_dim];
335 let mut r = vec![E::ScalarField::zero(); cur_dim];
336
337 let ith_round_eval = start_timer!(|| format!("{}-th round eval", i));
338 for b in 0..(1 << k) {
339 q[b] = f[(b << 1) + 1] - f[b << 1];
341
342 r[b] = f[b << 1] + (q[b] * point_at_k);
344 }
345 f = r;
346 end_timer!(ith_round_eval);
347 let scalars: Vec<_> = q.iter().map(|x| x.into_bigint()).collect();
348
349 let msm_timer = start_timer!(|| format!("msm of size {} at round {}", gi.evals.len(), i));
351
352 proofs.push(E::G1::msm_bigint(&gi.evals, &scalars).into_affine());
353 end_timer!(msm_timer);
354
355 end_timer!(ith_round);
356 }
357 let eval = polynomial
358 .evaluate(point)
359 .ok_or_else(|| PCSError::InvalidParameters("fail to eval poly at the point".to_string()))?;
360 end_timer!(open_timer);
361 Ok((MultilinearKzgProof { proofs }, eval))
362}
363
364fn verify_internal<E: Pairing>(
371 verifier_param: &MultilinearVerifierParam<E>,
372 commitment: &Commitment<E>,
373 point: &[E::ScalarField],
374 value: &E::ScalarField,
375 proof: &MultilinearKzgProof<E>,
376) -> Result<bool, PCSError> {
377 let verify_timer = start_timer!(|| "verify");
378 let num_var = point.len();
379
380 if num_var > verifier_param.num_vars {
381 return Err(PCSError::InvalidParameters(format!(
382 "point length ({}) exceeds param limit ({})",
383 num_var, verifier_param.num_vars
384 )));
385 }
386
387 let prepare_inputs_timer = start_timer!(|| "prepare pairing inputs");
388
389 let scalar_size = E::ScalarField::MODULUS_BIT_SIZE as usize;
390 let window_size = FixedBase::get_mul_window_size(num_var);
391
392 let h_table =
393 FixedBase::get_window_table(scalar_size, window_size, verifier_param.h.into_group());
394 let h_mul: Vec<E::G2> = FixedBase::msm(scalar_size, window_size, &h_table, point);
395
396 let ignored = verifier_param.num_vars - num_var;
398 let h_vec: Vec<_> = (0..num_var)
399 .map(|i| verifier_param.h_mask[ignored + i].into_group() - h_mul[i])
400 .collect();
401 let h_vec: Vec<E::G2Affine> = E::G2::normalize_batch(&h_vec);
402 end_timer!(prepare_inputs_timer);
403
404 let pairing_product_timer = start_timer!(|| "pairing product");
405
406 let mut pairings_l: Vec<E::G1Prepared> = proof
407 .proofs
408 .iter()
409 .map(|&x| E::G1Prepared::from(x))
410 .collect();
411
412 let mut pairings_r: Vec<E::G2Prepared> = h_vec
413 .into_iter()
414 .take(num_var)
415 .map(E::G2Prepared::from)
416 .collect();
417 pairings_l.push(E::G1Prepared::from(
418 (verifier_param.g * (*value) - commitment.0.into_group()).into_affine(),
419 ));
420 pairings_r.push(E::G2Prepared::from(verifier_param.h));
421
422 let res = E::multi_pairing(pairings_l, pairings_r).0 == E::TargetField::one();
423
424 end_timer!(pairing_product_timer);
425 end_timer!(verify_timer);
426 Ok(res)
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432 use ark_bls12_381::Bls12_381;
433 use ark_std::UniformRand;
434 use jf_utils::test_rng;
435 type E = Bls12_381;
436 type Fr = <E as Pairing>::ScalarField;
437
438 fn test_single_helper<R: RngCore + CryptoRng>(
439 params: &(MultilinearUniversalParams<E>, UnivariateUniversalParams<E>),
440 poly: &MLE<Fr>,
441 rng: &mut R,
442 ) -> Result<(), PCSError> {
443 let nv = poly.num_vars();
444 assert_ne!(nv, 0);
445 let uni_degree = 1;
446 let (ck, vk) = MultilinearKzgPCS::trim(params, uni_degree, Some(nv))?;
447 let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect();
448 let com = MultilinearKzgPCS::commit(&ck, poly)?;
449 let (proof, value) = MultilinearKzgPCS::open(&ck, poly, &point)?;
450
451 assert!(MultilinearKzgPCS::verify(
452 &vk, &com, &point, &value, &proof
453 )?);
454
455 let value = Fr::rand(rng);
456 assert!(!MultilinearKzgPCS::verify(
457 &vk, &com, &point, &value, &proof
458 )?);
459
460 Ok(())
461 }
462
463 #[test]
464 fn test_single_commit() -> Result<(), PCSError> {
465 let mut rng = test_rng();
466
467 let params = MultilinearKzgPCS::<E>::gen_srs_for_testing(&mut rng, 10)?;
468
469 let poly1 = MLE::from(DenseMultilinearExtension::rand(8, &mut rng));
471 test_single_helper(¶ms, &poly1, &mut rng)?;
472
473 let poly2 = MLE::from(DenseMultilinearExtension::rand(1, &mut rng));
475 test_single_helper(¶ms, &poly2, &mut rng)?;
476
477 Ok(())
478 }
479
480 #[test]
481 fn setup_commit_verify_constant_polynomial() {
482 let mut rng = test_rng();
483
484 assert!(MultilinearKzgPCS::<E>::gen_srs_for_testing(&mut rng, 0).is_err());
486 }
487}