Skip to content

Commit 961c8a6

Browse files
authored
fix(examples): simpler composition (#37)
1 parent 608703d commit 961c8a6

File tree

4 files changed

+116
-90
lines changed

4 files changed

+116
-90
lines changed

examples/schnorr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use group::Group;
1212
use rand::rngs::OsRng;
1313

1414
use sigma_rs::errors::Error;
15-
use sigma_rs::{LinearRelation, NISigmaProtocol};
15+
use sigma_rs::LinearRelation;
1616

1717
type ProofResult<T> = Result<T, Error>;
1818

@@ -34,14 +34,14 @@ fn create_relation(P: RistrettoPoint) -> LinearRelation<RistrettoPoint> {
3434
/// generate a proof that P = x * G
3535
#[allow(non_snake_case)]
3636
fn prove(x: Scalar, P: RistrettoPoint) -> ProofResult<Vec<u8>> {
37-
let nizk: NISigmaProtocol<_, _> = create_relation(P).into();
37+
let nizk = create_relation(P).into_nizk(b"schnorr-proof");
3838
nizk.prove_batchable(&vec![x], &mut OsRng)
3939
}
4040

4141
/// Verify a proof of knowledge of discrete logarithm for the given public key P
4242
#[allow(non_snake_case)]
4343
fn verify(P: RistrettoPoint, proof: &[u8]) -> ProofResult<()> {
44-
let nizk: NISigmaProtocol<_, _> = create_relation(P).into();
44+
let nizk = create_relation(P).into_nizk(b"schnorr-proof");
4545
nizk.verify_batchable(proof)
4646
}
4747

examples/simple_composition.rs

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,72 +14,90 @@ use sigma_rs::{
1414
type G = RistrettoPoint;
1515
type ProofResult<T> = Result<T, Error>;
1616

17+
/// Create an OR relation between two statements:
18+
/// 1. Knowledge of discrete log: P1 = x1 * G
19+
/// 2. Knowledge of DLEQ: (P2 = x2 * G, Q = x2 * H)
1720
#[allow(non_snake_case)]
18-
pub fn discrete_logarithm(x: Scalar) -> (LinearRelation<G>, Vec<Scalar>) {
19-
let mut relation = LinearRelation::<G>::new();
20-
21-
let var_x = relation.allocate_scalar();
22-
let var_G = relation.allocate_element();
23-
let _var_X = relation.allocate_eq(var_x * var_G);
24-
25-
relation.set_element(var_G, G::generator());
26-
relation.compute_image(&[x]).unwrap();
27-
28-
(relation, vec![x])
29-
}
30-
31-
#[allow(non_snake_case)]
32-
pub fn dleq(x: Scalar, h: G) -> (LinearRelation<G>, Vec<Scalar>) {
33-
let mut relation = LinearRelation::<G>::new();
34-
35-
let var_x = relation.allocate_scalar();
36-
let [var_G, var_H] = relation.allocate_elements();
37-
let _var_X = relation.allocate_eq(var_x * var_G);
38-
let _var_Y = relation.allocate_eq(var_x * var_H);
39-
40-
relation.set_elements([(var_G, G::generator()), (var_H, h)]);
41-
relation.compute_image(&[x]).unwrap();
42-
43-
(relation, vec![x])
44-
}
45-
46-
fn create_or_relations(x1: Scalar, x2: Scalar, h: G) -> (Protocol<G>, ProtocolWitness<G>) {
47-
let (rel1, _) = discrete_logarithm(x1);
48-
let (rel2, witness2) = dleq(x2, h);
49-
21+
fn create_relation(P1: G, P2: G, Q: G, H: G) -> Protocol<G> {
22+
// First relation: discrete logarithm P1 = x1 * G
23+
let mut rel1 = LinearRelation::<G>::new();
24+
let x1 = rel1.allocate_scalar();
25+
let G1 = rel1.allocate_element();
26+
let P1_var = rel1.allocate_eq(x1 * G1);
27+
rel1.set_element(G1, G::generator());
28+
rel1.set_element(P1_var, P1);
29+
30+
// Second relation: DLEQ (P2 = x2 * G, Q = x2 * H)
31+
let mut rel2 = LinearRelation::<G>::new();
32+
let x2 = rel2.allocate_scalar();
33+
let G2 = rel2.allocate_element();
34+
let H_var = rel2.allocate_element();
35+
let P2_var = rel2.allocate_eq(x2 * G2);
36+
let Q_var = rel2.allocate_eq(x2 * H_var);
37+
rel2.set_element(G2, G::generator());
38+
rel2.set_element(H_var, H);
39+
rel2.set_element(P2_var, P2);
40+
rel2.set_element(Q_var, Q);
41+
42+
// Compose into OR protocol
5043
let proto1 = Protocol::from(rel1);
5144
let proto2 = Protocol::from(rel2);
52-
let composed = Protocol::Or(vec![proto1, proto2]);
53-
54-
let witness = ProtocolWitness::Or(1, vec![ProtocolWitness::Simple(witness2)]);
55-
56-
(composed, witness)
45+
Protocol::Or(vec![proto1, proto2])
5746
}
5847

59-
fn prove_or(x1: Scalar, x2: Scalar, h: G) -> ProofResult<Vec<u8>> {
48+
/// Prove knowledge of one of the witnesses (we know x2 for the DLEQ)
49+
#[allow(non_snake_case)]
50+
fn prove(P1: G, x2: Scalar, H: G) -> ProofResult<Vec<u8>> {
6051
let mut rng = OsRng;
61-
let (composed, witness) = create_or_relations(x1, x2, h);
62-
let nizk = NISigmaProtocol::<_, ShakeCodec<G>>::new(b"or_proof_example", composed);
52+
53+
// Compute public values
54+
let P2 = G::generator() * x2;
55+
let Q = H * x2;
56+
57+
let protocol = create_relation(P1, P2, Q, H);
58+
let witness = ProtocolWitness::Or(1, vec![ProtocolWitness::Simple(vec![x2])]);
59+
let nizk = NISigmaProtocol::<_, ShakeCodec<G>>::new(b"or_proof_example", protocol);
6360

6461
nizk.prove_batchable(&witness, &mut rng)
6562
}
6663

67-
fn verify_or(x1: Scalar, x2: Scalar, h: G, proof: &[u8]) -> ProofResult<()> {
68-
let (composed, _) = create_or_relations(x1, x2, h);
69-
let nizk = NISigmaProtocol::<_, ShakeCodec<G>>::new(b"or_proof_example", composed);
64+
/// Verify an OR proof given the public values
65+
#[allow(non_snake_case)]
66+
fn verify(P1: G, P2: G, Q: G, H: G, proof: &[u8]) -> ProofResult<()> {
67+
let protocol = create_relation(P1, P2, Q, H);
68+
let nizk = NISigmaProtocol::<_, ShakeCodec<G>>::new(b"or_proof_example", protocol);
7069

7170
nizk.verify_batchable(proof)
7271
}
7372

73+
#[allow(non_snake_case)]
7474
fn main() {
7575
let mut rng = OsRng;
76+
77+
// Setup: We don't know x1, but we do know x2
7678
let x1 = Scalar::random(&mut rng);
7779
let x2 = Scalar::random(&mut rng);
78-
let h = G::random(&mut rng);
79-
80-
let proof = prove_or(x1, x2, h).expect("Proof generation failed");
81-
let verified = verify_or(x1, x2, h, &proof).is_ok();
82-
83-
println!("OR-proof verified: {verified}");
84-
println!("Proof bytes: {}", hex::encode(&proof));
80+
let H = G::random(&mut rng);
81+
82+
// Compute public values
83+
let P1 = G::generator() * x1; // We don't actually know x1 in the proof
84+
let P2 = G::generator() * x2; // We know x2
85+
let Q = H * x2; // Q = x2 * H
86+
87+
println!("OR-proof example: Proving knowledge of x1 OR x2");
88+
println!("(We only know x2, not x1)");
89+
90+
match prove(P1, x2, H) {
91+
Ok(proof) => {
92+
println!("Proof generated successfully");
93+
println!("Proof (hex): {}", hex::encode(&proof));
94+
95+
// Verify the proof
96+
match verify(P1, P2, Q, H, &proof) {
97+
Ok(()) => println!("✓ Proof verified successfully!"),
98+
Err(e) => println!("✗ Proof verification failed: {:?}", e),
99+
}
100+
}
101+
Err(e) => println!("✗ Failed to generate proof: {:?}", e),
102+
}
85103
}

src/fiat_shamir.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -249,40 +249,3 @@ where
249249
self.verify(&commitment, &challenge, &response)
250250
}
251251
}
252-
253-
/// Convenience trait implementation to create a NIZK directly from a LinearRelation.
254-
impl<G> From<crate::linear_relation::LinearRelation<G>>
255-
for NISigmaProtocol<crate::schnorr_protocol::SchnorrProof<G>, crate::codec::ShakeCodec<G>>
256-
where
257-
G: group::Group + group::GroupEncoding,
258-
{
259-
/// Convert a LinearRelation into a non-interactive zero-knowledge protocol
260-
/// using the default ShakeCodec and a generic domain separator.
261-
///
262-
/// # Example
263-
/// ```
264-
/// # use sigma_rs::{LinearRelation, NISigmaProtocol};
265-
/// # use curve25519_dalek::RistrettoPoint as G;
266-
/// # use curve25519_dalek::scalar::Scalar;
267-
/// # use rand::rngs::OsRng;
268-
/// # use group::Group;
269-
///
270-
/// let mut relation = LinearRelation::<G>::new();
271-
/// let x_var = relation.allocate_scalar();
272-
/// let g_var = relation.allocate_element();
273-
/// let p_var = relation.allocate_eq(x_var * g_var);
274-
///
275-
/// relation.set_element(g_var, G::generator());
276-
/// let x = Scalar::random(&mut OsRng);
277-
/// relation.compute_image(&[x]).unwrap();
278-
///
279-
/// // Convert to NIZK using From trait
280-
/// let nizk: NISigmaProtocol<_, _> = relation.into();
281-
/// let proof = nizk.prove_batchable(&vec![x], &mut OsRng).unwrap();
282-
/// assert!(nizk.verify_batchable(&proof).is_ok());
283-
/// ```
284-
fn from(relation: crate::linear_relation::LinearRelation<G>) -> Self {
285-
let schnorr = crate::schnorr_protocol::SchnorrProof::from(relation);
286-
Self::new(b"sigma-rs-default", schnorr)
287-
}
288-
}

src/linear_relation/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,4 +510,49 @@ where
510510

511511
out
512512
}
513+
514+
/// Convert this LinearRelation into a non-interactive zero-knowledge protocol
515+
/// using the ShakeCodec and a specified context/domain separator.
516+
///
517+
/// # Parameters
518+
/// - `context`: Domain separator bytes for the Fiat-Shamir transform
519+
///
520+
/// # Returns
521+
/// A `NISigmaProtocol` instance ready for proving and verification
522+
///
523+
/// # Example
524+
/// ```
525+
/// # use sigma_rs::{LinearRelation, NISigmaProtocol};
526+
/// # use curve25519_dalek::RistrettoPoint as G;
527+
/// # use curve25519_dalek::scalar::Scalar;
528+
/// # use rand::rngs::OsRng;
529+
/// # use group::Group;
530+
///
531+
/// let mut relation = LinearRelation::<G>::new();
532+
/// let x_var = relation.allocate_scalar();
533+
/// let g_var = relation.allocate_element();
534+
/// let p_var = relation.allocate_eq(x_var * g_var);
535+
///
536+
/// relation.set_element(g_var, G::generator());
537+
/// let x = Scalar::random(&mut OsRng);
538+
/// relation.compute_image(&[x]).unwrap();
539+
///
540+
/// // Convert to NIZK with custom context
541+
/// let nizk = relation.into_nizk(b"my-protocol-v1");
542+
/// let proof = nizk.prove_batchable(&vec![x], &mut OsRng).unwrap();
543+
/// assert!(nizk.verify_batchable(&proof).is_ok());
544+
/// ```
545+
pub fn into_nizk(
546+
self,
547+
context: &[u8],
548+
) -> crate::fiat_shamir::NISigmaProtocol<
549+
crate::schnorr_protocol::SchnorrProof<G>,
550+
crate::codec::ShakeCodec<G>,
551+
>
552+
where
553+
G: group::GroupEncoding,
554+
{
555+
let schnorr = crate::schnorr_protocol::SchnorrProof::from(self);
556+
crate::fiat_shamir::NISigmaProtocol::new(context, schnorr)
557+
}
513558
}

0 commit comments

Comments
 (0)