mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
chore(zk): regroup compute load proof optionals
This commit is contained in:
committed by
Nicolas Sarlin
parent
69482dec9b
commit
df9fd6cd19
@@ -1,8 +1,12 @@
|
||||
pub mod pke;
|
||||
pub mod pke_v2;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::Display;
|
||||
|
||||
use tfhe_versionable::VersionsDispatch;
|
||||
|
||||
use crate::curve_api::{Compressible, Curve};
|
||||
use crate::proofs::pke::{CompressedProof as PKEv1CompressedProof, Proof as PKEv1Proof};
|
||||
use crate::proofs::pke_v2::{CompressedProof as PKEv2CompressedProof, Proof as PKEv2Proof};
|
||||
use crate::curve_api::Curve;
|
||||
use crate::proofs::GroupElements;
|
||||
use crate::serialization::{
|
||||
SerializableAffine, SerializableCubicExtField, SerializableFp, SerializableFp2,
|
||||
@@ -34,33 +38,20 @@ pub type SerializableG1AffineVersions = SerializableAffineVersions<SerializableF
|
||||
pub type SerializableG2AffineVersions = SerializableAffineVersions<SerializableFp2>;
|
||||
pub type SerializableFp12Versions = SerializableQuadExtFieldVersions<SerializableFp6>;
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum PKEv1ProofVersions<G: Curve> {
|
||||
V0(PKEv1Proof<G>),
|
||||
/// The proof was missing some elements
|
||||
#[derive(Debug)]
|
||||
pub struct IncompleteProof;
|
||||
|
||||
impl Display for IncompleteProof {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"incomplete serialized ZK proof, missing some pre-computed elements"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum PKEv2ProofVersions<G: Curve> {
|
||||
V0(PKEv2Proof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum PKEv1CompressedProofVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(PKEv1CompressedProof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum PKEv2CompressedProofVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(PKEv2CompressedProof<G>),
|
||||
}
|
||||
impl Error for IncompleteProof {}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(dead_code)]
|
||||
|
||||
117
tfhe-zk-pok/src/backward_compatibility/pke.rs
Normal file
117
tfhe-zk-pok/src/backward_compatibility/pke.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
|
||||
|
||||
use crate::curve_api::{CompressedG1, CompressedG2, Compressible, Curve};
|
||||
use crate::proofs::pke::{
|
||||
CompressedComputeLoadProofFields, CompressedProof, ComputeLoadProofFields, Proof,
|
||||
};
|
||||
|
||||
use super::IncompleteProof;
|
||||
|
||||
#[derive(Version)]
|
||||
pub struct ProofV0<G: Curve> {
|
||||
c_hat: G::G2,
|
||||
c_y: G::G1,
|
||||
pi: G::G1,
|
||||
c_hat_t: Option<G::G2>,
|
||||
c_h: Option<G::G1>,
|
||||
pi_kzg: Option<G::G1>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Upgrade<Proof<G>> for ProofV0<G> {
|
||||
type Error = IncompleteProof;
|
||||
|
||||
fn upgrade(self) -> Result<Proof<G>, Self::Error> {
|
||||
let compute_load_proof_fields = match (self.c_hat_t, self.c_h, self.pi_kzg) {
|
||||
(None, None, None) => None,
|
||||
(Some(c_hat_t), Some(c_h), Some(pi_kzg)) => Some(ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}),
|
||||
_ => {
|
||||
return Err(IncompleteProof);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Proof {
|
||||
c_hat: self.c_hat,
|
||||
c_y: self.c_y,
|
||||
pi: self.pi,
|
||||
compute_load_proof_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum ProofVersions<G: Curve> {
|
||||
V0(ProofV0<G>),
|
||||
V1(Proof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum ComputeLoadProofFieldVersions<G: Curve> {
|
||||
V0(ComputeLoadProofFields<G>),
|
||||
}
|
||||
|
||||
pub struct CompressedProofV0<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
c_hat: CompressedG2<G>,
|
||||
c_y: CompressedG1<G>,
|
||||
pi: CompressedG1<G>,
|
||||
c_hat_t: Option<CompressedG2<G>>,
|
||||
c_h: Option<CompressedG1<G>>,
|
||||
pi_kzg: Option<CompressedG1<G>>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Upgrade<CompressedProof<G>> for CompressedProofV0<G>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
type Error = IncompleteProof;
|
||||
|
||||
fn upgrade(self) -> Result<CompressedProof<G>, Self::Error> {
|
||||
let compute_load_proof_fields = match (self.c_hat_t, self.c_h, self.pi_kzg) {
|
||||
(None, None, None) => None,
|
||||
(Some(c_hat_t), Some(c_h), Some(pi_kzg)) => Some(CompressedComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}),
|
||||
_ => {
|
||||
return Err(IncompleteProof);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(CompressedProof {
|
||||
c_hat: self.c_hat,
|
||||
c_y: self.c_y,
|
||||
pi: self.pi,
|
||||
compute_load_proof_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum CompressedProofVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(CompressedProofV0<G>),
|
||||
V1(CompressedProof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum CompressedComputeLoadProofFieldsVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(CompressedComputeLoadProofFields<G>),
|
||||
}
|
||||
142
tfhe-zk-pok/src/backward_compatibility/pke_v2.rs
Normal file
142
tfhe-zk-pok/src/backward_compatibility/pke_v2.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
// to follow the notation of the paper
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
|
||||
|
||||
use crate::curve_api::{CompressedG1, CompressedG2, Compressible, Curve};
|
||||
use crate::proofs::pke_v2::{
|
||||
CompressedComputeLoadProofFields, CompressedProof, ComputeLoadProofFields, Proof,
|
||||
};
|
||||
|
||||
use super::IncompleteProof;
|
||||
|
||||
#[derive(Version)]
|
||||
pub struct ProofV0<G: Curve> {
|
||||
C_hat_e: G::G2,
|
||||
C_e: G::G1,
|
||||
C_r_tilde: G::G1,
|
||||
C_R: G::G1,
|
||||
C_hat_bin: G::G2,
|
||||
C_y: G::G1,
|
||||
C_h1: G::G1,
|
||||
C_h2: G::G1,
|
||||
C_hat_t: G::G2,
|
||||
pi: G::G1,
|
||||
pi_kzg: G::G1,
|
||||
|
||||
C_hat_h3: Option<G::G2>,
|
||||
C_hat_w: Option<G::G2>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Upgrade<Proof<G>> for ProofV0<G> {
|
||||
type Error = IncompleteProof;
|
||||
|
||||
fn upgrade(self) -> Result<Proof<G>, Self::Error> {
|
||||
let compute_load_proof_fields = match (self.C_hat_h3, self.C_hat_w) {
|
||||
(None, None) => None,
|
||||
(Some(C_hat_h3), Some(C_hat_w)) => Some(ComputeLoadProofFields { C_hat_h3, C_hat_w }),
|
||||
_ => return Err(IncompleteProof),
|
||||
};
|
||||
|
||||
Ok(Proof {
|
||||
C_hat_e: self.C_hat_e,
|
||||
C_e: self.C_e,
|
||||
C_r_tilde: self.C_r_tilde,
|
||||
C_R: self.C_R,
|
||||
C_hat_bin: self.C_hat_bin,
|
||||
C_y: self.C_y,
|
||||
C_h1: self.C_h1,
|
||||
C_h2: self.C_h2,
|
||||
C_hat_t: self.C_hat_t,
|
||||
pi: self.pi,
|
||||
pi_kzg: self.pi_kzg,
|
||||
compute_load_proof_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum ProofVersions<G: Curve> {
|
||||
V0(ProofV0<G>),
|
||||
V1(Proof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum ComputeLoadProofFieldVersions<G: Curve> {
|
||||
V0(ComputeLoadProofFields<G>),
|
||||
}
|
||||
|
||||
pub struct CompressedProofV0<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
C_hat_e: CompressedG2<G>,
|
||||
C_e: CompressedG1<G>,
|
||||
C_r_tilde: CompressedG1<G>,
|
||||
C_R: CompressedG1<G>,
|
||||
C_hat_bin: CompressedG2<G>,
|
||||
C_y: CompressedG1<G>,
|
||||
C_h1: CompressedG1<G>,
|
||||
C_h2: CompressedG1<G>,
|
||||
C_hat_t: CompressedG2<G>,
|
||||
pi: CompressedG1<G>,
|
||||
pi_kzg: CompressedG1<G>,
|
||||
|
||||
C_hat_h3: Option<CompressedG2<G>>,
|
||||
C_hat_w: Option<CompressedG2<G>>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Upgrade<CompressedProof<G>> for CompressedProofV0<G>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
type Error = IncompleteProof;
|
||||
|
||||
fn upgrade(self) -> Result<CompressedProof<G>, Self::Error> {
|
||||
let compute_load_proof_fields = match (self.C_hat_h3, self.C_hat_w) {
|
||||
(None, None) => None,
|
||||
(Some(C_hat_h3), Some(C_hat_w)) => {
|
||||
Some(CompressedComputeLoadProofFields { C_hat_h3, C_hat_w })
|
||||
}
|
||||
_ => return Err(IncompleteProof),
|
||||
};
|
||||
|
||||
Ok(CompressedProof {
|
||||
C_hat_e: self.C_hat_e,
|
||||
C_e: self.C_e,
|
||||
C_r_tilde: self.C_r_tilde,
|
||||
C_R: self.C_R,
|
||||
C_hat_bin: self.C_hat_bin,
|
||||
C_y: self.C_y,
|
||||
C_h1: self.C_h1,
|
||||
C_h2: self.C_h2,
|
||||
C_hat_t: self.C_hat_t,
|
||||
pi: self.pi,
|
||||
pi_kzg: self.pi_kzg,
|
||||
compute_load_proof_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum CompressedProofVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(CompressedProofV0<G>),
|
||||
V1(CompressedProof<G>),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum CompressedComputeLoadProofFieldsVersions<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
V0(CompressedComputeLoadProofFields<G>),
|
||||
}
|
||||
@@ -128,6 +128,9 @@ pub trait Compressible: Sized {
|
||||
fn uncompress(compressed: Self::Compressed) -> Result<Self, Self::UncompressError>;
|
||||
}
|
||||
|
||||
pub type CompressedG1<G> = <<G as Curve>::G1 as Compressible>::Compressed;
|
||||
pub type CompressedG2<G> = <<G as Curve>::G2 as Compressible>::Compressed;
|
||||
|
||||
pub trait PairingGroupOps<Zp, G1, G2>:
|
||||
Copy
|
||||
+ Send
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// TODO: refactor copy-pasted code in proof/verify
|
||||
|
||||
use crate::backward_compatibility::{PKEv1CompressedProofVersions, PKEv1ProofVersions};
|
||||
use crate::backward_compatibility::pke::{
|
||||
CompressedComputeLoadProofFieldsVersions, CompressedProofVersions,
|
||||
ComputeLoadProofFieldVersions, ProofVersions,
|
||||
};
|
||||
use crate::serialization::{
|
||||
try_vec_to_array, InvalidSerializedAffineError, InvalidSerializedPublicParamsError,
|
||||
SerializableGroupElements, SerializablePKEv1PublicParams,
|
||||
@@ -186,14 +189,26 @@ impl<G: Curve> PublicParams<G> {
|
||||
deserialize = "G: Curve, G::G1: serde::Deserialize<'de>, G::G2: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, G::G1: serde::Serialize, G::G2: serde::Serialize"
|
||||
))]
|
||||
#[versionize(PKEv1ProofVersions)]
|
||||
#[versionize(ProofVersions)]
|
||||
pub struct Proof<G: Curve> {
|
||||
c_hat: G::G2,
|
||||
c_y: G::G1,
|
||||
pi: G::G1,
|
||||
c_hat_t: Option<G::G2>,
|
||||
c_h: Option<G::G1>,
|
||||
pi_kzg: Option<G::G1>,
|
||||
pub(crate) c_hat: G::G2,
|
||||
pub(crate) c_y: G::G1,
|
||||
pub(crate) pi: G::G1,
|
||||
pub(crate) compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
|
||||
}
|
||||
|
||||
/// These fields can be pre-computed on the prover side in the faster Verifier scheme. If that's the
|
||||
/// case, they should be included in the proof.
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Versionize)]
|
||||
#[serde(bound(
|
||||
deserialize = "G: Curve, G::G1: serde::Deserialize<'de>, G::G2: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, G::G1: serde::Serialize, G::G2: serde::Serialize"
|
||||
))]
|
||||
#[versionize(ComputeLoadProofFieldVersions)]
|
||||
pub(crate) struct ComputeLoadProofFields<G: Curve> {
|
||||
pub(crate) c_hat_t: G::G2,
|
||||
pub(crate) c_h: G::G1,
|
||||
pub(crate) pi_kzg: G::G1,
|
||||
}
|
||||
|
||||
type CompressedG2<G> = <<G as Curve>::G2 as Compressible>::Compressed;
|
||||
@@ -204,18 +219,32 @@ type CompressedG1<G> = <<G as Curve>::G1 as Compressible>::Compressed;
|
||||
deserialize = "G: Curve, CompressedG1<G>: serde::Deserialize<'de>, CompressedG2<G>: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, CompressedG1<G>: serde::Serialize, CompressedG2<G>: serde::Serialize"
|
||||
))]
|
||||
#[versionize(PKEv1CompressedProofVersions)]
|
||||
#[versionize(CompressedProofVersions)]
|
||||
pub struct CompressedProof<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
c_hat: CompressedG2<G>,
|
||||
c_y: CompressedG1<G>,
|
||||
pi: CompressedG1<G>,
|
||||
c_hat_t: Option<CompressedG2<G>>,
|
||||
c_h: Option<CompressedG1<G>>,
|
||||
pi_kzg: Option<CompressedG1<G>>,
|
||||
pub(crate) c_hat: CompressedG2<G>,
|
||||
pub(crate) c_y: CompressedG1<G>,
|
||||
pub(crate) pi: CompressedG1<G>,
|
||||
pub(crate) compute_load_proof_fields: Option<CompressedComputeLoadProofFields<G>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Versionize)]
|
||||
#[serde(bound(
|
||||
deserialize = "G: Curve, CompressedG1<G>: serde::Deserialize<'de>, CompressedG2<G>: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, CompressedG1<G>: serde::Serialize, CompressedG2<G>: serde::Serialize"
|
||||
))]
|
||||
#[versionize(CompressedComputeLoadProofFieldsVersions)]
|
||||
pub(crate) struct CompressedComputeLoadProofFields<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
pub(crate) c_hat_t: CompressedG2<G>,
|
||||
pub(crate) c_h: CompressedG1<G>,
|
||||
pub(crate) pi_kzg: CompressedG1<G>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Compressible for Proof<G>
|
||||
@@ -232,18 +261,24 @@ where
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
compute_load_proof_fields,
|
||||
} = self;
|
||||
|
||||
CompressedProof {
|
||||
c_hat: c_hat.compress(),
|
||||
c_y: c_y.compress(),
|
||||
pi: pi.compress(),
|
||||
c_hat_t: c_hat_t.map(|val| val.compress()),
|
||||
c_h: c_h.map(|val| val.compress()),
|
||||
pi_kzg: pi_kzg.map(|val| val.compress()),
|
||||
compute_load_proof_fields: compute_load_proof_fields.as_ref().map(
|
||||
|ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}| CompressedComputeLoadProofFields {
|
||||
c_hat_t: c_hat_t.compress(),
|
||||
c_h: c_h.compress(),
|
||||
pi_kzg: pi_kzg.compress(),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,28 +287,29 @@ where
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
compute_load_proof_fields,
|
||||
} = compressed;
|
||||
|
||||
Ok(Proof {
|
||||
c_hat: G::G2::uncompress(c_hat)?,
|
||||
c_y: G::G1::uncompress(c_y)?,
|
||||
pi: G::G1::uncompress(pi)?,
|
||||
c_hat_t: c_hat_t.map(G::G2::uncompress).transpose()?,
|
||||
c_h: c_h.map(G::G1::uncompress).transpose()?,
|
||||
pi_kzg: pi_kzg.map(G::G1::uncompress).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Curve> Proof<G> {
|
||||
pub fn content_is_usable(&self) -> bool {
|
||||
matches!(
|
||||
(self.c_hat_t, self.c_h, self.pi_kzg),
|
||||
(None, None, None) | (Some(_), Some(_), Some(_))
|
||||
)
|
||||
compute_load_proof_fields: if let Some(CompressedComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}) = compute_load_proof_fields
|
||||
{
|
||||
Some(ComputeLoadProofFields {
|
||||
c_hat_t: G::G2::uncompress(c_hat_t)?,
|
||||
c_h: G::G1::uncompress(c_h)?,
|
||||
pi_kzg: G::G1::uncompress(pi_kzg)?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,18 +829,18 @@ pub fn prove<G: Curve>(
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t: Some(c_hat_t),
|
||||
c_h: Some(c_h),
|
||||
pi_kzg: Some(pi_kzg),
|
||||
compute_load_proof_fields: Some(ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Proof {
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t: None,
|
||||
c_h: None,
|
||||
pi_kzg: None,
|
||||
compute_load_proof_fields: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -939,10 +975,9 @@ pub fn verify<G: Curve>(
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
ref compute_load_proof_fields,
|
||||
} = proof;
|
||||
|
||||
let e = G::Gt::pairing;
|
||||
|
||||
let &PublicParams {
|
||||
@@ -1081,7 +1116,12 @@ pub fn verify<G: Curve>(
|
||||
let [delta_eq, delta_y] = delta;
|
||||
let delta = [delta_eq, delta_y, delta_theta];
|
||||
|
||||
if let (Some(pi_kzg), Some(c_hat_t), Some(c_h)) = (pi_kzg, c_hat_t, c_h) {
|
||||
if let Some(&ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}) = compute_load_proof_fields.as_ref()
|
||||
{
|
||||
let mut z = G::Zp::ZERO;
|
||||
G::Zp::hash(
|
||||
core::array::from_mut(&mut z),
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use super::*;
|
||||
use crate::backward_compatibility::{PKEv2CompressedProofVersions, PKEv2ProofVersions};
|
||||
use crate::backward_compatibility::pke_v2::{CompressedProofVersions, ProofVersions};
|
||||
use crate::curve_api::{CompressedG1, CompressedG2};
|
||||
use crate::four_squares::*;
|
||||
use crate::serialization::{
|
||||
try_vec_to_array, InvalidSerializedAffineError, InvalidSerializedPublicParamsError,
|
||||
@@ -229,52 +230,69 @@ impl<G: Curve> PublicParams<G> {
|
||||
deserialize = "G: Curve, G::G1: serde::Deserialize<'de>, G::G2: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, G::G1: serde::Serialize, G::G2: serde::Serialize"
|
||||
))]
|
||||
#[versionize(PKEv2ProofVersions)]
|
||||
#[versionize(ProofVersions)]
|
||||
pub struct Proof<G: Curve> {
|
||||
C_hat_e: G::G2,
|
||||
C_e: G::G1,
|
||||
C_r_tilde: G::G1,
|
||||
C_R: G::G1,
|
||||
C_hat_bin: G::G2,
|
||||
C_y: G::G1,
|
||||
C_h1: G::G1,
|
||||
C_h2: G::G1,
|
||||
C_hat_t: G::G2,
|
||||
pi: G::G1,
|
||||
pi_kzg: G::G1,
|
||||
pub(crate) C_hat_e: G::G2,
|
||||
pub(crate) C_e: G::G1,
|
||||
pub(crate) C_r_tilde: G::G1,
|
||||
pub(crate) C_R: G::G1,
|
||||
pub(crate) C_hat_bin: G::G2,
|
||||
pub(crate) C_y: G::G1,
|
||||
pub(crate) C_h1: G::G1,
|
||||
pub(crate) C_h2: G::G1,
|
||||
pub(crate) C_hat_t: G::G2,
|
||||
pub(crate) pi: G::G1,
|
||||
pub(crate) pi_kzg: G::G1,
|
||||
|
||||
C_hat_h3: Option<G::G2>,
|
||||
C_hat_w: Option<G::G2>,
|
||||
pub(crate) compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
|
||||
}
|
||||
|
||||
type CompressedG2<G> = <<G as Curve>::G2 as Compressible>::Compressed;
|
||||
type CompressedG1<G> = <<G as Curve>::G1 as Compressible>::Compressed;
|
||||
/// These fields can be pre-computed on the prover side in the faster Verifier scheme. If that's the
|
||||
/// case, they should be included in the proof.
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub(crate) struct ComputeLoadProofFields<G: Curve> {
|
||||
pub(crate) C_hat_h3: G::G2,
|
||||
pub(crate) C_hat_w: G::G2,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Versionize)]
|
||||
#[serde(bound(
|
||||
deserialize = "G: Curve, CompressedG1<G>: serde::Deserialize<'de>, CompressedG2<G>: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, CompressedG1<G>: serde::Serialize, CompressedG2<G>: serde::Serialize"
|
||||
))]
|
||||
#[versionize(PKEv2CompressedProofVersions)]
|
||||
#[versionize(CompressedProofVersions)]
|
||||
pub struct CompressedProof<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
C_hat_e: CompressedG2<G>,
|
||||
C_e: CompressedG1<G>,
|
||||
C_r_tilde: CompressedG1<G>,
|
||||
C_R: CompressedG1<G>,
|
||||
C_hat_bin: CompressedG2<G>,
|
||||
C_y: CompressedG1<G>,
|
||||
C_h1: CompressedG1<G>,
|
||||
C_h2: CompressedG1<G>,
|
||||
C_hat_t: CompressedG2<G>,
|
||||
pi: CompressedG1<G>,
|
||||
pi_kzg: CompressedG1<G>,
|
||||
pub(crate) C_hat_e: CompressedG2<G>,
|
||||
pub(crate) C_e: CompressedG1<G>,
|
||||
pub(crate) C_r_tilde: CompressedG1<G>,
|
||||
pub(crate) C_R: CompressedG1<G>,
|
||||
pub(crate) C_hat_bin: CompressedG2<G>,
|
||||
pub(crate) C_y: CompressedG1<G>,
|
||||
pub(crate) C_h1: CompressedG1<G>,
|
||||
pub(crate) C_h2: CompressedG1<G>,
|
||||
pub(crate) C_hat_t: CompressedG2<G>,
|
||||
pub(crate) pi: CompressedG1<G>,
|
||||
pub(crate) pi_kzg: CompressedG1<G>,
|
||||
|
||||
C_hat_h3: Option<CompressedG2<G>>,
|
||||
C_hat_w: Option<CompressedG2<G>>,
|
||||
pub(crate) compute_load_proof_fields: Option<CompressedComputeLoadProofFields<G>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound(
|
||||
deserialize = "G: Curve, CompressedG1<G>: serde::Deserialize<'de>, CompressedG2<G>: serde::Deserialize<'de>",
|
||||
serialize = "G: Curve, CompressedG1<G>: serde::Serialize, CompressedG2<G>: serde::Serialize"
|
||||
))]
|
||||
pub(crate) struct CompressedComputeLoadProofFields<G: Curve>
|
||||
where
|
||||
G::G1: Compressible,
|
||||
G::G2: Compressible,
|
||||
{
|
||||
pub(crate) C_hat_h3: CompressedG2<G>,
|
||||
pub(crate) C_hat_w: CompressedG2<G>,
|
||||
}
|
||||
|
||||
impl<G: Curve> Compressible for Proof<G>
|
||||
@@ -299,8 +317,7 @@ where
|
||||
C_hat_t,
|
||||
pi,
|
||||
pi_kzg,
|
||||
C_hat_h3,
|
||||
C_hat_w,
|
||||
compute_load_proof_fields,
|
||||
} = self;
|
||||
|
||||
CompressedProof {
|
||||
@@ -315,8 +332,13 @@ where
|
||||
C_hat_t: C_hat_t.compress(),
|
||||
pi: pi.compress(),
|
||||
pi_kzg: pi_kzg.compress(),
|
||||
C_hat_h3: C_hat_h3.map(|val| val.compress()),
|
||||
C_hat_w: C_hat_w.map(|val| val.compress()),
|
||||
|
||||
compute_load_proof_fields: compute_load_proof_fields.as_ref().map(
|
||||
|ComputeLoadProofFields { C_hat_h3, C_hat_w }| CompressedComputeLoadProofFields {
|
||||
C_hat_h3: C_hat_h3.compress(),
|
||||
C_hat_w: C_hat_w.compress(),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,8 +355,7 @@ where
|
||||
C_hat_t,
|
||||
pi,
|
||||
pi_kzg,
|
||||
C_hat_h3,
|
||||
C_hat_w,
|
||||
compute_load_proof_fields,
|
||||
} = compressed;
|
||||
|
||||
Ok(Proof {
|
||||
@@ -349,8 +370,19 @@ where
|
||||
C_hat_t: G::G2::uncompress(C_hat_t)?,
|
||||
pi: G::G1::uncompress(pi)?,
|
||||
pi_kzg: G::G1::uncompress(pi_kzg)?,
|
||||
C_hat_h3: C_hat_h3.map(G::G2::uncompress).transpose()?,
|
||||
C_hat_w: C_hat_w.map(G::G2::uncompress).transpose()?,
|
||||
|
||||
compute_load_proof_fields: if let Some(CompressedComputeLoadProofFields {
|
||||
C_hat_h3,
|
||||
C_hat_w,
|
||||
}) = compute_load_proof_fields
|
||||
{
|
||||
Some(ComputeLoadProofFields {
|
||||
C_hat_h3: G::G2::uncompress(C_hat_h3)?,
|
||||
C_hat_w: G::G2::uncompress(C_hat_w)?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1383,42 +1415,50 @@ pub fn prove<G: Curve>(
|
||||
.collect::<Box<[_]>>();
|
||||
scalars.reverse();
|
||||
let C_h2 = G::G1::multi_mul_scalar(&g_list[..n], &scalars);
|
||||
let (C_hat_h3, C_hat_w) = match load {
|
||||
ComputeLoad::Proof => rayon::join(
|
||||
|| {
|
||||
Some(G::G2::multi_mul_scalar(
|
||||
&g_hat_list[n - (d + k)..n],
|
||||
&(0..d + k)
|
||||
.rev()
|
||||
.map(|j| {
|
||||
let mut acc = G::Zp::ZERO;
|
||||
for (i, &phi) in phi.iter().enumerate() {
|
||||
match R(i, d + k + 4 + j) {
|
||||
0 => {}
|
||||
1 => acc += phi,
|
||||
-1 => acc -= phi,
|
||||
_ => unreachable!(),
|
||||
let compute_load_proof_fields = match load {
|
||||
ComputeLoad::Proof => {
|
||||
let (C_hat_h3, C_hat_w) = rayon::join(
|
||||
|| {
|
||||
G::G2::multi_mul_scalar(
|
||||
&g_hat_list[n - (d + k)..n],
|
||||
&(0..d + k)
|
||||
.rev()
|
||||
.map(|j| {
|
||||
let mut acc = G::Zp::ZERO;
|
||||
for (i, &phi) in phi.iter().enumerate() {
|
||||
match R(i, d + k + 4 + j) {
|
||||
0 => {}
|
||||
1 => acc += phi,
|
||||
-1 => acc -= phi,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
delta_r * acc - delta_theta_q * theta[j]
|
||||
})
|
||||
.collect::<Box<[_]>>(),
|
||||
))
|
||||
},
|
||||
|| {
|
||||
Some(G::G2::multi_mul_scalar(
|
||||
&g_hat_list[..d + k + 4],
|
||||
&w[..d + k + 4],
|
||||
))
|
||||
},
|
||||
),
|
||||
ComputeLoad::Verify => (None, None),
|
||||
delta_r * acc - delta_theta_q * theta[j]
|
||||
})
|
||||
.collect::<Box<[_]>>(),
|
||||
)
|
||||
},
|
||||
|| G::G2::multi_mul_scalar(&g_hat_list[..d + k + 4], &w[..d + k + 4]),
|
||||
);
|
||||
|
||||
Some(ComputeLoadProofFields { C_hat_h3, C_hat_w })
|
||||
}
|
||||
ComputeLoad::Verify => None,
|
||||
};
|
||||
|
||||
let C_hat_h3_bytes = C_hat_h3.map(G::G2::to_le_bytes);
|
||||
let C_hat_w_bytes = C_hat_w.map(G::G2::to_le_bytes);
|
||||
let C_hat_h3_bytes = C_hat_h3_bytes.as_ref().map(|x| x.as_ref()).unwrap_or(&[]);
|
||||
let C_hat_w_bytes = C_hat_w_bytes.as_ref().map(|x| x.as_ref()).unwrap_or(&[]);
|
||||
let byte_generators =
|
||||
if let Some(ComputeLoadProofFields { C_hat_h3, C_hat_w }) = compute_load_proof_fields {
|
||||
Some((G::G2::to_le_bytes(C_hat_h3), G::G2::to_le_bytes(C_hat_w)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (C_hat_h3_bytes, C_hat_w_bytes): (&[u8], &[u8]) =
|
||||
if let Some((C_hat_h3_bytes_owner, C_hat_w_bytes_owner)) = byte_generators.as_ref() {
|
||||
(C_hat_h3_bytes_owner.as_ref(), C_hat_w_bytes_owner.as_ref())
|
||||
} else {
|
||||
(&[], &[])
|
||||
};
|
||||
|
||||
let C_hat_t = G::G2::multi_mul_scalar(g_hat_list, &t);
|
||||
|
||||
@@ -1622,10 +1662,9 @@ pub fn prove<G: Curve>(
|
||||
C_h1,
|
||||
C_h2,
|
||||
C_hat_t,
|
||||
C_hat_h3,
|
||||
C_hat_w,
|
||||
pi,
|
||||
pi_kzg,
|
||||
compute_load_proof_fields,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1747,11 +1786,11 @@ pub fn verify<G: Curve>(
|
||||
C_h1,
|
||||
C_h2,
|
||||
C_hat_t,
|
||||
C_hat_h3,
|
||||
C_hat_w,
|
||||
pi,
|
||||
pi_kzg,
|
||||
ref compute_load_proof_fields,
|
||||
} = proof;
|
||||
|
||||
let pairing = G::Gt::pairing;
|
||||
|
||||
let &PublicParams {
|
||||
@@ -1803,10 +1842,20 @@ pub fn verify<G: Curve>(
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let C_hat_h3_bytes = C_hat_h3.map(G::G2::to_le_bytes);
|
||||
let C_hat_w_bytes = C_hat_w.map(G::G2::to_le_bytes);
|
||||
let C_hat_h3_bytes = C_hat_h3_bytes.as_ref().map(|x| x.as_ref()).unwrap_or(&[]);
|
||||
let C_hat_w_bytes = C_hat_w_bytes.as_ref().map(|x| x.as_ref()).unwrap_or(&[]);
|
||||
let byte_generators = if let Some(&ComputeLoadProofFields { C_hat_h3, C_hat_w }) =
|
||||
compute_load_proof_fields.as_ref()
|
||||
{
|
||||
Some((G::G2::to_le_bytes(C_hat_h3), G::G2::to_le_bytes(C_hat_w)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (C_hat_h3_bytes, C_hat_w_bytes): (&[u8], &[u8]) =
|
||||
if let Some((C_hat_h3_bytes_owner, C_hat_w_bytes_owner)) = byte_generators.as_ref() {
|
||||
(C_hat_h3_bytes_owner.as_ref(), C_hat_w_bytes_owner.as_ref())
|
||||
} else {
|
||||
(&[], &[])
|
||||
};
|
||||
|
||||
let x_bytes = &*[
|
||||
q.to_le_bytes().as_slice(),
|
||||
@@ -2059,8 +2108,11 @@ pub fn verify<G: Curve>(
|
||||
|
||||
let lhs2 = pairing(
|
||||
C_r_tilde,
|
||||
match C_hat_h3 {
|
||||
Some(C_hat_h3) => C_hat_h3,
|
||||
match compute_load_proof_fields.as_ref() {
|
||||
Some(&ComputeLoadProofFields {
|
||||
C_hat_h3,
|
||||
C_hat_w: _,
|
||||
}) => C_hat_h3,
|
||||
None => G::G2::multi_mul_scalar(
|
||||
&g_hat_list[n - (d + k)..n],
|
||||
&(0..d + k)
|
||||
@@ -2093,8 +2145,11 @@ pub fn verify<G: Curve>(
|
||||
);
|
||||
let lhs4 = pairing(
|
||||
C_e.mul_scalar(delta_e),
|
||||
match C_hat_w {
|
||||
Some(C_hat_w) => C_hat_w,
|
||||
match compute_load_proof_fields.as_ref() {
|
||||
Some(&ComputeLoadProofFields {
|
||||
C_hat_h3: _,
|
||||
C_hat_w,
|
||||
}) => C_hat_w,
|
||||
None => G::G2::multi_mul_scalar(&g_hat_list[..d + k + 4], &w[..d + k + 4]),
|
||||
},
|
||||
);
|
||||
@@ -2140,7 +2195,7 @@ pub fn verify<G: Curve>(
|
||||
],
|
||||
);
|
||||
|
||||
let load = if C_hat_h3.is_some() && C_hat_w.is_some() {
|
||||
let load = if compute_load_proof_fields.is_some() {
|
||||
ComputeLoad::Proof
|
||||
} else {
|
||||
ComputeLoad::Verify
|
||||
@@ -2293,10 +2348,8 @@ pub fn verify<G: Curve>(
|
||||
g,
|
||||
{
|
||||
let mut C_hat = C_hat_t.mul_scalar(chi2);
|
||||
if let Some(C_hat_h3) = C_hat_h3 {
|
||||
if let Some(ComputeLoadProofFields { C_hat_h3, C_hat_w }) = compute_load_proof_fields {
|
||||
C_hat += C_hat_h3.mul_scalar(chi3);
|
||||
}
|
||||
if let Some(C_hat_w) = C_hat_w {
|
||||
C_hat += C_hat_w.mul_scalar(chi4);
|
||||
}
|
||||
C_hat
|
||||
@@ -2573,7 +2626,7 @@ mod tests {
|
||||
rng,
|
||||
);
|
||||
|
||||
let compressed_proof = bincode::serialize(&proof.clone().compress()).unwrap();
|
||||
let compressed_proof = bincode::serialize(&proof.compress()).unwrap();
|
||||
let proof =
|
||||
Proof::uncompress(bincode::deserialize(&compressed_proof).unwrap()).unwrap();
|
||||
|
||||
|
||||
@@ -81,9 +81,14 @@ pub struct Proof<G: Curve> {
|
||||
c_hat: G::G2,
|
||||
c_y: G::G1,
|
||||
pi: G::G1,
|
||||
c_hat_t: Option<G::G2>,
|
||||
c_h: Option<G::G1>,
|
||||
pi_kzg: Option<G::G1>,
|
||||
compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ComputeLoadProofFields<G: Curve> {
|
||||
c_hat_t: G::G2,
|
||||
c_h: G::G1,
|
||||
pi_kzg: G::G1,
|
||||
}
|
||||
|
||||
pub fn crs_gen<G: Curve>(
|
||||
@@ -594,18 +599,18 @@ pub fn prove<G: Curve>(
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t: Some(c_hat_t),
|
||||
c_h: Some(c_h),
|
||||
pi_kzg: Some(pi_kzg),
|
||||
compute_load_proof_fields: Some(ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Proof {
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t: None,
|
||||
c_h: None,
|
||||
pi_kzg: None,
|
||||
compute_load_proof_fields: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,10 +624,9 @@ pub fn verify<G: Curve>(
|
||||
c_hat,
|
||||
c_y,
|
||||
pi,
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
ref compute_load_proof_fields,
|
||||
} = proof;
|
||||
|
||||
let e = G::Gt::pairing;
|
||||
|
||||
let &PublicParams {
|
||||
@@ -785,7 +789,12 @@ pub fn verify<G: Curve>(
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(pi_kzg), Some(c_hat_t), Some(c_h)) = (pi_kzg, c_hat_t, c_h) {
|
||||
if let Some(&ComputeLoadProofFields {
|
||||
c_hat_t,
|
||||
c_h,
|
||||
pi_kzg,
|
||||
}) = compute_load_proof_fields.as_ref()
|
||||
{
|
||||
let mut z = G::Zp::ZERO;
|
||||
G::Zp::hash(
|
||||
core::array::from_mut(&mut z),
|
||||
|
||||
@@ -228,15 +228,11 @@ impl ParameterSetConformant for ProvenCompactCiphertextList {
|
||||
|
||||
let mut remaining_len = *total_expected_lwe_count;
|
||||
|
||||
for (compact_ct_list, proof) in proved_lists {
|
||||
for (compact_ct_list, _proof) in proved_lists {
|
||||
if remaining_len == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !proof.content_is_usable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let expected_len;
|
||||
|
||||
if remaining_len > max_elements_per_compact_list {
|
||||
|
||||
Reference in New Issue
Block a user