use bellman_ce::pairing::{CurveAffine, CurveProjective, EncodedPoint, Engine};
use blake2::{Blake2b, Digest};
use memmap::{Mmap, MmapMut};
use rand::{Rand, Rng};
use std::io::{self, Read, Write};
use typenum::consts::U64;
use super::parameters::{CeremonyParams, DeserializationError, UseCompression};
use super::utils::{hash_to_g2, write_point};
#[derive(Eq)]
pub struct PublicKey<E: Engine> {
pub tau_g1: (E::G1Affine, E::G1Affine),
pub alpha_g1: (E::G1Affine, E::G1Affine),
pub beta_g1: (E::G1Affine, E::G1Affine),
pub tau_g2: E::G2Affine,
pub alpha_g2: E::G2Affine,
pub beta_g2: E::G2Affine,
}
impl<E: Engine> PartialEq for PublicKey<E> {
fn eq(&self, other: &PublicKey<E>) -> bool {
self.tau_g1.0 == other.tau_g1.0
&& self.tau_g1.1 == other.tau_g1.1
&& self.alpha_g1.0 == other.alpha_g1.0
&& self.alpha_g1.1 == other.alpha_g1.1
&& self.beta_g1.0 == other.beta_g1.0
&& self.beta_g1.1 == other.beta_g1.1
&& self.tau_g2 == other.tau_g2
&& self.alpha_g2 == other.alpha_g2
&& self.beta_g2 == other.beta_g2
}
}
pub struct PrivateKey<E: Engine> {
pub tau: E::Fr,
pub alpha: E::Fr,
pub beta: E::Fr,
}
pub fn keypair<R: Rng, E: Engine>(rng: &mut R, digest: &[u8]) -> (PublicKey<E>, PrivateKey<E>) {
assert_eq!(digest.len(), 64);
let tau = E::Fr::rand(rng);
let alpha = E::Fr::rand(rng);
let beta = E::Fr::rand(rng);
let mut op = |x: E::Fr, personalization: u8| {
let g1_s = E::G1::rand(rng).into_affine();
let g1_s_x = g1_s.mul(x).into_affine();
let h: generic_array::GenericArray<u8, U64> = {
let mut h = Blake2b::default();
h.input(&[personalization]);
h.input(digest);
h.input(g1_s.into_uncompressed().as_ref());
h.input(g1_s_x.into_uncompressed().as_ref());
h.result()
};
let g2_s: E::G2Affine = hash_to_g2::<E>(h.as_ref()).into_affine();
let g2_s_x = g2_s.mul(x).into_affine();
((g1_s, g1_s_x), g2_s_x)
};
let pk_tau = op(tau, 0);
let pk_alpha = op(alpha, 1);
let pk_beta = op(beta, 2);
(
PublicKey {
tau_g1: pk_tau.0,
alpha_g1: pk_alpha.0,
beta_g1: pk_beta.0,
tau_g2: pk_tau.1,
alpha_g2: pk_alpha.1,
beta_g2: pk_beta.1,
},
PrivateKey { tau, alpha, beta },
)
}
impl<E: Engine> PublicKey<E> {
pub fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
write_point(writer, &self.tau_g1.0, UseCompression::No)?;
write_point(writer, &self.tau_g1.1, UseCompression::No)?;
write_point(writer, &self.alpha_g1.0, UseCompression::No)?;
write_point(writer, &self.alpha_g1.1, UseCompression::No)?;
write_point(writer, &self.beta_g1.0, UseCompression::No)?;
write_point(writer, &self.beta_g1.1, UseCompression::No)?;
write_point(writer, &self.tau_g2, UseCompression::No)?;
write_point(writer, &self.alpha_g2, UseCompression::No)?;
write_point(writer, &self.beta_g2, UseCompression::No)?;
Ok(())
}
pub fn deserialize<R: Read>(reader: &mut R) -> Result<PublicKey<E>, DeserializationError> {
fn read_uncompressed<EE: Engine, C: CurveAffine<Engine = EE, Scalar = EE::Fr>, R: Read>(
reader: &mut R,
) -> Result<C, DeserializationError> {
let mut repr = C::Uncompressed::empty();
reader.read_exact(repr.as_mut())?;
let v = repr.into_affine()?;
if v.is_zero() {
Err(DeserializationError::PointAtInfinity)
} else {
Ok(v)
}
}
let tau_g1_s = read_uncompressed::<E, _, _>(reader)?;
let tau_g1_s_tau = read_uncompressed::<E, _, _>(reader)?;
let alpha_g1_s = read_uncompressed::<E, _, _>(reader)?;
let alpha_g1_s_alpha = read_uncompressed::<E, _, _>(reader)?;
let beta_g1_s = read_uncompressed::<E, _, _>(reader)?;
let beta_g1_s_beta = read_uncompressed::<E, _, _>(reader)?;
let tau_g2 = read_uncompressed::<E, _, _>(reader)?;
let alpha_g2 = read_uncompressed::<E, _, _>(reader)?;
let beta_g2 = read_uncompressed::<E, _, _>(reader)?;
Ok(PublicKey {
tau_g1: (tau_g1_s, tau_g1_s_tau),
alpha_g1: (alpha_g1_s, alpha_g1_s_alpha),
beta_g1: (beta_g1_s, beta_g1_s_beta),
tau_g2,
alpha_g2,
beta_g2,
})
}
}
impl<E: Engine> PublicKey<E> {
pub fn write(
&self,
output_map: &mut MmapMut,
accumulator_was_compressed: UseCompression,
parameters: &CeremonyParams<E>,
) -> io::Result<()> {
let mut position = match accumulator_was_compressed {
UseCompression::Yes => parameters.contribution_size - parameters.public_key_size,
UseCompression::No => parameters.accumulator_size,
};
let g1_size = parameters.curve.g1;
let g2_size = parameters.curve.g2;
(&mut output_map[position..]).write_all(&self.tau_g1.0.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.tau_g1.1.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.alpha_g1.0.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.alpha_g1.1.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.beta_g1.0.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.beta_g1.1.into_uncompressed().as_ref())?;
position += g1_size;
(&mut output_map[position..]).write_all(&self.tau_g2.into_uncompressed().as_ref())?;
position += g2_size;
(&mut output_map[position..]).write_all(&self.alpha_g2.into_uncompressed().as_ref())?;
position += g2_size;
(&mut output_map[position..]).write_all(&self.beta_g2.into_uncompressed().as_ref())?;
output_map.flush()?;
Ok(())
}
pub fn read(
input_map: &Mmap,
accumulator_was_compressed: UseCompression,
parameters: &CeremonyParams<E>,
) -> Result<Self, DeserializationError> {
fn read_uncompressed<EE: Engine, C: CurveAffine<Engine = EE, Scalar = EE::Fr>>(
input_map: &Mmap,
position: usize,
) -> Result<C, DeserializationError> {
let mut repr = C::Uncompressed::empty();
let element_size = C::Uncompressed::size();
let mut memory_slice = input_map
.get(position..position + element_size)
.expect("must read point data from file");
memory_slice.read_exact(repr.as_mut())?;
let v = repr.into_affine()?;
if v.is_zero() {
Err(DeserializationError::PointAtInfinity)
} else {
Ok(v)
}
}
let mut position = match accumulator_was_compressed {
UseCompression::Yes => parameters.contribution_size - parameters.public_key_size,
UseCompression::No => parameters.accumulator_size,
};
let g1_size = parameters.curve.g1;
let g2_size = parameters.curve.g2;
let tau_g1_s = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let tau_g1_s_tau = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let alpha_g1_s = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let alpha_g1_s_alpha = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let beta_g1_s = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let beta_g1_s_beta = read_uncompressed::<E, _>(input_map, position)?;
position += g1_size;
let tau_g2 = read_uncompressed::<E, _>(input_map, position)?;
position += g2_size;
let alpha_g2 = read_uncompressed::<E, _>(input_map, position)?;
position += g2_size;
let beta_g2 = read_uncompressed::<E, _>(input_map, position)?;
Ok(PublicKey {
tau_g1: (tau_g1_s, tau_g1_s_tau),
alpha_g1: (alpha_g1_s, alpha_g1_s_alpha),
beta_g1: (beta_g1_s, beta_g1_s_beta),
tau_g2,
alpha_g2,
beta_g2,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{thread_rng, Rng};
mod bn256 {
use super::*;
use crate::parameters::CurveParams;
use bellman_ce::pairing::bn256::Bn256;
#[test]
fn test_pubkey_serialization() {
let curve = CurveParams::<Bn256>::new();
let public_key_size = 6 * curve.g1 + 3 * curve.g2;
let rng = &mut thread_rng();
let digest = (0..64).map(|_| rng.gen()).collect::<Vec<_>>();
let (pk, _) = keypair::<_, Bn256>(rng, &digest);
let mut v = vec![];
pk.serialize(&mut v).unwrap();
assert_eq!(v.len(), public_key_size);
let deserialized = PublicKey::<Bn256>::deserialize(&mut &v[..]).unwrap();
assert!(pk == deserialized);
}
}
}