Skip to content

Commit 123bb05

Browse files
committed
more complex linear relations
1 parent c0cf76a commit 123bb05

File tree

2 files changed

+101
-2
lines changed

2 files changed

+101
-2
lines changed

src/tests/test_relations.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22

3+
use bls12_381::Scalar;
34
use ff::Field;
45
use group::prime::PrimeGroup;
56
use rand::rngs::OsRng;
@@ -51,8 +52,7 @@ pub fn shifted_dlog<G: PrimeGroup, R: RngCore>(
5152

5253
let var_X = relation.allocate_eq(var_G * var_x + var_G * <G::Scalar as Field>::ONE);
5354
// another way of writing this is:
54-
relation.append_equation(var_X, (var_x + <G::Scalar as Field>::ONE) * var_G);
55-
55+
relation.append_equation(var_X, (var_x + Scalar::from(1)) * var_G);
5656

5757
relation.set_element(var_G, G::generator());
5858
relation.compute_image(&[x]).unwrap();
@@ -144,6 +144,31 @@ pub fn pedersen_commitment<G: PrimeGroup, R: RngCore>(
144144
(instance, witness)
145145
}
146146

147+
#[allow(non_snake_case)]
148+
pub fn twisted_pedersen_commitment<G: PrimeGroup, R: RngCore>(
149+
rng: &mut R,
150+
) -> (CanonicalLinearRelation<G>, Vec<G::Scalar>) {
151+
let H = G::random(&mut *rng);
152+
let x = G::Scalar::random(&mut *rng);
153+
let r = G::Scalar::random(&mut *rng);
154+
let mut relation = LinearRelation::new();
155+
156+
let [var_x, var_r] = relation.allocate_scalars();
157+
let [var_G, var_H] = relation.allocate_elements();
158+
159+
let var_C = relation.allocate_eq((var_x * Scalar::from(3)) * var_G + (var_r * Scalar::from(2) + Scalar::from(3)) * var_H);
160+
161+
relation.set_elements([(var_H, H), (var_G, G::generator())]);
162+
relation.compute_image(&[x, r]).unwrap();
163+
164+
let C = relation.linear_map.group_elements.get(var_C).unwrap();
165+
166+
let witness = vec![x, r];
167+
assert_eq!(C, G::generator() * x + H * r);
168+
let instance = (&relation).try_into().unwrap();
169+
(instance, witness)
170+
}
171+
147172
/// LinearMap for knowledge of equal openings to two distinct Pedersen commitments.
148173
#[allow(non_snake_case)]
149174
pub fn pedersen_commitment_dleq<G: PrimeGroup, R: RngCore>(
@@ -181,6 +206,7 @@ pub fn pedersen_commitment_dleq<G: PrimeGroup, R: RngCore>(
181206
(instance, witness_vec)
182207
}
183208

209+
184210
/// LinearMap for knowledge of an opening for use in a BBS commitment.
185211
// BBS message length is 3
186212
#[allow(non_snake_case)]

src/tests/test_validation_criteria.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,12 @@ mod instance_validation {
186186
#[cfg(test)]
187187
mod proof_validation {
188188
use crate::codec::KeccakByteSchnorrCodec;
189+
use crate::composition::{ComposedRelation, ComposedWitness};
189190
use crate::fiat_shamir::Nizk;
190191
use crate::linear_relation::{CanonicalLinearRelation, LinearRelation};
191192
use crate::schnorr_protocol::SchnorrProof;
192193
use bls12_381::{G1Projective as G, Scalar};
194+
use ff::Field;
193195
use rand::{thread_rng, RngCore};
194196

195197
type TestNizk = Nizk<SchnorrProof<G>, KeccakByteSchnorrCodec<G>>;
@@ -359,4 +361,75 @@ mod proof_validation {
359361
"Proof verification should fail for random bytes"
360362
);
361363
}
364+
365+
#[test]
366+
fn test_or_relation_wrong_branch() {
367+
// This test reproduces the issue from sigma_compiler's simple_or test
368+
// where an OR relation fails verification when using the wrong branch
369+
let mut rng = thread_rng();
370+
371+
// Create generators
372+
// For this test, we'll use two different multiples of the generator
373+
let B = G::generator();
374+
let A = B * Scalar::from(42u64); // Different generator
375+
376+
// Create scalars
377+
let x = Scalar::random(&mut rng);
378+
let y = Scalar::random(&mut rng);
379+
380+
// Set C = y*B (so the second branch should be satisfied)
381+
let C = B * y;
382+
383+
// Create the first branch: C = x*A
384+
let mut lr1 = LinearRelation::<G>::new();
385+
let x_var = lr1.allocate_scalar();
386+
let A_var = lr1.allocate_element();
387+
let eq1 = lr1.allocate_eq(x_var * A_var);
388+
lr1.set_element(A_var, A);
389+
lr1.set_element(eq1, C);
390+
391+
// Create the second branch: C = y*B
392+
let mut lr2 = LinearRelation::<G>::new();
393+
let y_var = lr2.allocate_scalar();
394+
let B_var = lr2.allocate_element();
395+
let eq2 = lr2.allocate_eq(y_var * B_var);
396+
lr2.set_element(B_var, B);
397+
lr2.set_element(eq2, C);
398+
399+
// Create OR composition
400+
let or_relation = ComposedRelation::Or(vec![
401+
ComposedRelation::from(lr1),
402+
ComposedRelation::from(lr2),
403+
]);
404+
405+
// The issue from sigma_compiler: the witness is always using branch 0
406+
// even when branch 1 should be used
407+
let witness_wrong = ComposedWitness::Or(
408+
0, // Always using branch 0
409+
vec![
410+
ComposedWitness::Simple(vec![x]),
411+
ComposedWitness::Simple(vec![y]),
412+
],
413+
);
414+
415+
// Test the bug: using branch 0 when C = y*B (branch 1 should be used)
416+
let nizk = Nizk::<_, KeccakByteSchnorrCodec<G>>::new(b"test_or_bug", or_relation);
417+
let proof_result = nizk.prove_batchable(&witness_wrong, &mut rng);
418+
419+
// This currently passes but should fail - this is the bug!
420+
// The prover is using branch 0 (C = x*A) but C actually equals y*B
421+
match proof_result {
422+
Ok(proof) => {
423+
let verify_result = nizk.verify_batchable(&proof);
424+
println!("Bug reproduced: Proof with wrong branch verified: {:?}", verify_result.is_ok());
425+
assert!(
426+
verify_result.is_err(),
427+
"BUG: Proof should fail when using wrong branch in OR relation, but it passed!"
428+
);
429+
}
430+
Err(e) => {
431+
println!("Proof generation failed as expected: {:?}", e);
432+
}
433+
}
434+
}
362435
}

0 commit comments

Comments
 (0)