1use crate::{
2 loader::{native::NativeLoader, LoadedScalar, Loader},
3 pcs::{kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver},
4 util::{
5 arithmetic::{Curve, CurveAffine, Field, MultiMillerLoop},
6 msm::Msm,
7 transcript::{TranscriptRead, TranscriptWrite},
8 },
9 Error,
10};
11use rand::Rng;
12use std::{fmt::Debug, marker::PhantomData};
13
14#[derive(Clone, Debug)]
17pub struct KzgAs<M, MOS>(PhantomData<(M, MOS)>);
18
19impl<M, L, MOS> AccumulationScheme<M::G1Affine, L> for KzgAs<M, MOS>
20where
21 M: MultiMillerLoop,
22 M::G1Affine: CurveAffine<ScalarExt = M::Fr, CurveExt = M::G1>,
23 L: Loader<M::G1Affine>,
24 MOS: Clone + Debug,
25{
26 type Accumulator = KzgAccumulator<M::G1Affine, L>;
27 type VerifyingKey = KzgAsVerifyingKey;
28 type Proof = KzgAsProof<M::G1Affine, L>;
29
30 fn read_proof<T>(
31 vk: &Self::VerifyingKey,
32 instances: &[Self::Accumulator],
33 transcript: &mut T,
34 ) -> Result<Self::Proof, Error>
35 where
36 T: TranscriptRead<M::G1Affine, L>,
37 {
38 KzgAsProof::read(vk, instances, transcript)
39 }
40
41 fn verify(
42 _: &Self::VerifyingKey,
43 instances: &[Self::Accumulator],
44 proof: &Self::Proof,
45 ) -> Result<Self::Accumulator, Error> {
46 let (lhs, rhs) = instances
47 .iter()
48 .map(|accumulator| (&accumulator.lhs, &accumulator.rhs))
49 .chain(proof.blind.as_ref().map(|(lhs, rhs)| (lhs, rhs)))
50 .unzip::<_, _, Vec<_>, Vec<_>>();
51
52 let powers_of_r = proof.r.powers(lhs.len());
53 let [lhs, rhs] = [lhs, rhs].map(|bases| {
54 bases
55 .into_iter()
56 .zip(powers_of_r.iter())
57 .map(|(base, r)| Msm::<M::G1Affine, L>::base(base) * r)
58 .sum::<Msm<_, _>>()
59 .evaluate(None)
60 });
61
62 Ok(KzgAccumulator::new(lhs, rhs))
63 }
64}
65
66#[derive(Clone, Copy, Debug, Default)]
68pub struct KzgAsProvingKey<C>(pub Option<(C, C)>);
69
70impl<C: Clone> KzgAsProvingKey<C> {
71 pub fn new(g: Option<(C, C)>) -> Self {
73 Self(g)
74 }
75
76 pub fn zk(&self) -> bool {
78 self.0.is_some()
79 }
80
81 pub fn vk(&self) -> KzgAsVerifyingKey {
83 KzgAsVerifyingKey(self.zk())
84 }
85}
86
87#[derive(Clone, Copy, Debug, Default)]
89pub struct KzgAsVerifyingKey(bool);
90
91impl KzgAsVerifyingKey {
92 pub fn zk(&self) -> bool {
94 self.0
95 }
96}
97
98#[derive(Clone, Debug)]
100pub struct KzgAsProof<C, L>
101where
102 C: CurveAffine,
103 L: Loader<C>,
104{
105 blind: Option<(L::LoadedEcPoint, L::LoadedEcPoint)>,
106 r: L::LoadedScalar,
107}
108
109impl<C, L> KzgAsProof<C, L>
110where
111 C: CurveAffine,
112 L: Loader<C>,
113{
114 fn read<T>(
115 vk: &KzgAsVerifyingKey,
116 instances: &[KzgAccumulator<C, L>],
117 transcript: &mut T,
118 ) -> Result<Self, Error>
119 where
120 T: TranscriptRead<C, L>,
121 {
122 assert!(!instances.is_empty());
123
124 for accumulator in instances {
125 transcript.common_ec_point(&accumulator.lhs)?;
126 transcript.common_ec_point(&accumulator.rhs)?;
127 }
128
129 let blind = vk
130 .zk()
131 .then(|| Ok((transcript.read_ec_point()?, transcript.read_ec_point()?)))
132 .transpose()?;
133
134 let r = transcript.squeeze_challenge();
135
136 Ok(Self { blind, r })
137 }
138}
139
140impl<M, MOS> AccumulationSchemeProver<M::G1Affine> for KzgAs<M, MOS>
141where
142 M: MultiMillerLoop,
143 M::G1Affine: CurveAffine<ScalarExt = M::Fr, CurveExt = M::G1>,
144 MOS: Clone + Debug,
145{
146 type ProvingKey = KzgAsProvingKey<M::G1Affine>;
147
148 fn create_proof<T, R>(
149 pk: &Self::ProvingKey,
150 instances: &[KzgAccumulator<M::G1Affine, NativeLoader>],
151 transcript: &mut T,
152 rng: R,
153 ) -> Result<KzgAccumulator<M::G1Affine, NativeLoader>, Error>
154 where
155 T: TranscriptWrite<M::G1Affine>,
156 R: Rng,
157 {
158 assert!(!instances.is_empty());
159
160 for accumulator in instances {
161 transcript.common_ec_point(&accumulator.lhs)?;
162 transcript.common_ec_point(&accumulator.rhs)?;
163 }
164
165 let blind = pk
166 .zk()
167 .then(|| {
168 let s = M::Fr::random(rng);
169 let (g, s_g) = pk.0.unwrap();
170 let lhs = (s_g * s).to_affine();
171 let rhs = (g * s).to_affine();
172 transcript.write_ec_point(lhs)?;
173 transcript.write_ec_point(rhs)?;
174 Ok((lhs, rhs))
175 })
176 .transpose()?;
177
178 let r = transcript.squeeze_challenge();
179
180 let (lhs, rhs) = instances
181 .iter()
182 .cloned()
183 .map(|accumulator| (accumulator.lhs, accumulator.rhs))
184 .chain(blind)
185 .unzip::<_, _, Vec<_>, Vec<_>>();
186
187 let powers_of_r = r.powers(lhs.len());
188 let [lhs, rhs] = [lhs, rhs].map(|msms| {
189 msms.iter()
190 .zip(powers_of_r.iter())
191 .map(|(msm, power_of_r)| Msm::<M::G1Affine, NativeLoader>::base(msm) * power_of_r)
192 .sum::<Msm<_, _>>()
193 .evaluate(None)
194 });
195
196 Ok(KzgAccumulator::new(lhs, rhs))
197 }
198}