use group::{prime::PrimeCurveAffine, UncompressedEncoding};
use pairing::MultiMillerLoop;
use crate::SynthesisError;
#[cfg(not(target_arch = "wasm32"))]
use memmap2::Mmap;
use rayon::prelude::*;
use std::fs::File;
use std::io;
use std::ops::Range;
use std::path::PathBuf;
use std::sync::Arc;
use super::{ParameterSource, PreparedVerifyingKey, VerifyingKey};
pub struct MappedParameters<E>
where
E: MultiMillerLoop,
{
pub param_file_path: PathBuf,
pub param_file: File,
pub params: Mmap,
pub vk: VerifyingKey<E>,
pub pvk: PreparedVerifyingKey<E>,
pub h: Vec<Range<usize>>,
pub l: Vec<Range<usize>>,
pub a: Vec<Range<usize>>,
pub b_g1: Vec<Range<usize>>,
pub b_g2: Vec<Range<usize>>,
pub checked: bool,
}
impl<'a, E> ParameterSource<E> for &'a MappedParameters<E>
where
E: MultiMillerLoop,
{
type G1Builder = (Arc<Vec<E::G1Affine>>, usize);
type G2Builder = (Arc<Vec<E::G2Affine>>, usize);
fn get_vk(&self, _: usize) -> Result<&VerifyingKey<E>, SynthesisError> {
Ok(&self.vk)
}
fn get_h(&self, _num_h: usize) -> Result<Self::G1Builder, SynthesisError> {
let builder = self
.h
.par_iter()
.cloned()
.map(|h| read_g1::<E>(&self.params, h, self.checked))
.collect::<Result<_, _>>()?;
Ok((Arc::new(builder), 0))
}
fn get_l(&self, _num_l: usize) -> Result<Self::G1Builder, SynthesisError> {
let builder = self
.l
.par_iter()
.cloned()
.map(|l| read_g1::<E>(&self.params, l, self.checked))
.collect::<Result<_, _>>()?;
Ok((Arc::new(builder), 0))
}
fn get_a(
&self,
num_inputs: usize,
_num_a: usize,
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
let builder = self
.a
.par_iter()
.cloned()
.map(|a| read_g1::<E>(&self.params, a, self.checked))
.collect::<Result<_, _>>()?;
let builder: Arc<Vec<_>> = Arc::new(builder);
Ok(((builder.clone(), 0), (builder, num_inputs)))
}
fn get_b_g1(
&self,
num_inputs: usize,
_num_b_g1: usize,
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
let builder = self
.b_g1
.par_iter()
.cloned()
.map(|b_g1| read_g1::<E>(&self.params, b_g1, self.checked))
.collect::<Result<_, _>>()?;
let builder: Arc<Vec<_>> = Arc::new(builder);
Ok(((builder.clone(), 0), (builder, num_inputs)))
}
fn get_b_g2(
&self,
num_inputs: usize,
_num_b_g2: usize,
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> {
let builder = self
.b_g2
.par_iter()
.cloned()
.map(|b_g2| read_g2::<E>(&self.params, b_g2, self.checked))
.collect::<Result<_, _>>()?;
let builder: Arc<Vec<_>> = Arc::new(builder);
Ok(((builder.clone(), 0), (builder, num_inputs)))
}
}
pub fn read_g1<E: MultiMillerLoop>(
mmap: &Mmap,
range: Range<usize>,
checked: bool,
) -> Result<E::G1Affine, std::io::Error> {
let ptr = &mmap[range];
let repr = unsafe {
&*(ptr as *const [u8] as *const <E::G1Affine as UncompressedEncoding>::Uncompressed)
};
let affine: E::G1Affine = {
let affine_opt = if checked {
E::G1Affine::from_uncompressed(repr)
} else {
E::G1Affine::from_uncompressed_unchecked(repr)
};
Option::from(affine_opt)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "not on curve"))
}?;
if affine.is_identity().into() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
} else {
Ok(affine)
}
}
pub fn read_g2<E: MultiMillerLoop>(
mmap: &Mmap,
range: Range<usize>,
checked: bool,
) -> Result<E::G2Affine, std::io::Error> {
let ptr = &mmap[range];
let repr = unsafe {
&*(ptr as *const [u8] as *const <E::G2Affine as UncompressedEncoding>::Uncompressed)
};
let affine: E::G2Affine = {
let affine_opt = if checked {
E::G2Affine::from_uncompressed(repr)
} else {
E::G2Affine::from_uncompressed_unchecked(repr)
};
Option::from(affine_opt)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "not on curve"))
}?;
if affine.is_identity().into() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
} else {
Ok(affine)
}
}