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