use crate::composer::permutation::constants::{K1, K2, K3};
use crate::fft::{EvaluationDomain, Evaluations, Polynomial};
use dusk_bls12_381::BlsScalar;
#[cfg(feature = "rkyv-impl")]
use bytecheck::CheckBytes;
#[cfg(feature = "rkyv-impl")]
use rkyv::{
ser::{ScratchSpace, Serializer},
Archive, Deserialize, Serialize,
};
#[derive(Debug, Eq, PartialEq, Clone)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Deserialize, Serialize),
archive(bound(serialize = "__S: Serializer + ScratchSpace")),
archive_attr(derive(CheckBytes))
)]
pub(crate) struct ProverKey {
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
pub(crate) s_sigma_1: (Polynomial, Evaluations),
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
pub(crate) s_sigma_2: (Polynomial, Evaluations),
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
pub(crate) s_sigma_3: (Polynomial, Evaluations),
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
pub(crate) s_sigma_4: (Polynomial, Evaluations),
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
pub(crate) linear_evaluations: Evaluations,
}
impl ProverKey {
pub(crate) fn compute_quotient_i(
&self,
index: usize,
a_i: &BlsScalar,
b_i: &BlsScalar,
c_i: &BlsScalar,
d_i: &BlsScalar,
z_i: &BlsScalar,
z_i_w: &BlsScalar,
alpha: &BlsScalar,
l1_alpha_sq: &BlsScalar,
beta: &BlsScalar,
gamma: &BlsScalar,
) -> BlsScalar {
let a = self.compute_quotient_identity_range_check_i(
index, a_i, b_i, c_i, d_i, z_i, alpha, beta, gamma,
);
let b = self.compute_quotient_copy_range_check_i(
index, a_i, b_i, c_i, d_i, z_i_w, alpha, beta, gamma,
);
let c = self.compute_quotient_term_check_one_i(z_i, l1_alpha_sq);
a + b + c
}
fn compute_quotient_identity_range_check_i(
&self,
index: usize,
a_i: &BlsScalar,
b_i: &BlsScalar,
c_i: &BlsScalar,
d_i: &BlsScalar,
z_i: &BlsScalar,
alpha: &BlsScalar,
beta: &BlsScalar,
gamma: &BlsScalar,
) -> BlsScalar {
let x = self.linear_evaluations[index];
(a_i + (beta * x) + gamma)
* (b_i + (beta * K1 * x) + gamma)
* (c_i + (beta * K2 * x) + gamma)
* (d_i + (beta * K3 * x) + gamma)
* z_i
* alpha
}
fn compute_quotient_copy_range_check_i(
&self,
index: usize,
a_i: &BlsScalar,
b_i: &BlsScalar,
c_i: &BlsScalar,
d_i: &BlsScalar,
z_i_w: &BlsScalar,
alpha: &BlsScalar,
beta: &BlsScalar,
gamma: &BlsScalar,
) -> BlsScalar {
let s_sigma_1_eval = self.s_sigma_1.1[index];
let s_sigma_2_eval = self.s_sigma_2.1[index];
let s_sigma_3_eval = self.s_sigma_3.1[index];
let s_sigma_4_eval = self.s_sigma_4.1[index];
let product = (a_i + (beta * s_sigma_1_eval) + gamma)
* (b_i + (beta * s_sigma_2_eval) + gamma)
* (c_i + (beta * s_sigma_3_eval) + gamma)
* (d_i + (beta * s_sigma_4_eval) + gamma)
* z_i_w
* alpha;
-product
}
fn compute_quotient_term_check_one_i(
&self,
z_i: &BlsScalar,
l1_alpha_sq: &BlsScalar,
) -> BlsScalar {
(z_i - BlsScalar::one()) * l1_alpha_sq
}
pub(crate) fn compute_linearization(
&self,
z_challenge: &BlsScalar,
(alpha, beta, gamma): (&BlsScalar, &BlsScalar, &BlsScalar),
(a_eval, b_eval, c_eval, d_eval): (
&BlsScalar,
&BlsScalar,
&BlsScalar,
&BlsScalar,
),
(sigma_1_eval, sigma_2_eval, sigma_3_eval): (
&BlsScalar,
&BlsScalar,
&BlsScalar,
),
z_eval: &BlsScalar,
z_poly: &Polynomial,
) -> Polynomial {
let a = self.compute_linearizer_identity_range_check(
(a_eval, b_eval, c_eval, d_eval),
z_challenge,
(alpha, beta, gamma),
z_poly,
);
let b = self.compute_linearizer_copy_range_check(
(a_eval, b_eval, c_eval),
z_eval,
sigma_1_eval,
sigma_2_eval,
sigma_3_eval,
(alpha, beta, gamma),
&self.s_sigma_4.0,
);
let domain = EvaluationDomain::new(z_poly.degree() - 2).unwrap();
let c = self.compute_linearizer_check_is_one(
&domain,
z_challenge,
&alpha.square(),
z_poly,
);
&(&a + &b) + &c
}
fn compute_linearizer_identity_range_check(
&self,
(a_eval, b_eval, c_eval, d_eval): (
&BlsScalar,
&BlsScalar,
&BlsScalar,
&BlsScalar,
),
z_challenge: &BlsScalar,
(alpha, beta, gamma): (&BlsScalar, &BlsScalar, &BlsScalar),
z_poly: &Polynomial,
) -> Polynomial {
let beta_z = beta * z_challenge;
let mut a_0 = a_eval + beta_z;
a_0 += gamma;
let beta_z_k1 = K1 * beta_z;
let mut a_1 = b_eval + beta_z_k1;
a_1 += gamma;
let beta_z_k2 = K2 * beta_z;
let mut a_2 = c_eval + beta_z_k2;
a_2 += gamma;
let beta_z_k3 = K3 * beta_z;
let mut a_3 = d_eval + beta_z_k3;
a_3 += gamma;
let mut a = a_0 * a_1;
a *= a_2;
a *= a_3;
a *= alpha; z_poly * &a }
fn compute_linearizer_copy_range_check(
&self,
(a_eval, b_eval, c_eval): (&BlsScalar, &BlsScalar, &BlsScalar),
z_eval: &BlsScalar,
sigma_1_eval: &BlsScalar,
sigma_2_eval: &BlsScalar,
sigma_3_eval: &BlsScalar,
(alpha, beta, gamma): (&BlsScalar, &BlsScalar, &BlsScalar),
s_sigma_4_poly: &Polynomial,
) -> Polynomial {
let beta_sigma_1 = beta * sigma_1_eval;
let mut a_0 = a_eval + beta_sigma_1;
a_0 += gamma;
let beta_sigma_2 = beta * sigma_2_eval;
let mut a_1 = b_eval + beta_sigma_2;
a_1 += gamma;
let beta_sigma_3 = beta * sigma_3_eval;
let mut a_2 = c_eval + beta_sigma_3;
a_2 += gamma;
let beta_z_eval = beta * z_eval;
let mut a = a_0 * a_1 * a_2;
a *= beta_z_eval;
a *= alpha; s_sigma_4_poly * &-a }
fn compute_linearizer_check_is_one(
&self,
domain: &EvaluationDomain,
z_challenge: &BlsScalar,
alpha_sq: &BlsScalar,
z_coeffs: &Polynomial,
) -> Polynomial {
let l_1_z = domain.evaluate_all_lagrange_coefficients(*z_challenge)[0];
z_coeffs * &(l_1_z * alpha_sq)
}
}