Skip to main content

simple_composition/
simple_composition.rs

1//! OR-proof composition example.
2
3use curve25519_dalek::ristretto::RistrettoPoint;
4use curve25519_dalek::scalar::Scalar;
5use group::Group;
6use rand::rngs::OsRng;
7use sigma_proofs::{
8    composition::{ComposedRelation, ComposedWitness},
9    errors::Error,
10    LinearRelation,
11};
12
13type G = RistrettoPoint;
14type ProofResult<T> = Result<T, Error>;
15
16/// Create an OR relation between two statements:
17/// 1. Knowledge of discrete log: P1 = x1 * G
18/// 2. Knowledge of DLEQ: (P2 = x2 * G, Q = x2 * H)
19#[allow(non_snake_case)]
20fn create_relation(P1: G, P2: G, Q: G, H: G) -> ComposedRelation<G> {
21    // First relation: discrete logarithm P1 = x1 * G
22    let mut rel1 = LinearRelation::<G>::new();
23    let x1 = rel1.allocate_scalar();
24    let G1 = rel1.allocate_element();
25    let P1_var = rel1.allocate_eq(x1 * G1);
26    rel1.set_element(G1, G::generator());
27    rel1.set_element(P1_var, P1);
28
29    // Second relation: DLEQ (P2 = x2 * G, Q = x2 * H)
30    let mut rel2 = LinearRelation::<G>::new();
31    let x2 = rel2.allocate_scalar();
32    let G2 = rel2.allocate_element();
33    let H_var = rel2.allocate_element();
34    let P2_var = rel2.allocate_eq(x2 * G2);
35    let Q_var = rel2.allocate_eq(x2 * H_var);
36    rel2.set_element(G2, G::generator());
37    rel2.set_element(H_var, H);
38    rel2.set_element(P2_var, P2);
39    rel2.set_element(Q_var, Q);
40
41    // Compose into OR protocol
42    ComposedRelation::or([rel1.canonical().unwrap(), rel2.canonical().unwrap()])
43}
44
45/// Prove knowledge of one of the witnesses (we know x2 for the DLEQ)
46#[allow(non_snake_case)]
47fn prove(P1: G, x2: Scalar, H: G) -> ProofResult<Vec<u8>> {
48    // Compute public values
49    let P2 = G::generator() * x2;
50    let Q = H * x2;
51
52    let instance = create_relation(P1, P2, Q, H);
53    // Create OR witness with branch 1 being the real one (index 1)
54    let witness = ComposedWitness::Or(vec![
55        ComposedWitness::Simple(vec![Scalar::from(0u64)]),
56        ComposedWitness::Simple(vec![x2]),
57    ]);
58    let nizk = instance.into_nizk(b"or_proof_example");
59
60    nizk.prove_batchable(&witness, &mut OsRng)
61}
62
63/// Verify an OR proof given the public values
64#[allow(non_snake_case)]
65fn verify(P1: G, P2: G, Q: G, H: G, proof: &[u8]) -> ProofResult<()> {
66    let protocol = create_relation(P1, P2, Q, H);
67    let nizk = protocol.into_nizk(b"or_proof_example");
68
69    nizk.verify_batchable(proof)
70}
71
72#[allow(non_snake_case)]
73fn main() {
74    // Setup: We don't know x1, but we do know x2
75    let x1 = Scalar::random(&mut OsRng);
76    let x2 = Scalar::random(&mut OsRng);
77    let H = G::random(&mut OsRng);
78
79    // Compute public values
80    let P1 = G::generator() * x1; // We don't actually know x1 in the proof
81    let P2 = G::generator() * x2; // We know x2
82    let Q = H * x2; // Q = x2 * H
83
84    println!("OR-proof example: Proving knowledge of x1 OR x2");
85    println!("(We only know x2, not x1)");
86
87    match prove(P1, x2, H) {
88        Ok(proof) => {
89            println!("Proof generated successfully");
90            println!("Proof (hex): {}", hex::encode(&proof));
91
92            // Verify the proof
93            match verify(P1, P2, Q, H, &proof) {
94                Ok(()) => println!("✓ Proof verified successfully!"),
95                Err(e) => println!("✗ Proof verification failed: {e:?}"),
96            }
97        }
98        Err(e) => println!("✗ Failed to generate proof: {e:?}"),
99    }
100}