Skip to content

Commit d49612a

Browse files
committed
fix: change validation criteria for identity elements.
Trivial relations that can be checked manually upon converting LinearRelation into CanonicalLinearRelation can have 0 in the image.
1 parent fe4d419 commit d49612a

File tree

2 files changed

+43
-40
lines changed

2 files changed

+43
-40
lines changed

src/linear_relation/canonical.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,6 @@ impl<G: PrimeGroup> TryFrom<&LinearRelation<G>> for CanonicalLinearRelation<G> {
352352
));
353353
}
354354

355-
if !relation
356-
.image()
357-
.is_ok_and(|img| img.iter().all(|&x| x != G::identity()))
358-
{
359-
return Err(InvalidInstance::new("Image contains identity element"));
360-
}
361-
362355
let mut canonical = CanonicalLinearRelation::new();
363356
canonical.num_scalars = relation.linear_map.num_scalars;
364357

@@ -367,17 +360,19 @@ impl<G: PrimeGroup> TryFrom<&LinearRelation<G>> for CanonicalLinearRelation<G> {
367360

368361
// Process each constraint using the modular helper method
369362
for (lhs, rhs) in iter::zip(&relation.image, &relation.linear_map.linear_combinations) {
363+
364+
let lhs_value = relation
365+
.linear_map
366+
.group_elements
367+
.get(*lhs)
368+
.map_err(|_| InvalidInstance::new("Unassigned group variable in image"))?;
369+
370370
// If the linear combination is trivial, check it directly and skip processing.
371371
if rhs
372372
.0
373373
.iter()
374374
.all(|weighted| matches!(weighted.term.scalar, ScalarTerm::Unit))
375375
{
376-
let lhs_value = relation
377-
.linear_map
378-
.group_elements
379-
.get(*lhs)
380-
.map_err(|_| InvalidInstance::new("Unassigned group variable in image"))?;
381376

382377
let rhs_value = rhs.0.iter().fold(G::identity(), |acc, weighted| {
383378
acc + relation
@@ -398,6 +393,10 @@ impl<G: PrimeGroup> TryFrom<&LinearRelation<G>> for CanonicalLinearRelation<G> {
398393
}
399394
}
400395

396+
if lhs_value == G::identity() {
397+
return Err(InvalidInstance::new("Image contains identity element"));
398+
}
399+
401400
canonical.process_constraint(lhs, rhs, relation, &mut weighted_group_cache)?;
402401
}
403402

src/tests/test_validation_criteria.rs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,27 @@ mod instance_validation {
3030
}
3131

3232
#[test]
33-
fn test_zero_image_elements() {
33+
fn test_zero_image() {
3434
// Create a linear relation with zero elements in the image
35+
// 0 = x * G (which is invalid)
3536
let mut relation = LinearRelation::<G>::new();
36-
37-
// Allocate scalars and elements
3837
let [var_x] = relation.allocate_scalars();
39-
let [var_g] = relation.allocate_elements::<1>();
40-
41-
// Set the group element
42-
relation.set_elements([(var_g, G::generator())]);
43-
44-
// Create an equation that results in zero (identity element)
45-
// This simulates a malformed relation where the image contains zero
46-
let zero_element = G::identity();
47-
let [var_zero] = relation.allocate_elements::<1>();
48-
relation.set_elements([(var_zero, zero_element)]);
49-
50-
// Add equation: 0 = x * G (which is invalid)
51-
relation.linear_map.linear_combinations.push(
52-
crate::linear_relation::LinearCombination::from(vec![(var_x, var_g)]),
53-
);
54-
relation.image.push(var_zero);
38+
let [var_G] = relation.allocate_elements();
39+
let var_X = relation.allocate_eq(var_G * var_x);
40+
relation.set_element(var_G, G::generator());
41+
relation.set_element(var_X, G::identity());
42+
let result = CanonicalLinearRelation::try_from(&relation);
43+
assert!(result.is_err());
5544

56-
// Try to convert to canonical form
45+
// Create a trivially valid linear relation with zero elements in the image
46+
// 0 = 0*B (which is invalid)
47+
let mut relation = LinearRelation::<G>::new();
48+
let [var_B] = relation.allocate_elements();
49+
let var_X = relation.allocate_eq(var_B * Scalar::from(0));
50+
relation.set_element(var_B, G::generator());
51+
relation.set_element(var_X, G::identity());
5752
let result = CanonicalLinearRelation::try_from(&relation);
58-
assert!(result.is_err())
53+
assert!(result.is_ok());
5954
}
6055

6156
#[test]
@@ -64,19 +59,20 @@ mod instance_validation {
6459
use ff::Field;
6560

6661
// This relation should fail for two reasons:
67-
// 1. because B is not assigned
62+
// 1. because var_B is not assigned
6863
let mut relation = LinearRelation::<G>::new();
6964
let x = relation.allocate_scalar();
70-
let B = relation.allocate_element();
71-
let _eq = relation.allocate_eq((x + (-Scalar::ONE)) * B + (-B));
65+
let var_B = relation.allocate_element();
66+
let var_X = relation.allocate_eq((x + (-Scalar::ONE)) * var_B + (-var_B));
67+
relation.set_element(var_X, G::identity());
7268
assert!(CanonicalLinearRelation::try_from(&relation).is_err());
7369

74-
// 2. because the equation is void
70+
// 2. because var_X is not assigned
7571
let mut relation = LinearRelation::<G>::new();
7672
let x = relation.allocate_scalar();
77-
let B = relation.allocate_element();
78-
let _eq = relation.allocate_eq((x + (-Scalar::ONE)) * B + (-B));
79-
relation.set_element(B, G::generator());
73+
let var_B = relation.allocate_element();
74+
let _var_X = relation.allocate_eq((x + (-Scalar::ONE)) * var_B + (-var_B));
75+
relation.set_element(var_B, G::generator());
8076
assert!(CanonicalLinearRelation::try_from(&relation).is_err());
8177
}
8278

@@ -110,6 +106,14 @@ mod instance_validation {
110106
let nizk = relation.into_nizk(b"test_session").unwrap();
111107
let narg_string = nizk.prove_batchable(&vec![], rng).unwrap();
112108
assert!(narg_string.is_empty());
109+
110+
111+
let mut relation = LinearRelation::<G>::new();
112+
let var_B = relation.allocate_element();
113+
let var_C = relation.allocate_eq(var_B * Scalar::from(1));
114+
relation.set_element(var_B, G::generator());
115+
relation.set_element(var_C, G::generator());
116+
assert!(CanonicalLinearRelation::try_from(&relation).is_ok());
113117
}
114118

115119
#[test]

0 commit comments

Comments
 (0)