snark_verifier_sdk/halo2/utils.rs
1use halo2_base::halo2_proofs::{
2 halo2curves::bn256::{Bn256, Fr, G1Affine},
3 plonk::{Circuit, VerifyingKey},
4 poly::kzg::commitment::ParamsKZG,
5};
6use rand::{rngs::StdRng, SeedableRng};
7use snark_verifier::{
8 system::halo2::{compile, Config},
9 verifier::plonk::PlonkProtocol,
10};
11
12use crate::{Snark, SHPLONK};
13
14use super::gen_dummy_snark_from_vk;
15
16#[derive(Clone, Copy, Debug)]
17pub struct AggregationDependencyIntent<'a> {
18 pub vk: &'a VerifyingKey<G1Affine>,
19 pub num_instance: &'a [usize],
20 pub accumulator_indices: Option<&'a [(usize, usize)]>,
21 /// See [`AggregationDependencyIntentOwned::agg_vk_hash_data`].
22 pub agg_vk_hash_data: Option<((usize, usize), Fr)>,
23}
24
25#[derive(Clone, Debug)]
26pub struct AggregationDependencyIntentOwned {
27 pub vk: VerifyingKey<G1Affine>,
28 pub num_instance: Vec<usize>,
29 pub accumulator_indices: Option<Vec<(usize, usize)>>,
30 /// If this dependency is itself from a universal aggregation circuit, this should contain (index, agg_vkey_hash), where `index = (i,j)` is the pair recording that the agg_vkey_hash is located at `instances[i][j]`.
31 pub agg_vk_hash_data: Option<((usize, usize), Fr)>,
32}
33
34impl AggregationDependencyIntent<'_> {
35 /// Converts `self` into `PlonkProtocol`
36 pub fn compile(self, params: &ParamsKZG<Bn256>) -> PlonkProtocol<G1Affine> {
37 compile(
38 params,
39 self.vk,
40 Config::kzg()
41 .with_num_instance(self.num_instance.to_vec())
42 .with_accumulator_indices(self.accumulator_indices.map(|v| v.to_vec())),
43 )
44 }
45}
46
47/// This trait should be implemented on the minimal circuit configuration data necessary to
48/// completely determine an aggregation circuit
49/// (independent of circuit inputs or specific snarks to be aggregated).
50/// This is used to generate a _dummy_ instantiation of a concrete `Circuit` type for the purposes of key generation.
51/// This dummy instantiation just needs to have the correct arithmetization format, but the witnesses do not need to
52/// satisfy constraints.
53///
54/// This trait is specialized for aggregation circuits, which need to aggregate **dependency** snarks.
55/// The aggregation circuit should only depend on the verifying key of each dependency snark.
56pub trait KeygenAggregationCircuitIntent {
57 /// Concrete circuit type. Defaults to [`AggregationCircuit`].
58 type AggregationCircuit: Circuit<Fr>;
59
60 /// The **ordered** list of [`VerifyingKey`]s of the circuits to be aggregated.
61 fn intent_of_dependencies(&self) -> Vec<AggregationDependencyIntent>;
62
63 /// Builds a _dummy_ instantiation of `Self::AggregationCircuit` for the purposes of key generation.
64 /// Assumes that `snarks` is an ordered list of [`Snark`]s, where the `i`th snark corresponds to the `i`th [`VerifyingKey`] in `vk_of_dependencies`.
65 /// The `snarks` only need to have the correct witness sizes (e.g., proof length) but the
66 /// snarks do _not_ need to verify.
67 ///
68 /// May specify additional custom logic for building the aggregation circuit from the snarks.
69 fn build_keygen_circuit_from_snarks(self, snarks: Vec<Snark>) -> Self::AggregationCircuit;
70
71 /// Builds a _dummy_ instantiation of `Self::AggregationCircuit` for the purposes of key generation.
72 ///
73 /// Generates dummy snarks from the verifying keys in `vk_of_dependencies`, **assuming** that SHPLONK is
74 /// used for the multi-open scheme.
75 fn build_keygen_circuit_shplonk(self) -> Self::AggregationCircuit
76 where
77 Self: Sized,
78 {
79 let mut rng = StdRng::seed_from_u64(0u64);
80 let snarks =
81 self.intent_of_dependencies()
82 .into_iter()
83 .map(
84 |AggregationDependencyIntent {
85 vk,
86 num_instance,
87 accumulator_indices,
88 agg_vk_hash_data,
89 }| {
90 let k = vk.get_domain().k();
91 // In KZG `gen_dummy_snark_from_vk` calls `compile`, which only uses `params` for `params.k()` so we can just use a random untrusted setup.
92 // Moreover since this is a dummy snark, the trusted setup shouldn't matter.
93 let params = ParamsKZG::setup(k, &mut rng);
94 let mut snark = gen_dummy_snark_from_vk::<SHPLONK>(
95 ¶ms,
96 vk,
97 num_instance.to_vec(),
98 accumulator_indices.map(|v| v.to_vec()),
99 );
100 // We set the current agg_vk_hash in the dummy snark so that the final agg_vk_hash is correct at the end of keygen.
101 if let Some(((i, j), agg_vk_hash)) = agg_vk_hash_data {
102 assert!(
103 i < snark.instances.len(),
104 "Invalid agg_vk_hash index: ({i},{j}), num_instance: {num_instance:?}");
105 assert!(j < snark.instances[i].len(),
106 "Invalid agg_vk_hash index: ({i},{j}), num_instance: {num_instance:?}");
107 snark.instances[i][j] = agg_vk_hash;
108 }
109 snark
110 },
111 )
112 .collect();
113 self.build_keygen_circuit_from_snarks(snarks)
114 }
115}
116
117impl<'a> From<&'a AggregationDependencyIntentOwned> for AggregationDependencyIntent<'a> {
118 fn from(intent: &'a AggregationDependencyIntentOwned) -> Self {
119 Self {
120 vk: &intent.vk,
121 num_instance: &intent.num_instance,
122 accumulator_indices: intent.accumulator_indices.as_deref(),
123 agg_vk_hash_data: intent.agg_vk_hash_data,
124 }
125 }
126}