use std::sync::Arc;
use crate::aggregator::Aggregator;
use crate::error::ConfigError;
use crate::traits::PairingEngine;
#[derive(Debug, Clone)]
pub struct Srs<E: PairingEngine> {
pub powers_of_tau_g1: Vec<E::G1Affine>,
pub tau_g2: E::G2Affine,
pub g2_generator: E::G2Affine,
k: u32,
}
impl<E: PairingEngine> Srs<E> {
pub fn from_ceremony(
powers_g1: Vec<E::G1Affine>,
tau_g2: E::G2Affine,
g2_gen: E::G2Affine,
) -> Self {
let k = (powers_g1.len() as f64).log2().ceil() as u32;
Self {
powers_of_tau_g1: powers_g1,
tau_g2,
g2_generator: g2_gen,
k,
}
}
#[cfg(any(test, test))]
pub fn mock(k: u32) -> Self {
use ff::Field;
use group::{Curve, Group};
let n = 1usize << k;
let tau = E::Fr::from(0x1234567890abcdef_u64);
let mut powers_g1 = Vec::with_capacity(n);
let mut tau_power = E::Fr::ONE;
for _ in 0..n {
let point = E::G1::generator() * tau_power;
powers_g1.push(point.to_affine());
tau_power *= tau;
}
let tau_g2 = (E::G1::generator() * tau).to_affine();
Self {
powers_of_tau_g1: powers_g1,
tau_g2: Self::mock_g2_point(tau),
g2_generator: Self::mock_g2_generator(),
k,
}
}
#[cfg(any(test, test))]
fn mock_g2_point(_scalar: E::Fr) -> E::G2Affine {
use std::any::{Any, TypeId};
if TypeId::of::<E>() == TypeId::of::<crate::backend::bn254::Bn254>() {
use group::{Curve, Group};
use halo2curves::bn256::G2;
let point = G2::generator().to_affine();
let point_any: &dyn Any = &point;
if let Some(casted) = point_any.downcast_ref::<E::G2Affine>() {
return casted.clone();
}
panic!("Type match failed despite TypeId check");
} else {
panic!("SRS mock only supports Bn254")
}
}
#[cfg(any(test, test))]
fn mock_g2_generator() -> E::G2Affine {
use std::any::TypeId;
if TypeId::of::<E>() == TypeId::of::<crate::backend::bn254::Bn254>() {
use group::{Curve, Group};
use halo2curves::bn256::G2;
let point = G2::generator().to_affine();
unsafe { std::mem::transmute_copy(&point) }
} else {
panic!("SRS mock only supports Bn254")
}
}
pub fn k(&self) -> u32 {
self.k
}
pub fn max_degree(&self) -> usize {
self.powers_of_tau_g1.len() - 1
}
}
#[derive(Debug)]
pub struct AggregatorBuilder<E: PairingEngine> {
srs: Option<Arc<Srs<E>>>,
max_batch_size: Option<usize>,
parallel: bool,
}
impl<E: PairingEngine> Default for AggregatorBuilder<E> {
fn default() -> Self {
Self::new()
}
}
impl<E: PairingEngine> AggregatorBuilder<E> {
pub fn new() -> Self {
Self {
srs: None,
max_batch_size: None,
parallel: false,
}
}
pub fn with_srs(mut self, srs: Arc<Srs<E>>) -> Self {
self.srs = Some(srs);
self
}
pub fn max_batch_size(mut self, size: usize) -> Self {
self.max_batch_size = Some(size);
self
}
pub fn enable_parallelism(mut self) -> Self {
self.parallel = true;
self
}
pub fn build(self) -> Result<Aggregator<E>, ConfigError> {
let srs = self.srs.ok_or(ConfigError::MissingSrs)?;
let max_batch_size = self.max_batch_size.unwrap_or(32);
if max_batch_size == 0 {
return Err(ConfigError::InvalidBatchSize(0));
}
Ok(Aggregator::new(srs, max_batch_size, self.parallel))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::bn254::Bn254;
#[test]
fn builder_requires_srs() {
let result = AggregatorBuilder::<Bn254>::new().build();
assert!(matches!(result, Err(ConfigError::MissingSrs)));
}
#[test]
fn builder_rejects_zero_batch_size() {
let srs = Arc::new(Srs::<Bn254>::mock(10));
let result = AggregatorBuilder::<Bn254>::new().with_srs(srs).max_batch_size(0).build();
assert!(matches!(result, Err(ConfigError::InvalidBatchSize(0))));
}
#[test]
fn builder_defaults_batch_size() {
let srs = Arc::new(Srs::<Bn254>::mock(10));
let aggregator = AggregatorBuilder::<Bn254>::new().with_srs(srs).build().unwrap();
assert_eq!(aggregator.max_batch_size(), 32);
}
#[test]
fn builder_fluent_api() {
let srs = Arc::new(Srs::<Bn254>::mock(10));
let aggregator = AggregatorBuilder::<Bn254>::new()
.with_srs(srs)
.max_batch_size(64)
.enable_parallelism()
.build()
.unwrap();
assert_eq!(aggregator.max_batch_size(), 64);
}
}