use ark_ec::{
pairing::{Pairing, PairingOutput},
AffineRepr, CurveGroup, Group,
};
use ark_ff::{One, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{cfg_iter, rand::RngCore, vec::Vec, UniformRand};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use crate::{error::SaverError, saver_groth16, setup::EncryptionGens, utils::chunks_count};
use dock_crypto_utils::{msm::multiply_field_elems_with_same_group_elem, serde_utils::*};
#[serde_as]
#[derive(
Clone,
PartialEq,
Eq,
Debug,
CanonicalSerialize,
CanonicalDeserialize,
Serialize,
Deserialize,
Zeroize,
ZeroizeOnDrop,
)]
pub struct SecretKey<F: PrimeField>(#[serde_as(as = "ArkObjectBytes")] pub F);
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct EncryptionKey<E: Pairing> {
#[serde_as(as = "ArkObjectBytes")]
pub X_0: E::G1Affine,
#[serde_as(as = "Vec<ArkObjectBytes>")]
pub X: Vec<E::G1Affine>,
#[serde_as(as = "Vec<ArkObjectBytes>")]
pub Y: Vec<E::G1Affine>,
#[serde_as(as = "Vec<ArkObjectBytes>")]
pub Z: Vec<E::G2Affine>,
#[serde_as(as = "ArkObjectBytes")]
pub P_1: E::G1Affine,
#[serde_as(as = "ArkObjectBytes")]
pub P_2: E::G1Affine,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PreparedEncryptionKey<E: Pairing> {
pub X_0: E::G1Affine,
pub X: Vec<E::G1Affine>,
pub Y: Vec<E::G1Affine>,
pub Z: Vec<E::G2Prepared>,
pub P_1: E::G1Affine,
pub P_2: E::G1Affine,
}
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct DecryptionKey<E: Pairing> {
#[serde_as(as = "ArkObjectBytes")]
pub V_0: E::G2Affine,
#[serde_as(as = "Vec<ArkObjectBytes>")]
pub V_1: Vec<E::G2Affine>,
#[serde_as(as = "Vec<ArkObjectBytes>")]
pub V_2: Vec<E::G2Affine>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PreparedDecryptionKey<E: Pairing> {
pub V_0: E::G2Prepared,
pub V_1: Vec<E::G2Prepared>,
pub V_2: Vec<E::G2Prepared>,
}
macro_rules! impl_enc_key_funcs {
() => {
pub fn supported_chunks_count(&self) -> crate::Result<u8> {
let n = self.X.len();
if self.Y.len() != n {
return Err(SaverError::MalformedEncryptionKey(self.Y.len(), n));
}
if self.Z.len() != (n + 1) {
return Err(SaverError::MalformedEncryptionKey(self.Z.len(), n));
}
Ok(n as u8)
}
pub fn validate(&self) -> crate::Result<()> {
self.supported_chunks_count()?;
Ok(())
}
pub fn commitment_key(&self) -> Vec<E::G1Affine> {
let mut ck = self.Y.clone();
ck.push(self.P_1.clone());
ck
}
};
}
macro_rules! impl_dec_key_funcs {
() => {
pub fn supported_chunks_count(&self) -> crate::Result<u8> {
let n = self.V_1.len();
if self.V_2.len() != n {
return Err(SaverError::MalformedDecryptionKey(self.V_2.len(), n));
}
Ok(n as u8)
}
pub fn validate(&self) -> crate::Result<()> {
self.supported_chunks_count()?;
Ok(())
}
pub fn pairing_powers_given_groth16_vk(
&self,
chunk_bit_size: u8,
snark_vk: &ark_groth16::VerifyingKey<E>,
) -> crate::Result<Vec<Vec<PairingOutput<E>>>> {
let g_i = saver_groth16::get_gs_for_encryption(&snark_vk);
self.pairing_powers(chunk_bit_size, g_i)
}
};
}
impl<E: Pairing> EncryptionKey<E> {
impl_enc_key_funcs!();
}
impl<E: Pairing> From<EncryptionKey<E>> for PreparedEncryptionKey<E> {
fn from(ek: EncryptionKey<E>) -> Self {
Self {
X_0: ek.X_0,
X: ek.X,
Y: ek.Y,
Z: cfg_iter!(ek.Z)
.map(|z| E::G2Prepared::from(*z))
.collect::<Vec<_>>(),
P_1: ek.P_1,
P_2: ek.P_2,
}
}
}
impl<E: Pairing> From<DecryptionKey<E>> for PreparedDecryptionKey<E> {
fn from(dk: DecryptionKey<E>) -> Self {
Self {
V_0: E::G2Prepared::from(dk.V_0),
V_1: cfg_iter!(dk.V_1)
.map(|v| E::G2Prepared::from(*v))
.collect::<Vec<_>>(),
V_2: cfg_iter!(dk.V_2)
.map(|v| E::G2Prepared::from(*v))
.collect::<Vec<_>>(),
}
}
}
impl<E: Pairing> PreparedEncryptionKey<E> {
impl_enc_key_funcs!();
}
impl<E: Pairing> DecryptionKey<E> {
impl_dec_key_funcs!();
pub fn pairing_powers(
&self,
chunk_bit_size: u8,
g_i: &[E::G1Affine],
) -> crate::Result<Vec<Vec<PairingOutput<E>>>> {
let prepared_dk = PreparedDecryptionKey::from(self.clone());
prepared_dk.pairing_powers(chunk_bit_size, g_i)
}
}
impl<E: Pairing> PreparedDecryptionKey<E> {
impl_dec_key_funcs!();
pub fn pairing_powers(
&self,
chunk_bit_size: u8,
g_i: &[E::G1Affine],
) -> crate::Result<Vec<Vec<PairingOutput<E>>>> {
let n = self.supported_chunks_count()? as usize;
let chunk_max_val = (1 << chunk_bit_size) - 1;
let mut powers = Vec::<Vec<PairingOutput<E>>>::with_capacity(n);
for i in 0..n {
let g_i_v_i = E::pairing(g_i[i], self.V_2[i].clone());
let mut powers_i = Vec::<PairingOutput<E>>::with_capacity(chunk_max_val as usize);
let mut cur = g_i_v_i;
powers_i.push(cur);
for _ in 1..chunk_max_val {
cur += g_i_v_i;
powers_i.push(cur);
}
powers.push(powers_i);
}
Ok(powers)
}
}
pub fn keygen<R: RngCore, E: Pairing>(
rng: &mut R,
chunk_bit_size: u8,
gens: &EncryptionGens<E>,
g_i: &[E::G1Affine],
delta_g: &E::G1Affine,
gamma_g: &E::G1Affine,
) -> crate::Result<(
SecretKey<E::ScalarField>,
EncryptionKey<E>,
DecryptionKey<E>,
)> {
let n = chunks_count::<E::ScalarField>(chunk_bit_size) as usize;
if n > g_i.len() {
return Err(SaverError::VectorShorterThanExpected(g_i.len(), n));
}
let rho = E::ScalarField::rand(rng);
let s = (0..n)
.map(|_| E::ScalarField::rand(rng))
.collect::<Vec<_>>();
let t = (0..=n)
.map(|_| E::ScalarField::rand(rng))
.collect::<Vec<_>>();
let v = (0..n)
.map(|_| E::ScalarField::rand(rng))
.collect::<Vec<_>>();
let delta_g_proj = delta_g.into_group();
let t_repr = cfg_iter!(t).map(|t| t.into_bigint()).collect::<Vec<_>>();
let X = multiply_field_elems_with_same_group_elem(delta_g_proj, &s);
let Y = (0..n)
.map(|i| g_i[i].mul_bigint(t_repr[i + 1]))
.collect::<Vec<_>>();
let Z = multiply_field_elems_with_same_group_elem(gens.H.into_group(), &t);
let P_1 = delta_g_proj
.mul_bigint((t[0] + (0..n).map(|j| s[j] * t[j + 1]).sum::<E::ScalarField>()).into_bigint());
let ek = EncryptionKey {
X_0: *delta_g,
X: E::G1::normalize_batch(&X),
Y: E::G1::normalize_batch(&Y),
Z: E::G2::normalize_batch(&Z),
P_1: P_1.into_affine(),
P_2: gamma_g
.mul_bigint((E::ScalarField::one() + s.iter().sum::<E::ScalarField>()).into_bigint())
.into_affine(),
};
let V_0 = gens.H.mul_bigint(rho.into_bigint());
let V_2 = multiply_field_elems_with_same_group_elem(V_0, &v);
let V_1 = multiply_field_elems_with_same_group_elem(
gens.H.into_group(),
&s.into_iter()
.zip(v.into_iter())
.map(|(s_i, v_i)| s_i * v_i)
.collect::<Vec<_>>(),
);
let dk = DecryptionKey {
V_0: V_0.into_affine(),
V_1: E::G2::normalize_batch(&V_1),
V_2: E::G2::normalize_batch(&V_2),
};
Ok((SecretKey(rho), ek, dk))
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::test_serialization;
use ark_bls12_381::Bls12_381;
use ark_std::rand::{prelude::StdRng, SeedableRng};
type Fr = <Bls12_381 as Pairing>::ScalarField;
#[test]
fn keygen_works() {
fn check_keygen(chunk_bit_size: u8) {
let mut rng = StdRng::seed_from_u64(0u64);
let chunk_count = chunks_count::<Fr>(chunk_bit_size) as usize;
let gens = EncryptionGens::<Bls12_381>::new_using_rng(&mut rng);
let g_i = (0..chunk_count)
.map(|_| <Bls12_381 as Pairing>::G1Affine::rand(&mut rng))
.collect::<Vec<_>>();
let delta = Fr::rand(&mut rng);
let gamma = Fr::rand(&mut rng);
let g_delta = gens.G.mul_bigint(delta.into_bigint()).into_affine();
let g_gamma = gens.G.mul_bigint(gamma.into_bigint()).into_affine();
let (sk, ek, dk) =
keygen(&mut rng, chunk_bit_size, &gens, &g_i, &g_delta, &g_gamma).unwrap();
let prepared_ek = PreparedEncryptionKey::from(ek.clone());
let prepared_dk = PreparedDecryptionKey::from(dk.clone());
assert_eq!(ek.X.len(), chunk_count);
assert_eq!(prepared_ek.X.len(), chunk_count);
assert_eq!(ek.Y.len(), chunk_count);
assert_eq!(prepared_ek.Y.len(), chunk_count);
assert_eq!(ek.Z.len(), chunk_count + 1);
assert_eq!(prepared_ek.Z.len(), chunk_count + 1);
assert_eq!(dk.V_1.len(), chunk_count);
assert_eq!(prepared_dk.V_1.len(), chunk_count);
assert_eq!(dk.V_2.len(), chunk_count);
assert_eq!(prepared_dk.V_2.len(), chunk_count);
ek.validate().unwrap();
prepared_ek.validate().unwrap();
dk.validate().unwrap();
prepared_dk.validate().unwrap();
assert_eq!(ek.supported_chunks_count().unwrap(), chunk_count as u8);
assert_eq!(
prepared_ek.supported_chunks_count().unwrap(),
chunk_count as u8
);
assert_eq!(dk.supported_chunks_count().unwrap(), chunk_count as u8);
assert_eq!(
prepared_dk.supported_chunks_count().unwrap(),
chunk_count as u8
);
assert_eq!(ek.commitment_key().len(), chunk_count + 1);
assert_eq!(prepared_ek.commitment_key().len(), chunk_count + 1);
assert_eq!(ek.commitment_key()[..chunk_count], ek.Y);
assert_eq!(prepared_ek.commitment_key()[..chunk_count], ek.Y);
assert_eq!(ek.commitment_key()[chunk_count], ek.P_1);
assert_eq!(prepared_ek.commitment_key()[chunk_count], ek.P_1);
test_serialization!(EncryptionKey<Bls12_381>, ek);
test_serialization!(DecryptionKey<Bls12_381>, dk);
test_serialization!(SecretKey<Fr>, sk);
drop(sk);
}
check_keygen(4);
check_keygen(8);
check_keygen(16);
}
}