use ark_ec::pairing::Pairing;
use ark_ec::twisted_edwards::{Affine, TECurveConfig};
use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
use ark_ff::PrimeField;
use ark_poly::EvaluationDomain;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::fmt;
use ark_std::iter;
use ark_std::ops::Range;
use ark_std::vec::Vec;
use w3f_pcs::pcs::kzg::urs::URS;
use w3f_pcs::pcs::PcsParams;
use w3f_plonk_common::domain::ZK_ROWS;
use crate::PiopParams;
const IDLE_ROWS: usize = ZK_ROWS + 1;
#[derive(Clone, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Ring<
F: PrimeField,
KzgCurve: Pairing<ScalarField = F>,
VrfCurveConfig: TECurveConfig<BaseField = F>,
> {
pub cx: KzgCurve::G1Affine,
pub cy: KzgCurve::G1Affine,
pub selector: KzgCurve::G1Affine,
pub max_keys: usize,
pub curr_keys: usize,
pub padding: Affine<VrfCurveConfig>,
}
impl<
F: PrimeField,
KzgCurve: Pairing<ScalarField = F>,
VrfCurveConfig: TECurveConfig<BaseField = F>,
> fmt::Debug for Ring<F, KzgCurve, VrfCurveConfig>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Ring(curr_keys={}, max_keys{})",
self.curr_keys, self.max_keys
)
}
}
impl<
F: PrimeField,
KzgCurve: Pairing<ScalarField = F>,
VrfCurveConfig: TECurveConfig<BaseField = F>,
> Ring<F, KzgCurve, VrfCurveConfig>
{
pub fn empty(
piop_params: &PiopParams<F, VrfCurveConfig>,
srs: impl Fn(Range<usize>) -> Result<Vec<KzgCurve::G1Affine>, ()>,
g: KzgCurve::G1,
) -> Self {
let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); let c1x = g * padding_x;
let c1y = g * padding_y;
let powers_of_h = piop_params.power_of_2_multiples_of_h();
let (mut xs, mut ys): (Vec<F>, Vec<F>) = powers_of_h
.iter()
.map(|p| p.xy().unwrap())
.map(|(x, y)| (x - padding_x, y - padding_y))
.unzip();
xs.resize(xs.len() + IDLE_ROWS, -padding_x);
ys.resize(ys.len() + IDLE_ROWS, -padding_y);
let domain_size = piop_params.domain.domain().size();
let srs_segment = &srs(piop_params.keyset_part_size..domain_size).unwrap();
let c2x = KzgCurve::G1::msm(srs_segment, &xs).unwrap();
let c2y = KzgCurve::G1::msm(srs_segment, &ys).unwrap();
let selector_inv = srs_segment.iter().sum::<KzgCurve::G1>();
let selector = g - selector_inv;
let (cx, cy, selector) = {
let affine = KzgCurve::G1::normalize_batch(&[c1x + c2x, c1y + c2y, selector]);
(affine[0], affine[1], affine[2])
};
Self {
cx,
cy,
selector,
max_keys: piop_params.keyset_part_size,
curr_keys: 0,
padding: piop_params.padding,
}
}
pub fn append(
&mut self,
keys: &[Affine<VrfCurveConfig>],
srs: impl Fn(Range<usize>) -> Result<Vec<KzgCurve::G1Affine>, ()>,
) {
let new_size = self.curr_keys + keys.len();
assert!(new_size <= self.max_keys);
let (padding_x, padding_y) = self.padding.xy().unwrap();
let (xs, ys): (Vec<F>, Vec<F>) = keys
.iter()
.map(|p| p.xy().unwrap())
.map(|(x, y)| (x - padding_x, y - padding_y))
.unzip();
let srs_segment = &srs(self.curr_keys..self.curr_keys + keys.len()).unwrap();
let cx_delta = KzgCurve::G1::msm(srs_segment, &xs).unwrap();
let cy_delta = KzgCurve::G1::msm(srs_segment, &ys).unwrap();
let (new_cx, new_cy) = {
let affine = KzgCurve::G1::normalize_batch(&[self.cx + cx_delta, self.cy + cy_delta]);
(affine[0], affine[1])
};
self.cx = new_cx;
self.cy = new_cy;
self.curr_keys = new_size;
}
pub fn with_keys(
piop_params: &PiopParams<F, VrfCurveConfig>,
keys: &[Affine<VrfCurveConfig>],
srs: &RingBuilderKey<F, KzgCurve>,
) -> Self {
let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); let powers_of_h = piop_params.power_of_2_multiples_of_h();
let (xs, ys): (Vec<F>, Vec<F>) = keys
.iter()
.chain(&powers_of_h)
.map(|p| p.xy().unwrap())
.map(|(x, y)| (x - padding_x, y - padding_y))
.chain(iter::repeat((-padding_x, -padding_y)).take(4))
.chain(iter::once((padding_x, padding_y)))
.unzip();
let bases = [
&srs.lis_in_g1[..keys.len()],
&srs.lis_in_g1[piop_params.keyset_part_size..],
&[srs.g1.into()],
]
.concat();
let cx = KzgCurve::G1::msm(&bases, &xs).unwrap();
let cy = KzgCurve::G1::msm(&bases, &ys).unwrap();
let selector_inv = srs.lis_in_g1[piop_params.keyset_part_size..]
.iter()
.sum::<KzgCurve::G1>();
let selector = srs.g1 - selector_inv;
let (cx, cy, selector) = {
let affine = KzgCurve::G1::normalize_batch(&[cx, cy, selector]);
(affine[0], affine[1], affine[2])
};
Self {
cx,
cy,
selector,
max_keys: piop_params.keyset_part_size,
curr_keys: keys.len(),
padding: piop_params.padding,
}
}
pub fn slots_left(&self) -> usize {
self.max_keys - self.curr_keys
}
pub const fn empty_unchecked(
domain_size: usize,
cx: KzgCurve::G1Affine,
cy: KzgCurve::G1Affine,
selector: KzgCurve::G1Affine,
padding: Affine<VrfCurveConfig>,
) -> Self {
let max_keys =
domain_size - (VrfCurveConfig::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS);
Self {
cx,
cy,
selector,
max_keys,
curr_keys: 0,
padding,
}
}
}
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct RingBuilderKey<F: PrimeField, KzgCurve: Pairing<ScalarField = F>> {
pub lis_in_g1: Vec<KzgCurve::G1Affine>,
pub g1: KzgCurve::G1,
}
impl<F: PrimeField, KzgCurve: Pairing<ScalarField = F>> RingBuilderKey<F, KzgCurve> {
pub fn from_srs(srs: &URS<KzgCurve>, domain_size: usize) -> Self {
let g1 = srs.powers_in_g1[0].into_group();
let ck = srs.ck_with_lagrangian(domain_size);
let lis_in_g1 = ck.lagrangian.unwrap().lis_in_g;
Self { lis_in_g1, g1 }
}
}
#[cfg(test)]
mod tests {
use ark_bls12_381::{Bls12_381, Fr, G1Affine};
use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, EdwardsAffine};
use ark_std::{test_rng, UniformRand};
use w3f_pcs::pcs::kzg::urs::URS;
use w3f_pcs::pcs::kzg::KZG;
use w3f_pcs::pcs::PCS;
use w3f_plonk_common::domain::Domain;
use w3f_plonk_common::test_helpers::random_vec;
use crate::ring::Ring;
use crate::PiopParams;
use super::*;
type TestRing = Ring<Fr, Bls12_381, BandersnatchConfig>;
#[test]
fn test_ring_mgmt() {
let rng = &mut test_rng();
let domain_size = 1 << 9;
let pcs_params = KZG::<Bls12_381>::setup(domain_size - 1, rng);
let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size);
let srs = |range: Range<usize>| Ok(ring_builder_key.lis_in_g1[range].to_vec());
let h = EdwardsAffine::rand(rng);
let seed = EdwardsAffine::rand(rng);
let padding = EdwardsAffine::rand(rng);
let domain = Domain::new(domain_size, true);
let piop_params = PiopParams::setup(domain, h, seed, padding);
let mut ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1);
let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &[]);
assert_eq!(ring.cx, monimial_cx);
assert_eq!(ring.cy, monimial_cy);
let keys = random_vec::<EdwardsAffine, _>(ring.max_keys, rng);
ring.append(&keys, srs);
let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &keys);
assert_eq!(ring.cx, monimial_cx);
assert_eq!(ring.cy, monimial_cy);
let same_ring = TestRing::with_keys(&piop_params, &keys, &ring_builder_key);
assert_eq!(ring, same_ring);
}
#[test]
fn test_empty_rings() {
let rng = &mut test_rng();
let domain_size = 1 << 9;
let pcs_params = KZG::<Bls12_381>::setup(domain_size - 1, rng);
let ring_builder_key = RingBuilderKey::from_srs(&pcs_params, domain_size);
let srs = |range: Range<usize>| Ok(ring_builder_key.lis_in_g1[range].to_vec());
let h = EdwardsAffine::rand(rng);
let seed = EdwardsAffine::rand(rng);
let padding = EdwardsAffine::rand(rng);
let domain = Domain::new(domain_size, true);
let piop_params = PiopParams::setup(domain, h, seed, padding);
let ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1);
let same_ring = TestRing::with_keys(&piop_params, &[], &ring_builder_key);
assert_eq!(ring, same_ring);
}
fn get_monomial_commitment(
pcs_params: &URS<Bls12_381>,
piop_params: &PiopParams<Fr, BandersnatchConfig>,
keys: &[EdwardsAffine],
) -> (G1Affine, G1Affine) {
let (_, verifier_key) =
crate::piop::index::<_, KZG<Bls12_381>, _>(pcs_params, piop_params, keys);
let [monimial_cx, monimial_cy] = verifier_key.fixed_columns_committed.points;
(monimial_cx.0, monimial_cy.0)
}
}