Skip to content

Commit 4ebf8d8

Browse files
committed
fix(schnorr): support nonlinear relations in simulate_commitment and add related test
- Fixed the `SchnorrProof::simulate_commitment` method to correctly handle nonlinear relations during simulation, ensuring compliance with the protocol’s expected behavior. - Added a dedicated test (`translated_discrete_logarithm`) to validate simulation and verification in the presence of nonlinear constraints. These changes improve protocol correctness and strengthen test coverage for complex use cases.
1 parent 916c372 commit 4ebf8d8

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

src/schnorr_protocol.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,16 @@ where
324324
return Err(Error::InvalidInstanceWitnessPair);
325325
}
326326

327+
let zero_vec = vec![<<G as Group>::Scalar as Field>::ZERO; self.0.linear_map.num_scalars];
328+
let zero_image = self.0.linear_map.evaluate(&zero_vec)?;
327329
let response_image = self.0.linear_map.evaluate(response)?;
328330
let image = self.0.image()?;
329331

330332
let commitment = response_image
331333
.iter()
332334
.zip(&image)
333-
.map(|(res, img)| *res - *img * challenge)
335+
.zip(&zero_image)
336+
.map(|((res, img), z_img)| *res - (*img - *z_img) * challenge)
334337
.collect::<Vec<_>>();
335338
Ok(commitment)
336339
}

src/tests/relations.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rand::rngs::OsRng;
55
use crate::fiat_shamir::NISigmaProtocol;
66
use crate::tests::test_utils::{
77
bbs_blind_commitment_computation, discrete_logarithm, dleq, pedersen_commitment,
8-
pedersen_commitment_dleq,
8+
pedersen_commitment_dleq, translated_discrete_logarithm,
99
};
1010
use crate::{codec::ShakeCodec, schnorr_protocol::SchnorrProof};
1111

@@ -17,6 +17,12 @@ fn test_discrete_logarithm() {
1717
discrete_logarithm::<G>(Scalar::random(&mut rng));
1818
}
1919

20+
#[test]
21+
fn test_translated_discrete_logarithm() {
22+
let mut rng = OsRng;
23+
translated_discrete_logarithm::<G>(Scalar::random(&mut rng));
24+
}
25+
2026
#[test]
2127
fn test_dleq() {
2228
let mut rng = OsRng;
@@ -97,6 +103,33 @@ fn noninteractive_discrete_logarithm() {
97103
);
98104
}
99105

106+
#[test]
107+
fn noninteractive_translated_discrete_logarithm() {
108+
let mut rng = OsRng;
109+
let (relation, witness) = translated_discrete_logarithm(Scalar::random(&mut rng));
110+
111+
// The SigmaProtocol induced by relation
112+
let protocol = SchnorrProof::from(relation);
113+
// Fiat-Shamir wrapper
114+
let domain_sep = b"test-fiat-shamir-schnorr";
115+
let nizk = NISigmaProtocol::<SchnorrProof<G>, ShakeCodec<G>>::new(domain_sep, protocol);
116+
117+
// Batchable and compact proofs
118+
let proof_batchable_bytes = nizk.prove_batchable(&witness, &mut rng).unwrap();
119+
let proof_compact_bytes = nizk.prove_compact(&witness, &mut rng).unwrap();
120+
// Verify proofs
121+
let verified_batchable = nizk.verify_batchable(&proof_batchable_bytes).is_ok();
122+
let verified_compact = nizk.verify_compact(&proof_compact_bytes).is_ok();
123+
assert!(
124+
verified_batchable,
125+
"Fiat-Shamir Schnorr proof verification failed"
126+
);
127+
assert!(
128+
verified_compact,
129+
"Fiat-Shamir Schnorr proof verification failed"
130+
);
131+
}
132+
100133
#[test]
101134
fn noninteractive_dleq() {
102135
let mut rng = OsRng;

src/tests/test_utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Definitions used in tests for this crate.
22
3+
use ff::Field;
34
use group::{Group, GroupEncoding};
45

56
use crate::linear_relation::{msm_pr, LinearRelation};
@@ -25,6 +26,27 @@ pub fn discrete_logarithm<G: Group + GroupEncoding>(
2526
(relation, vec![x])
2627
}
2728

29+
/// LinearMap for knowledge of a translated discrete logarithm relative to a fixed basepoint.
30+
#[allow(non_snake_case)]
31+
pub fn translated_discrete_logarithm<G: Group + GroupEncoding>(
32+
x: G::Scalar,
33+
) -> (LinearRelation<G>, Vec<G::Scalar>) {
34+
let mut relation: LinearRelation<G> = LinearRelation::new();
35+
36+
let var_x = relation.allocate_scalar();
37+
let var_G = relation.allocate_element();
38+
39+
let var_X = relation.allocate_eq((var_x + <<G as Group>::Scalar as Field>::ONE) * var_G);
40+
41+
relation.set_element(var_G, G::generator());
42+
relation.compute_image(&[x]).unwrap();
43+
44+
let X = relation.linear_map.group_elements.get(var_X).unwrap();
45+
46+
assert!(vec![X] == relation.linear_map.evaluate(&[x]).unwrap());
47+
(relation, vec![x])
48+
}
49+
2850
/// LinearMap for knowledge of a discrete logarithm equality between two pairs.
2951
#[allow(non_snake_case)]
3052
pub fn dleq<G: Group + GroupEncoding>(H: G, x: G::Scalar) -> (LinearRelation<G>, Vec<G::Scalar>) {

0 commit comments

Comments
 (0)