arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/poly-iop/src/perm_check/util.rs
poly-iop/src/perm_check/util.rsRaw
  1//! This module implements useful functions for the permutation check protocol.
  2
  3use crate::PolyIOPErrors;
  4use ark_ff::PrimeField;
  5use ark_poly::DenseMultilinearExtension;
  6use ark_std::{end_timer, rand::RngCore, start_timer};
  7
  8/// Returns three MLEs:
  9/// - prod(0,x)
 10/// - numerator
 11/// - denominator
 12///
 13/// where
 14/// - `prod(0,x) := prod(0, x1, …, xn)` which is the MLE over the
 15/// evaluations of the following polynomial on the boolean hypercube {0,1}^n:
 16///
 17///  (f(x) + \beta s_id(x) + \gamma)/(g(x) + \beta s_perm(x) + \gamma)
 18///
 19///  where
 20///  - beta and gamma are challenges
 21///  - f(x), g(x), s_id(x), s_perm(x) are mle-s
 22///
 23/// - numerator is the MLE for `f(x) + \beta s_id(x) + \gamma`
 24/// - denominator is the MLE for `g(x) + \beta s_perm(x) + \gamma`
 25///
 26/// The caller needs to check num_vars matches in f/g/s_id/s_perm
 27/// Cost: linear in N.
 28#[allow(clippy::type_complexity)]
 29pub(super) fn compute_prod_0<F: PrimeField>(
 30    beta: &F,
 31    gamma: &F,
 32    fx: &DenseMultilinearExtension<F>,
 33    gx: &DenseMultilinearExtension<F>,
 34    s_perm: &DenseMultilinearExtension<F>,
 35) -> Result<
 36    (
 37        DenseMultilinearExtension<F>,
 38        DenseMultilinearExtension<F>,
 39        DenseMultilinearExtension<F>,
 40    ),
 41    PolyIOPErrors,
 42> {
 43    let start = start_timer!(|| "compute prod(1,x)");
 44
 45    let num_vars = fx.num_vars;
 46    let mut prod_0x_evals = vec![];
 47    let mut numerator_evals = vec![];
 48    let mut denominator_evals = vec![];
 49
 50    let s_id = identity_permutation_mle::<F>(num_vars);
 51
 52    for (&fi, (&gi, (&s_id_i, &s_perm_i))) in
 53        fx.iter().zip(gx.iter().zip(s_id.iter().zip(s_perm.iter())))
 54    {
 55        let numerator = fi + *beta * s_id_i + gamma;
 56        let denominator = gi + *beta * s_perm_i + gamma;
 57
 58        prod_0x_evals.push(numerator / denominator);
 59        numerator_evals.push(numerator);
 60        denominator_evals.push(denominator);
 61    }
 62
 63    let prod_0x = DenseMultilinearExtension::from_evaluations_vec(num_vars, prod_0x_evals);
 64    let numerator = DenseMultilinearExtension::from_evaluations_vec(num_vars, numerator_evals);
 65    let denominator = DenseMultilinearExtension::from_evaluations_vec(num_vars, denominator_evals);
 66
 67    end_timer!(start);
 68    Ok((prod_0x, numerator, denominator))
 69}
 70
 71/// An MLE that represent an identity permutation: `f(index) \mapto index`
 72pub fn identity_permutation_mle<F: PrimeField>(num_vars: usize) -> DenseMultilinearExtension<F> {
 73    let s_id_vec = (0..1u64 << num_vars).map(F::from).collect();
 74    DenseMultilinearExtension::from_evaluations_vec(num_vars, s_id_vec)
 75}
 76
 77/// An MLE that represent a random permutation
 78pub fn random_permutation_mle<F: PrimeField, R: RngCore>(
 79    num_vars: usize,
 80    rng: &mut R,
 81) -> DenseMultilinearExtension<F> {
 82    let len = 1u64 << num_vars;
 83    let mut s_id_vec: Vec<F> = (0..len).map(F::from).collect();
 84    let mut s_perm_vec = vec![];
 85    for _ in 0..len {
 86        let index = rng.next_u64() as usize % s_id_vec.len();
 87        s_perm_vec.push(s_id_vec.remove(index));
 88    }
 89    DenseMultilinearExtension::from_evaluations_vec(num_vars, s_perm_vec)
 90}
 91
 92#[cfg(test)]
 93mod test {
 94    use super::*;
 95    use crate::utils::bit_decompose;
 96    use ark_bls12_381::Fr;
 97    use ark_ff::UniformRand;
 98    use ark_poly::MultilinearExtension;
 99    use ark_std::test_rng;
100
101    #[test]
102    fn test_compute_prod_0() -> Result<(), PolyIOPErrors> {
103        let mut rng = test_rng();
104
105        for num_vars in 2..6 {
106            let f = DenseMultilinearExtension::rand(num_vars, &mut rng);
107            let g = DenseMultilinearExtension::rand(num_vars, &mut rng);
108
109            let s_id = identity_permutation_mle::<Fr>(num_vars);
110            let s_perm = random_permutation_mle(num_vars, &mut rng);
111
112            let beta = Fr::rand(&mut rng);
113            let gamma = Fr::rand(&mut rng);
114
115            let (prod_0, numerator, denominator) = compute_prod_0(&beta, &gamma, &f, &g, &s_perm)?;
116
117            for i in 0..1 << num_vars {
118                let r: Vec<Fr> = bit_decompose(i, num_vars)
119                    .iter()
120                    .map(|&x| Fr::from(x))
121                    .collect();
122
123                let prod_0_eval = prod_0.evaluate(&r).unwrap();
124                let numerator_eval = numerator.evaluate(&r).unwrap();
125                let denominator_eval = denominator.evaluate(&r).unwrap();
126
127                let f_eval = f.evaluate(&r).unwrap();
128                let g_eval = g.evaluate(&r).unwrap();
129                let s_id_eval = s_id.evaluate(&r).unwrap();
130                let s_perm_eval = s_perm.evaluate(&r).unwrap();
131
132                let numerator_eval_rec = f_eval + beta * s_id_eval + gamma;
133                let denominator_eval_rec = g_eval + beta * s_perm_eval + gamma;
134                let prod_0_eval_rec = numerator_eval_rec / denominator_eval_rec;
135
136                assert_eq!(numerator_eval, numerator_eval_rec);
137                assert_eq!(denominator_eval, denominator_eval_rec);
138                assert_eq!(prod_0_eval, prod_0_eval_rec);
139            }
140        }
141        Ok(())
142    }
143}