chore(zk): match zkv2 hash impl with the description

- encode the position of bits proven to be 0 in the hashes
- hash the infinite norm instead of the euclidean one
- hash the value of k with the statement
This commit is contained in:
Nicolas Sarlin
2025-10-27 14:39:43 +01:00
committed by Nicolas Sarlin
parent bcb1356b76
commit b7fc208e40
6 changed files with 480 additions and 79 deletions

View File

@@ -2,12 +2,15 @@
#![allow(non_snake_case)]
use std::convert::Infallible;
use std::error::Error;
use std::fmt::Display;
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
use crate::curve_api::{CompressedG1, CompressedG2, Compressible, Curve};
use crate::proofs::pke_v2::{
CompressedComputeLoadProofFields, CompressedProof, ComputeLoadProofFields, PkeV2HashMode, Proof,
CompressedComputeLoadProofFields, CompressedProof, ComputeLoadProofFields, PkeV2HashMode,
PkeV2SupportedHashConfig, Proof,
};
use super::IncompleteProof;
@@ -89,10 +92,10 @@ pub struct ProofV1<G: Curve> {
compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
}
impl<G: Curve> Upgrade<Proof<G>> for ProofV1<G> {
impl<G: Curve> Upgrade<ProofV2<G>> for ProofV1<G> {
type Error = Infallible;
fn upgrade(self) -> Result<Proof<G>, Self::Error> {
fn upgrade(self) -> Result<ProofV2<G>, Self::Error> {
let ProofV1 {
C_hat_e,
C_e,
@@ -108,7 +111,7 @@ impl<G: Curve> Upgrade<Proof<G>> for ProofV1<G> {
compute_load_proof_fields,
} = self;
Ok(Proof {
Ok(ProofV2 {
C_hat_e,
C_e,
C_r_tilde,
@@ -126,11 +129,92 @@ impl<G: Curve> Upgrade<Proof<G>> for ProofV1<G> {
}
}
#[derive(Version)]
pub struct ProofV2<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,
compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
hash_mode: PkeV2HashMode,
}
#[derive(Debug)]
pub struct UnsupportedHashConfig(String);
impl Display for UnsupportedHashConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Unsupported Hash config in pke V2 Proof: {}", self.0)
}
}
impl Error for UnsupportedHashConfig {}
impl TryFrom<PkeV2HashMode> for PkeV2SupportedHashConfig {
type Error = UnsupportedHashConfig;
fn try_from(value: PkeV2HashMode) -> Result<Self, Self::Error> {
match value {
PkeV2HashMode::BackwardCompat => Ok(PkeV2SupportedHashConfig::V0_4_0),
PkeV2HashMode::Classical => Err(UnsupportedHashConfig(String::from(
"Proof use hash mode \"Classical\" which has never been part of a default configuration",
))),
PkeV2HashMode::Compact => Ok(PkeV2SupportedHashConfig::V0_7_0),
}
}
}
impl<G: Curve> Upgrade<Proof<G>> for ProofV2<G> {
type Error = UnsupportedHashConfig;
fn upgrade(self) -> Result<Proof<G>, Self::Error> {
let ProofV2 {
C_hat_e,
C_e,
C_r_tilde,
C_R,
C_hat_bin,
C_y,
C_h1,
C_h2,
C_hat_t,
pi,
pi_kzg,
compute_load_proof_fields,
hash_mode,
} = self;
Ok(Proof {
C_hat_e,
C_e,
C_r_tilde,
C_R,
C_hat_bin,
C_y,
C_h1,
C_h2,
C_hat_t,
pi,
pi_kzg,
compute_load_proof_fields,
hash_config: hash_mode.try_into()?,
})
}
}
#[derive(VersionsDispatch)]
pub enum ProofVersions<G: Curve> {
V0(ProofV0<G>),
V1(ProofV1<G>),
V2(Proof<G>),
V2(ProofV2<G>),
V3(Proof<G>),
}
#[derive(VersionsDispatch)]
@@ -230,14 +314,14 @@ where
compute_load_proof_fields: Option<CompressedComputeLoadProofFields<G>>,
}
impl<G: Curve> Upgrade<CompressedProof<G>> for CompressedProofV1<G>
impl<G: Curve> Upgrade<CompressedProofV2<G>> for CompressedProofV1<G>
where
G::G1: Compressible,
G::G2: Compressible,
{
type Error = Infallible;
fn upgrade(self) -> Result<CompressedProof<G>, Self::Error> {
fn upgrade(self) -> Result<CompressedProofV2<G>, Self::Error> {
let CompressedProofV1 {
C_hat_e,
C_e,
@@ -253,7 +337,7 @@ where
compute_load_proof_fields,
} = self;
Ok(CompressedProof {
Ok(CompressedProofV2 {
C_hat_e,
C_e,
C_r_tilde,
@@ -271,6 +355,69 @@ where
}
}
#[derive(Version)]
pub struct CompressedProofV2<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>,
compute_load_proof_fields: Option<CompressedComputeLoadProofFields<G>>,
hash_mode: PkeV2HashMode,
}
impl<G: Curve> Upgrade<CompressedProof<G>> for CompressedProofV2<G>
where
G::G1: Compressible,
G::G2: Compressible,
{
type Error = UnsupportedHashConfig;
fn upgrade(self) -> Result<CompressedProof<G>, Self::Error> {
let CompressedProofV2 {
C_hat_e,
C_e,
C_r_tilde,
C_R,
C_hat_bin,
C_y,
C_h1,
C_h2,
C_hat_t,
pi,
pi_kzg,
compute_load_proof_fields,
hash_mode,
} = self;
Ok(CompressedProof {
C_hat_e,
C_e,
C_r_tilde,
C_R,
C_hat_bin,
C_y,
C_h1,
C_h2,
C_hat_t,
pi,
pi_kzg,
compute_load_proof_fields,
hash_config: hash_mode.try_into()?,
})
}
}
#[derive(VersionsDispatch)]
pub enum CompressedProofVersions<G: Curve>
where
@@ -279,7 +426,8 @@ where
{
V0(CompressedProofV0<G>),
V1(CompressedProofV1<G>),
V2(CompressedProof<G>),
V2(CompressedProofV2<G>),
V3(CompressedProof<G>),
}
#[derive(VersionsDispatch)]
@@ -297,3 +445,9 @@ pub enum PkeV2HashModeVersions {
#[allow(dead_code)]
V0(PkeV2HashMode),
}
#[derive(VersionsDispatch)]
pub enum PkeV2SupportedHashConfigVersions {
#[allow(dead_code)]
V0(PkeV2SupportedHashConfig),
}

View File

@@ -5,7 +5,7 @@ use tfhe_versionable::Versionize;
/// Scalar generation using the hash random oracle
use crate::{
backward_compatibility::pke_v2::PkeV2HashModeVersions,
backward_compatibility::pke_v2::{PkeV2HashModeVersions, PkeV2SupportedHashConfigVersions},
curve_api::{Curve, FieldOps},
proofs::pke_v2::{compute_crs_params, inf_norm_bound_to_euclidean_squared},
};
@@ -39,6 +39,191 @@ pub enum PkeV2HashMode {
Compact = 2,
}
#[derive(Debug, Clone, Copy)]
/// How the position of bits proven to be 0 is encoded
pub enum PkeV2ProvenZeroBitsEncoding {
/// Light encoding where we only store the number of msb bits, that is the same for all slots
MsbZeroBitsCountOnly = 0,
/// Flexible encoding that allows to define any bit in any slot as being proven to be 0
AnyBitAnySlot = 1,
}
impl PkeV2ProvenZeroBitsEncoding {
pub fn encode_proven_zero_bits(
&self,
msb_zero_padding_bit_count: u64,
t: u64,
k: usize,
) -> Vec<u8> {
match self {
PkeV2ProvenZeroBitsEncoding::MsbZeroBitsCountOnly => {
msb_zero_padding_bit_count.to_le_bytes().to_vec()
}
PkeV2ProvenZeroBitsEncoding::AnyBitAnySlot => {
encode_proven_zero_bits_anybit_anyslot(msb_zero_padding_bit_count, t, k)
}
}
}
}
#[derive(Debug, Clone, Copy)]
/// The kind of norm bound that is hashed in the statement.
pub enum PkeV2HashedBoundType {
/// Hash the square of the derived L2/Euclidean norm that is used for the proof
SquaredEuclideanNorm = 0,
/// Hash the infinite norm given as input by the prover
InfinityNorm = 1,
}
#[derive(Debug, Clone, Copy)]
pub struct PkeV2HashConfig {
pub(crate) mode: PkeV2HashMode,
pub(crate) proven_zero_bits_encoding: PkeV2ProvenZeroBitsEncoding,
pub(crate) hashed_bound_type: PkeV2HashedBoundType,
/// Should we also hash the value of k with the statement
pub(crate) hash_k: bool,
}
impl PkeV2HashConfig {
pub fn mode(&self) -> PkeV2HashMode {
self.mode
}
pub fn proven_zero_bits_encoding(&self) -> PkeV2ProvenZeroBitsEncoding {
self.proven_zero_bits_encoding
}
pub fn hashed_bound(&self) -> PkeV2HashedBoundType {
self.hashed_bound_type
}
pub fn hash_k(&self) -> bool {
self.hash_k
}
}
/// List of hash config that were used for a given version of this crate
///
/// This is stored in the proof so that we only support a specific subset of all possible config.
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, Versionize)]
#[versionize(PkeV2SupportedHashConfigVersions)]
pub enum PkeV2SupportedHashConfig {
V0_4_0 = 0,
V0_7_0 = 1,
// Default hashing configuration used for proofs. This can be updated for performance or
// compliance reasons as long as we still handle the previous version for backward
// compatibility.
#[default]
V0_8_0 = 2,
}
const PKEV2_HASH_CONFIG_V0_4_0: PkeV2HashConfig = PkeV2HashConfig {
mode: PkeV2HashMode::BackwardCompat,
proven_zero_bits_encoding: PkeV2ProvenZeroBitsEncoding::MsbZeroBitsCountOnly,
hashed_bound_type: PkeV2HashedBoundType::SquaredEuclideanNorm,
hash_k: false,
};
const PKEV2_HASH_CONFIG_V0_7_0: PkeV2HashConfig = PkeV2HashConfig {
mode: PkeV2HashMode::Compact,
proven_zero_bits_encoding: PkeV2ProvenZeroBitsEncoding::MsbZeroBitsCountOnly,
hashed_bound_type: PkeV2HashedBoundType::SquaredEuclideanNorm,
hash_k: false,
};
const PKEV2_HASH_CONFIG_V0_8_0: PkeV2HashConfig = PkeV2HashConfig {
mode: PkeV2HashMode::Compact,
proven_zero_bits_encoding: PkeV2ProvenZeroBitsEncoding::AnyBitAnySlot,
hashed_bound_type: PkeV2HashedBoundType::InfinityNorm,
hash_k: true,
};
impl From<PkeV2SupportedHashConfig> for PkeV2HashConfig {
fn from(value: PkeV2SupportedHashConfig) -> Self {
match value {
PkeV2SupportedHashConfig::V0_4_0 => PKEV2_HASH_CONFIG_V0_4_0,
PkeV2SupportedHashConfig::V0_7_0 => PKEV2_HASH_CONFIG_V0_7_0,
PkeV2SupportedHashConfig::V0_8_0 => PKEV2_HASH_CONFIG_V0_8_0,
}
}
}
/// Encode the bits proven to be 0 in a plaintext list.
///
/// Today, the proof only allows to prove msb to be 0, and the same number of msb is used for every
/// slots. This function encodes the number of 0 bits in a more future proof way. This allows in the
/// future to prove any bit in any slot to be 0 without having to change the encoding.
///
/// For example, for a list of 6 elements, composed of 4 bits of plaintext that can take any value
/// and 1 bit of padding that is proven to be 0, we have:
/// -> k = 6, t = 2**5, msb_zero_padding_bit_count = 1
/// -> the base value to be encoded is 0b01111 (1 zero bit + 4 free bits). In lsb to msb this is
/// 11110.
/// -> By copying the base value in lsb to msb 6 times, we get the following bit string:
/// bit: 11110|11110|11110|11110|11110|11110
/// pos: 01234 56789 abcde f ...
/// -> that is decomposed in bytes:
/// bit: 11110111 10111101 11101111 01111000
/// pos: 01234567 89abcdef ...
/// -> in the usual msb to lsb notation, the resulting bytes are:
/// bit: 0b11101111 0b10111101 0b11110111 0b11110
/// pos: 76543210 fedcba98 ...
fn encode_proven_zero_bits_anybit_anyslot(
msb_zero_padding_bit_count: u64,
t: u64,
k: usize,
) -> Vec<u8> {
let t_log2 = t.ilog2();
assert!(msb_zero_padding_bit_count <= t_log2 as u64);
assert!(k < u32::MAX as usize);
let msb_zero_padding_bit_count = msb_zero_padding_bit_count as u32;
let k = k as u32;
let effective_t_log2 = t_log2 - msb_zero_padding_bit_count;
// true since t is a u64
assert!(effective_t_log2 <= 64);
// This is the base value that will be encoded for all slots. For example, for 4 bits of
// plaintext and one bit of padding proven to be 0, this will be 0b01111.
// This value is stored in a u64 to support plaintext + padding size > 8.
let encoded_base = if effective_t_log2 == 64 {
u64::MAX
} else {
!(u64::MAX << effective_t_log2)
};
let number_bits_to_pack = k * t_log2;
let packed_byte_len = number_bits_to_pack.div_ceil(u8::BITS);
let mut packed = Vec::with_capacity(packed_byte_len as usize);
// A temporary buffer of 128 bits that is used to store `encoded_base` + a remainder of at
// most 7 bits.
let mut bit_buffer: u128 = 0;
let mut bits_in_buffer = 0;
for _ in 0..k {
// Add new bits to the temporary buffer
bit_buffer |= (encoded_base as u128) << bits_in_buffer;
bits_in_buffer += t_log2;
// Dump the temporary buffer into the byte vec until there is less that a full byte left
while bits_in_buffer >= u8::BITS {
packed.push(bit_buffer as u8);
bit_buffer >>= u8::BITS;
bits_in_buffer -= u8::BITS;
}
}
if bits_in_buffer > 0 {
packed.push(bit_buffer as u8);
}
packed
}
impl PkeV2HashMode {
/// Generate a list of scalars using the hash random oracle. The generated hashes are written to
/// the `output` slice and a byte representation is returned
@@ -164,7 +349,7 @@ impl<'a> RHash<'a> {
C_hat_e_bytes: &'a [u8],
C_e_bytes: &'a [u8],
C_r_tilde_bytes: &'a [u8],
mode: PkeV2HashMode,
config: PkeV2HashConfig,
) -> (Box<[i8]>, Self) {
let (
&PublicParams {
@@ -196,12 +381,30 @@ impl<'a> RHash<'a> {
bound_type,
);
let encoded_zero_bits = config.proven_zero_bits_encoding.encode_proven_zero_bits(
msbs_zero_padding_bit_count,
t_input,
k,
);
let hashed_bound = match config.hashed_bound_type {
PkeV2HashedBoundType::SquaredEuclideanNorm => B_squared.to_le_bytes().to_vec(),
PkeV2HashedBoundType::InfinityNorm => B_inf.to_le_bytes().to_vec(),
};
let hashed_k = if config.hash_k {
(k as u64).to_le_bytes().to_vec()
} else {
Vec::new()
};
let x_bytes = [
q.to_le_bytes().as_slice(),
(d as u64).to_le_bytes().as_slice(),
B_squared.to_le_bytes().as_slice(),
hashed_k.as_slice(),
&hashed_bound,
t_input.to_le_bytes().as_slice(),
msbs_zero_padding_bit_count.to_le_bytes().as_slice(),
encoded_zero_bits.as_slice(),
&*a.iter()
.flat_map(|&x| x.to_le_bytes())
.collect::<Box<[_]>>(),
@@ -257,7 +460,7 @@ impl<'a> RHash<'a> {
})
.collect::<Box<[i8]>>();
let R_bytes = mode.encode_R(&R);
let R_bytes = config.mode.encode_R(&R);
(
R,
@@ -275,7 +478,7 @@ impl<'a> RHash<'a> {
n,
k,
d,
mode,
mode: config.mode,
},
R_bytes,
@@ -1177,3 +1380,31 @@ impl<'a> ZHash<'a> {
chi
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_proven_zero_bits_encoding() {
// Test the most common case
let res = encode_proven_zero_bits_anybit_anyslot(1, 1 << 5, 6);
// base value is 0b01111 (msb to lsb)
// -> 11110 * 6 (lsb to msb)
// -> 11110|11110|11110|11110|11110|11110 (lsb to msb)
// -> 11110111 10111101 11101111 01111000 (lsb to msb)
// -> 0b11101111 0b10111101 0b11110111 0b11110 (msb to lsb)
let expected = vec![0b11101111, 0b10111101, 0b11110111, 0b11110];
assert_eq!(expected, res);
// Test a case where plaintext modulus log is > 8
let res = encode_proven_zero_bits_anybit_anyslot(2, 1 << 9, 3);
// base value is 0b001111111 (msb to lsb)
// 111111100 * 3 (lsb to msb)
// 111111100|111111100|111111100 (lsb to msb)
// 11111110 01111111 00111111 10000000 (lsb to msb)
// 0b1111111, 0b11111110, 0b11111100, 0b1 (msb to lsb)
let expected = vec![0b1111111, 0b11111110, 0b11111100, 0b1];
assert_eq!(expected, res);
}
}

View File

@@ -20,7 +20,7 @@ mod hashes;
use hashes::RHash;
pub use hashes::PkeV2HashMode;
pub use hashes::*;
fn bit_iter(x: u64, nbits: u32) -> impl Iterator<Item = bool> {
(0..nbits).map(move |idx| ((x >> idx) & 1) != 0)
@@ -370,7 +370,7 @@ pub struct Proof<G: Curve> {
pub(crate) pi: G::G1,
pub(crate) pi_kzg: G::G1,
pub(crate) compute_load_proof_fields: Option<ComputeLoadProofFields<G>>,
pub(crate) hash_mode: PkeV2HashMode,
pub(crate) hash_config: PkeV2SupportedHashConfig,
}
impl<G: Curve> Proof<G> {
@@ -393,7 +393,7 @@ impl<G: Curve> Proof<G> {
pi,
pi_kzg,
ref compute_load_proof_fields,
hash_mode: _,
hash_config: _,
} = self;
C_hat_e.validate_projective()
@@ -421,8 +421,8 @@ impl<G: Curve> Proof<G> {
}
}
pub fn hash_mode(&self) -> PkeV2HashMode {
self.hash_mode
pub fn hash_config(&self) -> PkeV2SupportedHashConfig {
self.hash_config
}
}
@@ -471,7 +471,7 @@ where
pub(crate) pi: CompressedG1<G>,
pub(crate) pi_kzg: CompressedG1<G>,
pub(crate) compute_load_proof_fields: Option<CompressedComputeLoadProofFields<G>>,
pub(crate) hash_mode: PkeV2HashMode,
pub(crate) hash_config: PkeV2SupportedHashConfig,
}
#[derive(Serialize, Deserialize, Versionize)]
@@ -512,7 +512,7 @@ where
pi,
pi_kzg,
compute_load_proof_fields,
hash_mode,
hash_config,
} = self;
CompressedProof {
@@ -534,7 +534,7 @@ where
C_hat_w: C_hat_w.compress(),
},
),
hash_mode: *hash_mode,
hash_config: *hash_config,
}
}
@@ -552,7 +552,7 @@ where
pi,
pi_kzg,
compute_load_proof_fields,
hash_mode,
hash_config,
} = compressed;
Ok(Proof {
@@ -580,7 +580,7 @@ where
} else {
None
},
hash_mode,
hash_config,
})
}
}
@@ -831,7 +831,7 @@ pub fn prove<G: Curve>(
metadata,
load,
seed,
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Panic,
)
}
@@ -842,7 +842,7 @@ fn prove_impl<G: Curve>(
metadata: &[u8],
load: ComputeLoad,
seed: &[u8],
hash_mode: PkeV2HashMode,
hash_config: PkeV2SupportedHashConfig,
sanity_check_mode: ProofSanityCheckMode,
) -> Proof<G> {
_ = load;
@@ -864,6 +864,9 @@ fn prove_impl<G: Curve>(
},
PublicCommit { a, b, c1, c2, .. },
) = public;
let stored_hash_config = hash_config;
let hash_config = hash_config.into();
let g_list = &*g_lists.g_list.0;
let g_hat_list = &*g_lists.g_hat_list.0;
@@ -987,7 +990,7 @@ fn prove_impl<G: Curve>(
C_hat_e_bytes.as_ref(),
C_e_bytes.as_ref(),
C_r_tilde_bytes.as_ref(),
hash_mode,
hash_config,
);
let R = |i: usize, j: usize| R[i + j * 128];
@@ -1606,7 +1609,7 @@ fn prove_impl<G: Curve>(
pi,
pi_kzg,
compute_load_proof_fields,
hash_mode,
hash_config: stored_hash_config,
}
}
@@ -1743,8 +1746,9 @@ pub fn verify_impl<G: Curve>(
pi,
pi_kzg,
ref compute_load_proof_fields,
hash_mode,
hash_config,
} = proof;
let hash_config = hash_config.into();
let pairing = G::Gt::pairing;
@@ -1811,7 +1815,7 @@ pub fn verify_impl<G: Curve>(
C_hat_e_bytes.as_ref(),
C_e_bytes.as_ref(),
C_r_tilde_bytes.as_ref(),
hash_mode,
hash_config,
);
let R = |i: usize, j: usize| R[i + j * 128];
@@ -2342,14 +2346,17 @@ mod tests {
);
for load in [ComputeLoad::Proof, ComputeLoad::Verify] {
for hash_mode in [PkeV2HashMode::BackwardCompat, PkeV2HashMode::Classical] {
for hash_config in [
PkeV2SupportedHashConfig::V0_4_0,
PkeV2SupportedHashConfig::V0_7_0,
] {
let proof = prove_impl(
(&public_param, &public_commit),
&private_commit,
&testcase.metadata,
load,
&seed.to_le_bytes(),
hash_mode,
hash_config,
ProofSanityCheckMode::Panic,
);
@@ -2378,7 +2385,7 @@ mod tests {
crs: &PublicParams<Curve>,
load: ComputeLoad,
seed: &[u8],
hash_mode: PkeV2HashMode,
hash_config: PkeV2SupportedHashConfig,
sanity_check_mode: ProofSanityCheckMode,
) -> VerificationResult {
let (public_commit, private_commit) = commit(
@@ -2399,7 +2406,7 @@ mod tests {
&testcase.metadata,
load,
seed,
hash_mode,
hash_config,
sanity_check_mode,
);
@@ -2417,15 +2424,23 @@ mod tests {
testcase_name: &str,
crs: &PublicParams<Curve>,
seed: &[u8],
hash_mode: PkeV2HashMode,
hash_config: PkeV2SupportedHashConfig,
sanity_check_mode: ProofSanityCheckMode,
expected_result: VerificationResult,
) {
for load in [ComputeLoad::Proof, ComputeLoad::Verify] {
assert_eq!(
prove_and_verify(testcase, ct, crs, load, seed, hash_mode, sanity_check_mode),
prove_and_verify(
testcase,
ct,
crs,
load,
seed,
hash_config,
sanity_check_mode
),
expected_result,
"Testcase {testcase_name} {hash_mode:?} hash with load {load} failed"
"Testcase {testcase_name} {hash_config:?} hash with load {load} failed"
)
}
}
@@ -2691,7 +2706,7 @@ mod tests {
&format!("{name}_crs"),
&crs,
&seed.to_le_bytes(),
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Ignore,
expected_result,
);
@@ -2701,7 +2716,7 @@ mod tests {
&format!("{name}_crs_max_k"),
&crs_max_k,
&seed.to_le_bytes(),
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Ignore,
expected_result,
);
@@ -2795,7 +2810,7 @@ mod tests {
test_name,
&public_param,
&seed.to_le_bytes(),
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Panic,
VerificationResult::Reject,
);
@@ -3056,7 +3071,7 @@ mod tests {
"testcase_bad_delta",
&crs,
&seed.to_le_bytes(),
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Panic,
VerificationResult::Reject,
);
@@ -3098,7 +3113,7 @@ mod tests {
&format!("testcase_big_params_{bound:?}"),
&crs,
&seed.to_le_bytes(),
PkeV2HashMode::Compact,
PkeV2SupportedHashConfig::default(),
ProofSanityCheckMode::Panic,
VerificationResult::Accept,
);