mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-07 22:04:10 -05:00
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:
committed by
Nicolas Sarlin
parent
bcb1356b76
commit
b7fc208e40
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user