midnight-proofs 0.7.1

Fast PLONK-based zero-knowledge proving system
//! Implementation of permutation argument.

use super::circuit::{Any, Column};
use crate::{
    poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
    utils::{
        helpers::{polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice},
        SerdeFormat,
    },
};

pub(crate) mod keygen;
pub(crate) mod prover;
pub(crate) mod verifier;

use std::io;

use ff::{PrimeField, WithSmallOrderMulGroup};
pub use keygen::Assembly;
use midnight_curves::serde::SerdeObject;

use crate::{
    plonk::permutation::keygen::compute_polys_and_cosets,
    poly::{commitment::PolynomialCommitmentScheme, EvaluationDomain},
    utils::helpers::{byte_length, ProcessedSerdeObject},
};

/// A permutation argument.
#[derive(Debug, Clone)]
pub struct Argument {
    /// A sequence of columns involved in the argument.
    pub columns: Vec<Column<Any>>,
}

impl Argument {
    pub(crate) fn new() -> Self {
        Argument { columns: vec![] }
    }

    /// Returns the minimum circuit degree required by the permutation argument.
    /// The argument may use larger degree gates depending on the actual
    /// circuit's degree and how many columns are involved in the permutation.
    pub(crate) fn required_degree(&self) -> usize {
        // degree 2:
        // l_0(X) * (1 - z(X)) = 0
        //
        // We will fit as many polynomials p_i(X) as possible
        // into the required degree of the circuit, so the
        // following will not affect the required degree of
        // this middleware.
        //
        // (1 - (l_last(X) + l_blind(X))) * (
        //   z(\omega X) \prod (p(X) + \beta s_i(X) + \gamma)
        // - z(X) \prod (p(X) + \delta^i \beta X + \gamma)
        // )
        //
        // On the first sets of columns, except the first
        // set, we will do
        //
        // l_0(X) * (z(X) - z'(\omega^(last) X)) = 0
        //
        // where z'(X) is the permutation for the previous set
        // of columns.
        //
        // On the final set of columns, we will do
        //
        // degree 3:
        // l_last(X) * (z'(X)^2 - z'(X)) = 0
        //
        // which will allow the last value to be zero to
        // ensure the argument is perfectly complete.

        // There are constraints of degree 3 regardless of the
        // number of columns involved.
        3
    }

    pub(crate) fn add_column(&mut self, column: Column<Any>) {
        if !self.columns.contains(&column) {
            self.columns.push(column);
        }
    }

    /// Returns columns that participate on the permutation argument.
    pub fn get_columns(&self) -> Vec<Column<Any>> {
        self.columns.clone()
    }
}

/// The verifying key for a single permutation argument.
#[derive(Clone, Debug)]
pub struct VerifyingKey<F: PrimeField, CS: PolynomialCommitmentScheme<F>> {
    commitments: Vec<CS::Commitment>,
}

impl<F: PrimeField, CS: PolynomialCommitmentScheme<F>> VerifyingKey<F, CS> {
    /// Returns the (permutation argument) commitments of the verifying key.
    pub fn commitments(&self) -> &Vec<CS::Commitment> {
        &self.commitments
    }

    pub(crate) fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()>
    where
        CS::Commitment: ProcessedSerdeObject,
    {
        for commitment in &self.commitments {
            commitment.write(writer, format)?;
        }
        Ok(())
    }

    pub(crate) fn read<R: io::Read>(
        reader: &mut R,
        argument: &Argument,
        format: SerdeFormat,
    ) -> io::Result<Self>
    where
        CS::Commitment: ProcessedSerdeObject,
    {
        let commitments = (0..argument.columns.len())
            .map(|_| CS::Commitment::read(reader, format))
            .collect::<Result<Vec<_>, _>>()?;
        Ok(VerifyingKey { commitments })
    }

    pub(crate) fn bytes_length(&self, format: SerdeFormat) -> usize
    where
        CS::Commitment: ProcessedSerdeObject,
    {
        self.commitments.len() * byte_length::<CS::Commitment>(format)
    }
}

/// The proving key for a single permutation argument.
#[derive(Clone, Debug)]
pub(crate) struct ProvingKey<F: PrimeField> {
    pub(crate) permutations: Vec<Polynomial<F, LagrangeCoeff>>,
    pub(crate) polys: Vec<Polynomial<F, Coeff>>,
    pub(crate) cosets: Vec<Polynomial<F, ExtendedLagrangeCoeff>>,
}

impl<F: WithSmallOrderMulGroup<3> + SerdeObject> ProvingKey<F> {
    /// Reads proving key for a single permutation argument from buffer using
    /// `Polynomial::read`.
    pub(super) fn read<R: io::Read>(
        reader: &mut R,
        format: SerdeFormat,
        domain: &EvaluationDomain<F>,
        p: &Argument,
    ) -> io::Result<Self> {
        let permutations = read_polynomial_vec(reader, format)?;
        let (polys, cosets) = compute_polys_and_cosets::<F>(domain, p, &permutations);
        Ok(ProvingKey {
            permutations,
            polys,
            cosets,
        })
    }

    /// Writes proving key for a single permutation argument to buffer using
    /// `Polynomial::write`.
    pub(super) fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
        write_polynomial_slice(&self.permutations, writer)?;
        Ok(())
    }
}

impl<F: PrimeField> ProvingKey<F> {
    /// Gets the total number of bytes in the serialization of `self`
    pub(super) fn bytes_length(&self) -> usize {
        polynomial_slice_byte_length(&self.permutations)
            + polynomial_slice_byte_length(&self.polys)
            + polynomial_slice_byte_length(&self.cosets)
    }
}