1use ark_ec::pairing::Pairing;
2use ark_ec::twisted_edwards::{Affine, TECurveConfig};
3use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
4use ark_ff::PrimeField;
5use ark_poly::EvaluationDomain;
6use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
7use ark_std::fmt;
8use ark_std::iter;
9use ark_std::ops::Range;
10use ark_std::vec::Vec;
11use w3f_pcs::pcs::kzg::urs::URS;
12use w3f_pcs::pcs::PcsParams;
13
14use w3f_plonk_common::domain::ZK_ROWS;
15
16use crate::PiopParams;
17
18const IDLE_ROWS: usize = ZK_ROWS + 1;
19
20#[derive(Clone, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
36pub struct Ring<
37 F: PrimeField,
38 KzgCurve: Pairing<ScalarField = F>,
39 VrfCurveConfig: TECurveConfig<BaseField = F>,
40> {
41 pub cx: KzgCurve::G1Affine,
43 pub cy: KzgCurve::G1Affine,
45 pub selector: KzgCurve::G1Affine,
47 pub max_keys: usize,
49 pub curr_keys: usize,
51 pub padding: Affine<VrfCurveConfig>,
53}
54
55impl<
56 F: PrimeField,
57 KzgCurve: Pairing<ScalarField = F>,
58 VrfCurveConfig: TECurveConfig<BaseField = F>,
59 > fmt::Debug for Ring<F, KzgCurve, VrfCurveConfig>
60{
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 write!(
63 f,
64 "Ring(curr_keys={}, max_keys{})",
65 self.curr_keys, self.max_keys
66 )
67 }
68}
69
70impl<
71 F: PrimeField,
72 KzgCurve: Pairing<ScalarField = F>,
73 VrfCurveConfig: TECurveConfig<BaseField = F>,
74 > Ring<F, KzgCurve, VrfCurveConfig>
75{
76 pub fn empty(
88 piop_params: &PiopParams<F, VrfCurveConfig>,
89 srs: impl Fn(Range<usize>) -> Result<Vec<KzgCurve::G1Affine>, ()>,
90 g: KzgCurve::G1,
91 ) -> Self {
92 let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); let c1x = g * padding_x;
94 let c1y = g * padding_y;
95
96 let powers_of_h = piop_params.power_of_2_multiples_of_h();
97 let (mut xs, mut ys): (Vec<F>, Vec<F>) = powers_of_h
98 .iter()
99 .map(|p| p.xy().unwrap())
100 .map(|(x, y)| (x - padding_x, y - padding_y))
101 .unzip();
102 xs.resize(xs.len() + IDLE_ROWS, -padding_x);
103 ys.resize(ys.len() + IDLE_ROWS, -padding_y);
104 let domain_size = piop_params.domain.domain().size();
105 let srs_segment = &srs(piop_params.keyset_part_size..domain_size).unwrap();
106 let c2x = KzgCurve::G1::msm(srs_segment, &xs).unwrap();
107 let c2y = KzgCurve::G1::msm(srs_segment, &ys).unwrap();
108
109 let selector_inv = srs_segment.iter().sum::<KzgCurve::G1>();
110 let selector = g - selector_inv;
111
112 let (cx, cy, selector) = {
113 let affine = KzgCurve::G1::normalize_batch(&[c1x + c2x, c1y + c2y, selector]);
114 (affine[0], affine[1], affine[2])
115 };
116
117 Self {
118 cx,
119 cy,
120 selector,
121 max_keys: piop_params.keyset_part_size,
122 curr_keys: 0,
123 padding: piop_params.padding,
124 }
125 }
126
127 pub fn append(
132 &mut self,
133 keys: &[Affine<VrfCurveConfig>],
134 srs: impl Fn(Range<usize>) -> Result<Vec<KzgCurve::G1Affine>, ()>,
135 ) {
136 let new_size = self.curr_keys + keys.len();
137 assert!(new_size <= self.max_keys);
138 let (padding_x, padding_y) = self.padding.xy().unwrap();
139 let (xs, ys): (Vec<F>, Vec<F>) = keys
140 .iter()
141 .map(|p| p.xy().unwrap())
142 .map(|(x, y)| (x - padding_x, y - padding_y))
143 .unzip();
144 let srs_segment = &srs(self.curr_keys..self.curr_keys + keys.len()).unwrap();
145 let cx_delta = KzgCurve::G1::msm(srs_segment, &xs).unwrap();
146 let cy_delta = KzgCurve::G1::msm(srs_segment, &ys).unwrap();
147
148 let (new_cx, new_cy) = {
149 let affine = KzgCurve::G1::normalize_batch(&[self.cx + cx_delta, self.cy + cy_delta]);
150 (affine[0], affine[1])
151 };
152
153 self.cx = new_cx;
154 self.cy = new_cy;
155 self.curr_keys = new_size;
156 }
157
158 pub fn with_keys(
165 piop_params: &PiopParams<F, VrfCurveConfig>,
166 keys: &[Affine<VrfCurveConfig>],
167 srs: &RingBuilderKey<F, KzgCurve>,
168 ) -> Self {
169 let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); let powers_of_h = piop_params.power_of_2_multiples_of_h();
171
172 let (xs, ys): (Vec<F>, Vec<F>) = keys
178 .iter()
179 .chain(&powers_of_h)
180 .map(|p| p.xy().unwrap())
181 .map(|(x, y)| (x - padding_x, y - padding_y))
182 .chain(iter::repeat((-padding_x, -padding_y)).take(4))
183 .chain(iter::once((padding_x, padding_y)))
184 .unzip();
185
186 let bases = [
188 &srs.lis_in_g1[..keys.len()],
189 &srs.lis_in_g1[piop_params.keyset_part_size..],
190 &[srs.g1.into()],
191 ]
192 .concat();
193
194 let cx = KzgCurve::G1::msm(&bases, &xs).unwrap();
195 let cy = KzgCurve::G1::msm(&bases, &ys).unwrap();
196 let selector_inv = srs.lis_in_g1[piop_params.keyset_part_size..]
197 .iter()
198 .sum::<KzgCurve::G1>();
199 let selector = srs.g1 - selector_inv;
200
201 let (cx, cy, selector) = {
202 let affine = KzgCurve::G1::normalize_batch(&[cx, cy, selector]);
203 (affine[0], affine[1], affine[2])
204 };
205
206 Self {
207 cx,
208 cy,
209 selector,
210 max_keys: piop_params.keyset_part_size,
211 curr_keys: keys.len(),
212 padding: piop_params.padding,
213 }
214 }
215
216 pub fn slots_left(&self) -> usize {
217 self.max_keys - self.curr_keys
218 }
219
220 pub const fn empty_unchecked(
221 domain_size: usize,
222 cx: KzgCurve::G1Affine,
223 cy: KzgCurve::G1Affine,
224 selector: KzgCurve::G1Affine,
225 padding: Affine<VrfCurveConfig>,
226 ) -> Self {
227 let max_keys =
228 domain_size - (VrfCurveConfig::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS);
229 Self {
230 cx,
231 cy,
232 selector,
233 max_keys,
234 curr_keys: 0,
235 padding,
236 }
237 }
238}
239
240#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
241pub struct RingBuilderKey<F: PrimeField, KzgCurve: Pairing<ScalarField = F>> {
242 pub lis_in_g1: Vec<KzgCurve::G1Affine>,
244 pub g1: KzgCurve::G1,
246}
247
248impl<F: PrimeField, KzgCurve: Pairing<ScalarField = F>> RingBuilderKey<F, KzgCurve> {
249 pub fn from_srs(srs: &URS<KzgCurve>, domain_size: usize) -> Self {
250 let g1 = srs.powers_in_g1[0].into_group();
251 let ck = srs.ck_with_lagrangian(domain_size);
252 let lis_in_g1 = ck.lagrangian.unwrap().lis_in_g;
253 Self { lis_in_g1, g1 }
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use ark_bls12_381::{Bls12_381, Fr, G1Affine};
260 use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine};
261 use ark_std::{test_rng, UniformRand};
262 use w3f_pcs::pcs::kzg::urs::URS;
263 use w3f_pcs::pcs::kzg::KZG;
264 use w3f_pcs::pcs::PCS;
265
266 use w3f_plonk_common::domain::Domain;
267 use w3f_plonk_common::test_helpers::random_vec;
268
269 use crate::ring::Ring;
270 use crate::PiopParams;
271
272 use super::*;
273
274 type TestRing = Ring<Fr, Bls12_381, BandersnatchConfig>;
275
276 #[test]
277 fn test_ring_mgmt() {
278 let rng = &mut test_rng();
279
280 let domain_size = 1 << 9;
281
282 let pcs_params = KZG::<Bls12_381>::setup(domain_size - 1, rng);
283 let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size);
284 let srs = |range: Range<usize>| Ok(ring_builder_key.lis_in_g1[range].to_vec());
285
286 let h = EdwardsAffine::rand(rng);
288 let seed = EdwardsAffine::rand(rng);
289 let padding = EdwardsAffine::rand(rng);
290 let domain = Domain::new(domain_size, true);
291 let piop_params = PiopParams::setup(domain, h, seed, padding);
292
293 let mut ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1);
294 let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &[]);
295 assert_eq!(ring.cx, monimial_cx);
296 assert_eq!(ring.cy, monimial_cy);
297
298 let keys = random_vec::<EdwardsAffine, _>(ring.max_keys, rng);
299 ring.append(&keys, srs);
300 let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &keys);
301 assert_eq!(ring.cx, monimial_cx);
302 assert_eq!(ring.cy, monimial_cy);
303
304 let same_ring = TestRing::with_keys(&piop_params, &keys, &ring_builder_key);
305 assert_eq!(ring, same_ring);
306 }
307
308 #[test]
309 fn test_empty_rings() {
310 let rng = &mut test_rng();
311
312 let domain_size = 1 << 9;
313
314 let pcs_params = KZG::<Bls12_381>::setup(domain_size - 1, rng);
315 let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size);
316 let srs = |range: Range<usize>| Ok(ring_builder_key.lis_in_g1[range].to_vec());
317
318 let h = EdwardsAffine::rand(rng);
320 let seed = EdwardsAffine::rand(rng);
321 let padding = EdwardsAffine::rand(rng);
322 let domain = Domain::new(domain_size, true);
323 let piop_params = PiopParams::setup(domain, h, seed, padding);
324
325 let ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1);
326 let same_ring = TestRing::with_keys(&piop_params, &[], &ring_builder_key);
327 assert_eq!(ring, same_ring);
328 }
329
330 fn get_monomial_commitment(
331 pcs_params: &URS<Bls12_381>,
332 piop_params: &PiopParams<Fr, BandersnatchConfig>,
333 keys: &[EdwardsAffine],
334 ) -> (G1Affine, G1Affine) {
335 let (_, verifier_key) =
336 crate::piop::index::<_, KZG<Bls12_381>, _>(pcs_params, piop_params, keys);
337 let [monimial_cx, monimial_cy] = verifier_key.fixed_columns_committed.points;
338 (monimial_cx.0, monimial_cy.0)
339 }
340}