use super::key::{CommitKey, OpeningKey};
use crate::{error::Error, util};
use dusk_bls12_381::{G1Affine, G1Projective, G2Affine};
use dusk_bytes::{DeserializableSlice, Serializable};
use rand_core::{CryptoRng, RngCore};
#[derive(Debug, Clone)]
pub struct PublicParameters {
pub(crate) commit_key: CommitKey,
pub(crate) opening_key: OpeningKey,
}
impl PublicParameters {
pub fn setup<R: RngCore + CryptoRng>(
max_degree: usize,
mut rng: &mut R,
) -> Result<PublicParameters, Error> {
if max_degree < 1 {
return Err(Error::DegreeIsZero);
}
let beta = util::random_scalar(&mut rng);
let powers_of_beta = util::powers_of(&beta, max_degree);
let g = util::random_g1_point(&mut rng);
let powers_of_g: Vec<G1Projective> =
util::slow_multiscalar_mul_single_base(&powers_of_beta, g);
assert_eq!(powers_of_g.len(), max_degree + 1);
let mut normalised_g = vec![G1Affine::identity(); max_degree + 1];
G1Projective::batch_normalize(&powers_of_g, &mut normalised_g);
let h: G2Affine = util::random_g2_point(&mut rng).into();
let beta_h: G2Affine = (h * beta).into();
Ok(PublicParameters {
commit_key: CommitKey {
powers_of_g: normalised_g,
},
opening_key: OpeningKey::new(g.into(), h, beta_h),
})
}
pub fn to_raw_var_bytes(&self) -> Vec<u8> {
let mut bytes = self.opening_key.to_bytes().to_vec();
bytes.extend(&self.commit_key.to_raw_var_bytes());
bytes
}
pub unsafe fn from_slice_unchecked(bytes: &[u8]) -> Self {
let opening_key = &bytes[..OpeningKey::SIZE];
let opening_key = OpeningKey::from_slice(opening_key)
.expect("Error at OpeningKey deserialization");
let commit_key = &bytes[OpeningKey::SIZE..];
let commit_key = CommitKey::from_slice_unchecked(commit_key);
Self {
commit_key,
opening_key,
}
}
pub fn to_var_bytes(&self) -> Vec<u8> {
let mut bytes = self.opening_key.to_bytes().to_vec();
bytes.extend(self.commit_key.to_var_bytes().iter());
bytes
}
pub fn from_slice(bytes: &[u8]) -> Result<PublicParameters, Error> {
if bytes.len() <= OpeningKey::SIZE {
return Err(Error::NotEnoughBytes);
}
let mut buf = &bytes[..];
let opening_key = OpeningKey::from_reader(&mut buf)?;
let commit_key = CommitKey::from_slice(&buf)?;
let pp = PublicParameters {
opening_key,
commit_key,
};
Ok(pp)
}
pub(crate) fn trim(
&self,
truncated_degree: usize,
) -> Result<(CommitKey, OpeningKey), Error> {
let truncated_prover_key =
self.commit_key.truncate(truncated_degree)?;
let opening_key = self.opening_key.clone();
Ok((truncated_prover_key, opening_key))
}
pub fn max_degree(&self) -> usize {
self.commit_key.max_degree()
}
}
#[cfg(test)]
mod test {
use super::*;
use dusk_bls12_381::BlsScalar;
#[test]
fn test_powers_of() {
let x = BlsScalar::from(10u64);
let degree = 100u64;
let powers_of_x = util::powers_of(&x, degree as usize);
for (i, x_i) in powers_of_x.iter().enumerate() {
assert_eq!(*x_i, x.pow(&[i as u64, 0, 0, 0]))
}
let last_element = powers_of_x.last().unwrap();
assert_eq!(*last_element, x.pow(&[degree, 0, 0, 0]))
}
#[test]
fn test_serialise_deserialise_public_parameter() {
let pp =
PublicParameters::setup(1 << 7, &mut rand::thread_rng()).unwrap();
let got_pp = PublicParameters::from_slice(&pp.to_var_bytes()).unwrap();
assert_eq!(got_pp.commit_key.powers_of_g, pp.commit_key.powers_of_g);
assert_eq!(got_pp.opening_key.g, pp.opening_key.g);
assert_eq!(got_pp.opening_key.h, pp.opening_key.h);
assert_eq!(got_pp.opening_key.beta_h, pp.opening_key.beta_h);
}
#[test]
fn public_parameters_bytes_unchecked() {
let pp =
PublicParameters::setup(1 << 7, &mut rand::thread_rng()).unwrap();
let pp_p = unsafe {
let bytes = pp.to_raw_var_bytes();
PublicParameters::from_slice_unchecked(&bytes)
};
assert_eq!(pp.commit_key, pp_p.commit_key);
assert_eq!(pp.opening_key.g, pp_p.opening_key.g);
assert_eq!(pp.opening_key.h, pp_p.opening_key.h);
assert_eq!(pp.opening_key.beta_h, pp_p.opening_key.beta_h);
}
}