chore(zk): regroup compute load proof optionals

This commit is contained in:
Mayeul@Zama
2024-10-04 08:24:12 +02:00
committed by Nicolas Sarlin
parent 69482dec9b
commit df9fd6cd19
8 changed files with 532 additions and 181 deletions

View File

@@ -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)]

View 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>),
}

View 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>),
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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();

View File

@@ -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),

View File

@@ -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 {