chore(zk): check that crs group element at index n is 0

This commit is contained in:
Nicolas Sarlin
2025-05-13 12:39:20 +02:00
committed by Nicolas Sarlin
parent 9ee8259002
commit 786fe66495
5 changed files with 60 additions and 4 deletions

View File

@@ -97,6 +97,7 @@ pub trait CurveGroupOps<Zp>:
+ core::ops::Sub<Self, Output = Self>
+ core::ops::Neg<Output = Self>
+ core::iter::Sum
+ PartialEq
{
const ZERO: Self;
const GENERATOR: Self;

View File

@@ -124,7 +124,14 @@ impl<G: Curve> GroupElements<G> {
}
/// Check if the elements are valid for their respective groups
pub fn is_valid(&self) -> bool {
pub fn is_valid(&self, n: usize) -> bool {
if self.g_list.0.len() != n * 2
|| self.g_hat_list.0.len() != n
|| G::G1::projective(self.g_list[n + 1]) != G::G1::ZERO
{
return false;
}
let (g_list_valid, g_hat_list_valid) = rayon::join(
|| self.g_list.0.par_iter().all(G::G1::validate_affine),
|| self.g_hat_list.0.par_iter().all(G::G2::validate_affine),

View File

@@ -189,7 +189,7 @@ impl<G: Curve> PublicParams<G> {
/// - valid points of the curve
/// - in the correct subgroup
pub fn is_usable(&self) -> bool {
self.g_lists.is_valid()
self.g_lists.is_valid(self.n)
}
}

View File

@@ -139,8 +139,16 @@ where
hash_z,
hash_chi,
} = compressed;
let uncompressed_g_lists = GroupElements::uncompress(g_lists)?;
if G::G1::projective(uncompressed_g_lists.g_list[n + 1]) != G::G1::ZERO {
return Err(InvalidSerializedPublicParamsError::InvalidGroupElements(
InvalidSerializedGroupElementsError::MissingPuncteredElement,
));
}
Ok(Self {
g_lists: GroupElements::uncompress(g_lists)?,
g_lists: uncompressed_g_lists,
D,
n,
d,
@@ -166,6 +174,8 @@ where
}
impl<G: Curve> PublicParams<G> {
/// Builds a crs from raw elements. When the elements are received from an untrusted party, the
/// resulting crs should be validated with [`Self::is_usable`]
#[allow(clippy::too_many_arguments)]
pub fn from_vec(
g_list: Vec<Affine<G::Zp, G::G1>>,
@@ -227,8 +237,9 @@ impl<G: Curve> PublicParams<G> {
/// This means checking that the points are:
/// - valid points of the curve
/// - in the correct subgroup
/// - the size of the list is correct and the element at index n is 0
pub fn is_usable(&self) -> bool {
self.g_lists.is_valid()
self.g_lists.is_valid(self.n)
}
}
@@ -775,6 +786,7 @@ fn prove_impl<G: Curve>(
B_squared >= e_sqr_norm,
"squared norm of error ({e_sqr_norm}) exceeds threshold ({B_squared})",
);
assert_eq!(G::G1::projective(g_list[n]), G::G1::ZERO);
}
// FIXME: div_round
@@ -3290,6 +3302,37 @@ mod tests {
}
}
/// Test the `is_usable` method, that checks the correctness of the the crs
#[test]
fn test_crs_usable() {
let PkeTestParameters {
d,
k,
B,
q,
t,
msbs_zero_padding_bit_count,
} = PKEV2_TEST_PARAMS;
let rng = &mut StdRng::seed_from_u64(0);
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
let public_param = crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
assert!(public_param.is_usable());
let public_param_that_was_compressed =
serialize_then_deserialize(&public_param, Compress::Yes).unwrap();
assert!(public_param_that_was_compressed.is_usable());
let mut bad_crs = public_param.clone();
bad_crs.g_lists.g_list[public_param.n + 1] = bad_crs.g_lists.g_list[public_param.n];
assert!(!bad_crs.is_usable());
}
/// Test the `is_usable` method, that checks the correctness of the EC points in the proof
#[test]
fn test_proof_usable() {

View File

@@ -256,6 +256,7 @@ pub(crate) type SerializableFp12 = SerializableQuadExtField<SerializableFp6>;
pub enum InvalidSerializedGroupElementsError {
InvalidAffine(InvalidSerializedAffineError),
InvalidGlistDimension(InvalidArraySizeError),
MissingPuncteredElement,
}
impl Display for InvalidSerializedGroupElementsError {
@@ -267,6 +268,9 @@ impl Display for InvalidSerializedGroupElementsError {
InvalidSerializedGroupElementsError::InvalidGlistDimension(arr_error) => {
write!(f, "invalid number of elements in g_list: {arr_error}")
}
InvalidSerializedGroupElementsError::MissingPuncteredElement => {
write!(f, "Element at index n in g_list should be 0")
}
}
}
}
@@ -278,6 +282,7 @@ impl Error for InvalidSerializedGroupElementsError {
InvalidSerializedGroupElementsError::InvalidGlistDimension(arr_error) => {
Some(arr_error)
}
InvalidSerializedGroupElementsError::MissingPuncteredElement => None,
}
}
}