Skip to content

Commit 93335e2

Browse files
mmakerGOURIOU
andcommitted
Add test_validation_criterias.
This file is meant to check for edge cases in the instance as considered "valid" and in the proof as to be parsed and verified correctly. Related to PR #58. Co-Authored-By: GOURIOU <[email protected]>
1 parent 41fa258 commit 93335e2

File tree

4 files changed

+290
-2
lines changed

4 files changed

+290
-2
lines changed

src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ mod composition;
22
mod relations;
33
mod spec;
44
pub mod test_utils;
5+
mod test_validation_criterias;

src/tests/spec/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod bls12_381;
22
mod custom_schnorr_protocol;
33
mod random;
4-
mod rng;
4+
pub mod rng;
55

66
mod test_duplex_sponge;
77
mod test_vectors;

src/tests/spec/test_vectors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::tests::spec::{custom_schnorr_protocol::DeterministicSchnorrProof, rng
1212

1313
type SchnorrNizk = Nizk<DeterministicSchnorrProof<G>, KeccakByteSchnorrCodec<G>>;
1414

15-
1615
#[derive(Debug)]
1716
struct TestVector {
1817
ciphersuite: String,
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
//! Validation criteria tests for sigma protocols
2+
//!
3+
//! This module contains tests for validating both instances and proofs,
4+
//! ensuring that malformed inputs are properly rejected.
5+
6+
#[cfg(test)]
7+
mod instance_validation {
8+
use crate::errors::Error;
9+
use crate::linear_relation::{CanonicalLinearRelation, LinearRelation};
10+
use bls12_381::{G1Projective as G, Scalar};
11+
12+
#[test]
13+
fn test_unassigned_group_vars() {
14+
// Create a linear relation with unassigned group variables
15+
let mut relation = LinearRelation::<G>::new();
16+
17+
// Allocate scalars and elements
18+
let [var_x] = relation.allocate_scalars();
19+
let [var_g, var_x_g] = relation.allocate_elements::<2>();
20+
21+
// Set only one element, leaving var_g unassigned
22+
let x_val = G::generator() * Scalar::from(42u64);
23+
relation.set_elements([(var_x_g, x_val)]);
24+
25+
// Add equation: X = x * G (but G is not set)
26+
relation.append_equation(var_x_g, var_x * var_g);
27+
28+
// Try to convert to canonical form - should fail
29+
let result = CanonicalLinearRelation::try_from(&relation);
30+
assert!(result.is_err());
31+
assert!(matches!(
32+
result.unwrap_err(),
33+
Error::UnassignedGroupVar { .. }
34+
));
35+
}
36+
37+
#[test]
38+
fn test_zero_image_elements() {
39+
// Create a linear relation with zero elements in the image
40+
let mut relation = LinearRelation::<G>::new();
41+
42+
// Allocate scalars and elements
43+
let [var_x] = relation.allocate_scalars();
44+
let [var_g] = relation.allocate_elements::<1>();
45+
46+
// Set the group element
47+
relation.set_elements([(var_g, G::generator())]);
48+
49+
// Create an equation that results in zero (identity element)
50+
// This simulates a malformed relation where the image contains zero
51+
let zero_element = G::identity();
52+
let [var_zero] = relation.allocate_elements::<1>();
53+
relation.set_elements([(var_zero, zero_element)]);
54+
55+
// Add equation: 0 = x * G (which is invalid)
56+
relation.linear_map.linear_combinations.push(
57+
crate::linear_relation::LinearCombination::from(vec![(var_x, var_g)]),
58+
);
59+
relation.image.push(var_zero);
60+
61+
// Try to convert to canonical form
62+
let result = CanonicalLinearRelation::try_from(&relation);
63+
64+
// The conversion might succeed, but we should verify the image contains zero
65+
if let Ok(canonical) = result {
66+
assert!(canonical.image.iter().any(|&elem| elem == G::identity()));
67+
}
68+
}
69+
70+
#[test]
71+
fn test_empty_instance() {
72+
// Create an empty linear relation
73+
let relation = LinearRelation::<G>::new();
74+
75+
// Try to convert empty relation to canonical form
76+
let result = CanonicalLinearRelation::try_from(&relation);
77+
78+
// Empty relations should be rejected
79+
assert!(result.is_err());
80+
}
81+
82+
#[test]
83+
fn test_inconsistent_equation_count() {
84+
// Create a relation with mismatched equations and image elements
85+
let mut relation = LinearRelation::<G>::new();
86+
87+
// Allocate elements
88+
let [var_x] = relation.allocate_scalars();
89+
let [var_g, var_h] = relation.allocate_elements::<2>();
90+
91+
// Set elements
92+
relation.set_elements([
93+
(var_g, G::generator()),
94+
(var_h, G::generator() * Scalar::from(2u64)),
95+
]);
96+
97+
// Add two equations but only one image element
98+
relation.linear_map.linear_combinations.push(
99+
crate::linear_relation::LinearCombination::from(vec![(var_x, var_g)]),
100+
);
101+
relation.linear_map.linear_combinations.push(
102+
crate::linear_relation::LinearCombination::from(vec![(var_x, var_h)]),
103+
);
104+
relation.image.push(var_g); // Only one image element for two equations
105+
106+
// Try to convert - should fail due to inconsistency
107+
let result = CanonicalLinearRelation::try_from(&relation);
108+
assert!(result.is_err());
109+
}
110+
}
111+
112+
#[cfg(test)]
113+
mod proof_validation {
114+
use crate::codec::KeccakByteSchnorrCodec;
115+
use crate::fiat_shamir::Nizk;
116+
use crate::linear_relation::{CanonicalLinearRelation, LinearRelation};
117+
use crate::schnorr_protocol::SchnorrProof;
118+
use bls12_381::{G1Projective as G, Scalar};
119+
use rand::{thread_rng, RngCore};
120+
121+
type TestNizk = Nizk<SchnorrProof<G>, KeccakByteSchnorrCodec<G>>;
122+
123+
/// Helper function to create a simple discrete log proof
124+
fn create_valid_proof() -> (Vec<u8>, TestNizk) {
125+
let mut rng = thread_rng();
126+
127+
// Create a simple discrete log relation
128+
let mut relation = LinearRelation::<G>::new();
129+
let [var_x] = relation.allocate_scalars();
130+
let [var_g, var_x_g] = relation.allocate_elements::<2>();
131+
132+
let x = Scalar::from(42u64);
133+
let x_g = G::generator() * x;
134+
135+
relation.set_elements([(var_g, G::generator()), (var_x_g, x_g)]);
136+
relation.append_equation(var_x_g, var_x * var_g);
137+
138+
let canonical = CanonicalLinearRelation::try_from(&relation).unwrap();
139+
let protocol = SchnorrProof(canonical);
140+
let nizk = TestNizk::new(b"test_session", protocol);
141+
142+
let witness = vec![x];
143+
let proof = nizk.prove_batchable(&witness, &mut rng).unwrap();
144+
145+
(proof, nizk)
146+
}
147+
148+
#[test]
149+
fn test_proof_bitflip() {
150+
let (mut proof, nizk) = create_valid_proof();
151+
152+
// Verify the original proof is valid
153+
assert!(nizk.verify_batchable(&proof).is_ok());
154+
155+
// Test bitflips at various positions
156+
let positions = [0, proof.len() / 2, proof.len() - 1];
157+
158+
for &pos in &positions {
159+
let original_byte = proof[pos];
160+
161+
// Flip each bit in the byte
162+
for bit in 0..8 {
163+
proof[pos] = original_byte ^ (1 << bit);
164+
165+
// Verification should fail
166+
assert!(
167+
nizk.verify_batchable(&proof).is_err(),
168+
"Proof verification should fail with bit {} flipped at position {}",
169+
bit,
170+
pos
171+
);
172+
173+
// Restore original byte
174+
proof[pos] = original_byte;
175+
}
176+
}
177+
}
178+
179+
#[test]
180+
fn test_proof_append_bytes() {
181+
let (mut proof, nizk) = create_valid_proof();
182+
183+
// Verify the original proof is valid
184+
assert!(nizk.verify_batchable(&proof).is_ok());
185+
186+
// Test appending various amounts of bytes
187+
let append_sizes = [1, 8, 32, 100];
188+
189+
for &size in &append_sizes {
190+
let original_len = proof.len();
191+
192+
// Append random bytes
193+
let mut rng = thread_rng();
194+
let mut extra_bytes = vec![0u8; size];
195+
rng.fill_bytes(&mut extra_bytes);
196+
proof.extend_from_slice(&extra_bytes);
197+
198+
// Verification should fail
199+
assert!(
200+
nizk.verify_batchable(&proof).is_err(),
201+
"Proof verification should fail with {} bytes appended",
202+
size
203+
);
204+
205+
// Restore original proof
206+
proof.truncate(original_len);
207+
}
208+
}
209+
210+
#[test]
211+
fn test_proof_prepend_bytes() {
212+
let (proof, nizk) = create_valid_proof();
213+
214+
// Verify the original proof is valid
215+
assert!(nizk.verify_batchable(&proof).is_ok());
216+
217+
// Test prepending various amounts of bytes
218+
let prepend_sizes = [1, 8, 32, 100];
219+
220+
for &size in &prepend_sizes {
221+
// Create new proof with prepended bytes
222+
let mut rng = thread_rng();
223+
let mut prepended_proof = vec![0u8; size];
224+
rng.fill_bytes(&mut prepended_proof);
225+
prepended_proof.extend_from_slice(&proof);
226+
227+
// Verification should fail
228+
assert!(
229+
nizk.verify_batchable(&prepended_proof).is_err(),
230+
"Proof verification should fail with {} bytes prepended",
231+
size
232+
);
233+
}
234+
}
235+
236+
#[test]
237+
fn test_proof_truncation() {
238+
let (proof, nizk) = create_valid_proof();
239+
240+
// Verify the original proof is valid
241+
assert!(nizk.verify_batchable(&proof).is_ok());
242+
243+
// Test truncating various amounts
244+
let truncate_sizes = [1, 8, proof.len() / 2, proof.len() - 1];
245+
246+
for &size in &truncate_sizes {
247+
if size < proof.len() {
248+
let truncated_proof = &proof[..proof.len() - size];
249+
250+
// Verification should fail
251+
assert!(
252+
nizk.verify_batchable(truncated_proof).is_err(),
253+
"Proof verification should fail with {} bytes truncated",
254+
size
255+
);
256+
}
257+
}
258+
}
259+
260+
#[test]
261+
fn test_empty_proof() {
262+
let (_, nizk) = create_valid_proof();
263+
let empty_proof = vec![];
264+
265+
// Verification should fail for empty proof
266+
assert!(
267+
nizk.verify_batchable(&empty_proof).is_err(),
268+
"Proof verification should fail for empty proof"
269+
);
270+
}
271+
272+
#[test]
273+
fn test_random_bytes_as_proof() {
274+
let (valid_proof, nizk) = create_valid_proof();
275+
let proof_len = valid_proof.len();
276+
277+
// Test with completely random bytes of the same length
278+
let mut rng = thread_rng();
279+
let mut random_proof = vec![0u8; proof_len];
280+
rng.fill_bytes(&mut random_proof);
281+
282+
// Verification should fail
283+
assert!(
284+
nizk.verify_batchable(&random_proof).is_err(),
285+
"Proof verification should fail for random bytes"
286+
);
287+
}
288+
}

0 commit comments

Comments
 (0)