legogroth16/aggregation/
utils.rs

1use ark_ec::{
2    pairing::{Pairing, PairingOutput},
3    AffineRepr, CurveGroup, VariableBaseMSM,
4};
5use ark_ff::PrimeField;
6use ark_std::{
7    cfg_into_iter, cfg_iter, cfg_iter_mut,
8    ops::{AddAssign, Mul, MulAssign},
9    string::ToString,
10    vec::Vec,
11};
12use dock_crypto_utils::{
13    ff::{powers, sum_of_powers},
14    randomized_pairing_check::RandomizedPairingChecker,
15};
16
17use crate::aggregation::{
18    commitment::PairCommitment,
19    key::{Key, PreparedVKey},
20};
21
22use crate::aggregation::{
23    error::AggregationError,
24    kzg::{prove_commitment_v, prove_commitment_w, verify_kzg_v, verify_kzg_w, KZGOpening},
25    srs::VerifierSRSProjective,
26};
27
28#[cfg(feature = "parallel")]
29use rayon::prelude::*;
30
31/// compress is similar to commit::{V,W}KEY::compress: it modifies the `vec`
32/// vector by setting the value at index $i:0 -> split$  $vec[i] = vec[i] +
33/// vec[i+split]^scaler$. The `vec` vector is half of its size after this call.
34pub(crate) fn compress<C: AffineRepr>(vec: &mut Vec<C>, split: usize, scalar: &C::ScalarField) {
35    let s_repr = scalar.into_bigint();
36    let (left, right) = vec.split_at_mut(split);
37    cfg_iter_mut!(left)
38        .zip(cfg_iter!(right))
39        .for_each(|(a_l, a_r)| {
40            let x = a_r.mul_bigint(s_repr);
41            *a_l = (x + *a_l).into_affine();
42        });
43    let len = left.len();
44    vec.resize(len, C::zero());
45}
46
47pub(crate) fn inner_product_and_single_commitments<E: Pairing>(
48    c_left: &[E::G1Affine],
49    c_right: &[E::G1Affine],
50    r_left_bi: &[<E::ScalarField as PrimeField>::BigInt],
51    r_right_bi: &[<E::ScalarField as PrimeField>::BigInt],
52    vk_left_prep: PreparedVKey<E>,
53    vk_right_prep: PreparedVKey<E>,
54) -> (
55    E::G1Affine,
56    E::G1Affine,
57    PairCommitment<E>,
58    PairCommitment<E>,
59) {
60    // z_l = c[n':] ^ r[:n']
61    let zc_l = E::G1::msm_bigint(c_right, r_left_bi).into_affine();
62    // Z_r = c[:n'] ^ r[n':]
63    let zc_r = E::G1::msm_bigint(c_left, r_right_bi).into_affine();
64
65    // u_l = c[n':] * v[:n']
66    let tuc_l = PairCommitment::<E>::single(vk_left_prep, c_right).unwrap();
67    // u_r = c[:n'] * v[n':]
68    let tuc_r = PairCommitment::<E>::single(vk_right_prep, c_left).unwrap();
69
70    (zc_l, zc_r, tuc_l, tuc_r)
71}
72
73pub(crate) fn inner_product_and_double_commitments<E: Pairing>(
74    a_left: &[E::G1Affine],
75    a_right: &[E::G1Affine],
76    b_left: Vec<E::G2Prepared>,
77    b_right: Vec<E::G2Prepared>,
78    wk_left: &Key<E::G1Affine>,
79    wk_right: &Key<E::G1Affine>,
80    vk_left_prep: PreparedVKey<E>,
81    vk_right_prep: PreparedVKey<E>,
82) -> (
83    PairingOutput<E>,
84    PairingOutput<E>,
85    PairCommitment<E>,
86    PairCommitment<E>,
87) {
88    let tab_l =
89        PairCommitment::<E>::double(vk_left_prep, wk_right, &a_right, b_left.clone()).unwrap();
90
91    let tab_r =
92        PairCommitment::<E>::double(vk_right_prep, wk_left, &a_left, b_right.clone()).unwrap();
93
94    // \prod e(A_right,B_left)
95    let zab_l = E::multi_pairing(a_right, b_left);
96    let zab_r = E::multi_pairing(a_left, b_right);
97    (zab_l, zab_r, tab_l, tab_r)
98}
99
100pub(crate) fn aggregate_public_inputs<G: AffineRepr>(
101    public_inputs: &[Vec<G::ScalarField>],
102    r_powers: &[G::ScalarField],
103    r_sum: G::ScalarField,
104    gamma_abc_g1: &[G],
105) -> G {
106    // compute the middle part of the final pairing equation, the one with the public inputs
107
108    // We want to compute MUL(i:0 -> l) S_i ^ (SUM(j:0 -> n) ai,j * r^j)
109    // this table keeps tracks of incremental computation of each i-th
110    // exponent to later multiply with S_i
111    // The index of the table is i, which is an index of the public
112    // input element
113    // We incrementally build the r vector and the table
114    // NOTE: in this version it's not r^2j but simply r^j
115
116    let l = public_inputs[0].len();
117
118    // now we do the multi exponentiation
119    let mut summed = cfg_into_iter!(0..l)
120        .map(|i| {
121            // i denotes the column of the public input, and j denotes which public input
122            let mut c = public_inputs[0][i];
123            for j in 1..public_inputs.len() {
124                let mut ai = public_inputs[j][i];
125                ai.mul_assign(&r_powers[j]);
126                c.add_assign(&ai);
127            }
128            c.into_bigint()
129        })
130        .collect::<Vec<_>>();
131
132    summed.insert(0, r_sum.into_bigint());
133
134    G::Group::msm_bigint(&gamma_abc_g1, &summed).into_affine()
135}
136
137pub(crate) fn prove_commitments<E: Pairing>(
138    h_alpha_powers_table: &[E::G2Affine],
139    h_beta_powers_table: &[E::G2Affine],
140    g_alpha_powers_table: &[E::G1Affine],
141    g_beta_powers_table: &[E::G1Affine],
142    challenges: &[E::ScalarField],
143    challenges_inv: &[E::ScalarField],
144    shift: &E::ScalarField,
145    kzg_challenge: &E::ScalarField,
146) -> Result<(KZGOpening<E::G2Affine>, KZGOpening<E::G1Affine>), AggregationError> {
147    let vkey_opening = prove_commitment_v(
148        h_alpha_powers_table,
149        h_beta_powers_table,
150        challenges_inv,
151        kzg_challenge,
152    )?;
153    let wkey_opening = prove_commitment_w(
154        g_alpha_powers_table,
155        g_beta_powers_table,
156        challenges,
157        shift,
158        kzg_challenge,
159    )?;
160    Ok((vkey_opening, wkey_opening))
161}
162
163pub(crate) fn verify_kzg<E: Pairing>(
164    v_srs: &VerifierSRSProjective<E>,
165    final_vkey: &(E::G2Affine, E::G2Affine),
166    vkey_opening: &KZGOpening<E::G2Affine>,
167    final_wkey: &(E::G1Affine, E::G1Affine),
168    wkey_opening: &KZGOpening<E::G1Affine>,
169    challenges: &[E::ScalarField],
170    challenges_inv: &[E::ScalarField],
171    shift: &E::ScalarField,
172    kzg_challenge: &E::ScalarField,
173    pairing_checker: &mut RandomizedPairingChecker<E>,
174) {
175    // Verify commitment keys wellformed
176    // check the opening proof for v
177    verify_kzg_v(
178        v_srs,
179        final_vkey,
180        vkey_opening,
181        &challenges_inv,
182        kzg_challenge,
183        pairing_checker,
184    );
185
186    // check the opening proof for w - note that w has been rescaled by $r^{-1}$
187    verify_kzg_w(
188        v_srs,
189        final_wkey,
190        wkey_opening,
191        &challenges,
192        shift,
193        kzg_challenge,
194        pairing_checker,
195    );
196}
197
198pub(crate) fn final_verification_check<E: Pairing>(
199    mut source1: Vec<E::G1Affine>,
200    mut source2: Vec<E::G2Affine>,
201    z_c: E::G1Affine,
202    z_ab: &PairingOutput<E>,
203    r: &E::ScalarField,
204    public_inputs: &[Vec<E::ScalarField>],
205    alpha_g1: &E::G1Affine,
206    beta_g2: E::G2Affine,
207    gamma_g2: E::G2Affine,
208    delta_g2: E::G2Affine,
209    gamma_abc_g1: &[E::G1Affine],
210    checker: &mut RandomizedPairingChecker<E>,
211) -> Result<(), AggregationError> {
212    let public_inputs_len = public_inputs
213        .len()
214        .try_into()
215        .map_err(|_| AggregationError::PublicInputsTooLarge(public_inputs.len()))?;
216    let r_powers = powers(r, public_inputs_len);
217    let r_sum = sum_of_powers::<E::ScalarField>(r, public_inputs_len);
218
219    // Check aggregate pairing product equation
220
221    let alpha_g1_r_sum = alpha_g1.mul(r_sum);
222    source1.push(alpha_g1_r_sum.into_affine());
223    source2.push(beta_g2);
224
225    source1.push(aggregate_public_inputs(
226        public_inputs,
227        &r_powers,
228        r_sum,
229        gamma_abc_g1,
230    ));
231    source2.push(gamma_g2);
232
233    source1.push(z_c);
234    source2.push(delta_g2);
235
236    checker.add_multiple_sources_and_target(&source1, source2, &z_ab);
237
238    match checker.verify() {
239        true => Ok(()),
240        false => Err(AggregationError::InvalidProof(
241            "Proof Verification Failed due to pairing checks".to_string(),
242        )),
243    }
244}