Skip to content

Commit adb589d

Browse files
committed
refactor: simulator for sigma protocols.
1 parent 7a9e575 commit adb589d

File tree

5 files changed

+117
-141
lines changed

5 files changed

+117
-141
lines changed

src/composition.rs

Lines changed: 44 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,20 @@ impl<G: Group + GroupEncoding> SigmaProtocol for Protocol<G> {
129129
))
130130
}
131131
(Protocol::Or(ps), ProtocolWitness::Or(w_index, w)) => {
132-
let mut commitments = Vec::with_capacity(ps.len());
132+
let mut commitments = Vec::new();
133133
let mut simulated_challenges = Vec::new();
134134
let mut simulated_responses = Vec::new();
135-
let (real_commit, real_state) = ps[*w_index].prover_commit(&w[0], rng)?;
136-
for (i, _) in ps.iter().enumerate() {
137-
if i != *w_index {
138-
let (c, ch, r) = ps[i].simulate_transcript(rng);
139-
commitments.push(c);
140-
simulated_challenges.push(ch);
141-
simulated_responses.push(r);
142-
} else {
143-
commitments.push(real_commit.clone());
144-
}
135+
136+
let (real_commitment, real_state) = ps[*w_index].prover_commit(&w[0], rng)?;
137+
138+
for i in (0..ps.len()).filter(|i| i != w_index) {
139+
let (commitment, challenge, response) = ps[i].simulate_transcript(rng)?;
140+
commitments.push(commitment);
141+
simulated_challenges.push(challenge);
142+
simulated_responses.push(response);
145143
}
144+
commitments.insert(*w_index, real_commitment);
145+
146146
Ok((
147147
ProtocolCommitment::Or(commitments),
148148
ProtocolProverState::Or(
@@ -152,7 +152,7 @@ impl<G: Group + GroupEncoding> SigmaProtocol for Protocol<G> {
152152
),
153153
))
154154
}
155-
_ => panic!(),
155+
_ => unreachable!(),
156156
}
157157
}
158158

@@ -423,7 +423,9 @@ impl<G: Group + GroupEncoding> SigmaProtocol for Protocol<G> {
423423
}
424424
}
425425
}
426+
}
426427

428+
impl<G: Group + GroupEncoding> SigmaProtocolSimulator for Protocol<G> {
427429
fn simulate_commitment(
428430
&self,
429431
challenge: &Self::Challenge,
@@ -450,107 +452,75 @@ impl<G: Group + GroupEncoding> SigmaProtocol for Protocol<G> {
450452
_ => panic!(),
451453
}
452454
}
453-
}
454455

455-
impl<G: Group + GroupEncoding> SigmaProtocolSimulator for Protocol<G> {
456-
fn simulate_proof(
457-
&self,
458-
challenge: &Self::Challenge,
459-
rng: &mut (impl rand::Rng + rand::CryptoRng),
460-
) -> (Self::Commitment, Self::Response) {
456+
fn simulate_response<R: rand::Rng + rand::CryptoRng>(&self, rng: &mut R) -> Self::Response {
461457
match self {
462-
Protocol::Simple(p) => {
463-
let (c, r) = p.simulate_proof(challenge, rng);
464-
(ProtocolCommitment::Simple(c), ProtocolResponse::Simple(r))
465-
}
458+
Protocol::Simple(p) => ProtocolResponse::Simple(p.simulate_response(rng)),
466459
Protocol::And(ps) => {
467-
let mut commitments = Vec::with_capacity(ps.len());
468-
let mut responses = Vec::with_capacity(ps.len());
469-
470-
for p in ps.iter() {
471-
let (c, r) = p.simulate_proof(challenge, rng);
472-
commitments.push(c);
473-
responses.push(r);
474-
}
475-
(
476-
ProtocolCommitment::And(commitments),
477-
ProtocolResponse::And(responses),
478-
)
460+
ProtocolResponse::And(ps.iter().map(|p| p.simulate_response(rng)).collect())
479461
}
480462
Protocol::Or(ps) => {
481-
let mut commitments = Vec::with_capacity(ps.len());
482-
let mut challenges = Vec::new();
463+
let mut challenges = Vec::with_capacity(ps.len());
483464
let mut responses = Vec::with_capacity(ps.len());
484-
485-
for p in ps.iter().take(ps.len() - 1) {
486-
let (c, ch, r) = p.simulate_transcript(rng);
487-
commitments.push(c);
488-
challenges.push(ch);
489-
responses.push(r);
465+
for _ in 0..ps.len() {
466+
challenges.push(G::Scalar::random(&mut *rng));
490467
}
491-
let last_ch: <G as Group>::Scalar = challenges.iter().sum();
492-
let (last_c, last_r) = ps[ps.len() - 1].simulate_proof(&last_ch, rng);
493-
commitments.push(last_c);
494-
challenges.push(last_ch);
495-
responses.push(last_r);
496-
497-
(
498-
ProtocolCommitment::Or(commitments),
499-
ProtocolResponse::Or(challenges, responses),
500-
)
468+
for p in ps.iter() {
469+
responses.push(p.simulate_response(&mut *rng));
470+
}
471+
ProtocolResponse::Or(challenges, responses)
501472
}
502473
}
503474
}
504475

505-
fn simulate_transcript(
476+
fn simulate_transcript<R: rand::Rng + rand::CryptoRng>(
506477
&self,
507-
rng: &mut (impl rand::Rng + rand::CryptoRng),
508-
) -> (Self::Commitment, Self::Challenge, Self::Response) {
478+
rng: &mut R,
479+
) -> Result<(Self::Commitment, Self::Challenge, Self::Response), Error> {
509480
match self {
510481
Protocol::Simple(p) => {
511-
let (c, ch, r) = p.simulate_transcript(rng);
512-
(
482+
let (c, ch, r) = p.simulate_transcript(rng)?;
483+
Ok((
513484
ProtocolCommitment::Simple(c),
514485
ch,
515486
ProtocolResponse::Simple(r),
516-
)
487+
))
517488
}
518489
Protocol::And(ps) => {
519-
let mut commitments = Vec::with_capacity(ps.len());
490+
let challenge = G::Scalar::random(&mut *rng);
520491
let mut responses = Vec::with_capacity(ps.len());
521-
522-
let (c, challenge, r) = ps[0].simulate_transcript(rng);
523-
commitments.push(c);
524-
responses.push(r);
525-
526-
for p in ps.iter().skip(1) {
527-
let (c, r) = p.simulate_proof(&challenge, rng);
528-
commitments.push(c);
529-
responses.push(r);
492+
for p in ps.iter() {
493+
responses.push(p.simulate_response(&mut *rng));
530494
}
531-
(
495+
let commitments = ps
496+
.iter()
497+
.enumerate()
498+
.map(|(i, p)| p.simulate_commitment(&challenge, &responses[i]))
499+
.collect::<Result<Vec<_>, Error>>()?;
500+
501+
Ok((
532502
ProtocolCommitment::And(commitments),
533503
challenge,
534504
ProtocolResponse::And(responses),
535-
)
505+
))
536506
}
537507
Protocol::Or(ps) => {
538508
let mut commitments = Vec::with_capacity(ps.len());
539509
let mut challenges = Vec::with_capacity(ps.len());
540510
let mut responses = Vec::with_capacity(ps.len());
541511

542512
for p in ps.iter() {
543-
let (c, ch, r) = p.simulate_transcript(rng);
513+
let (c, ch, r) = p.simulate_transcript(rng)?;
544514
commitments.push(c);
545515
challenges.push(ch);
546516
responses.push(r);
547517
}
548518
let challenge = challenges.iter().sum();
549-
(
519+
Ok((
550520
ProtocolCommitment::Or(commitments),
551521
challenge,
552522
ProtocolResponse::Or(challenges, responses),
553-
)
523+
))
554524
}
555525
}
556526
}

src/fiat_shamir.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
//! - `P`: the underlying Sigma protocol ([`SigmaProtocol`] trait).
1313
//! - `C`: the codec ([`Codec`] trait).
1414
15-
use crate::codec::Codec;
1615
use crate::errors::Error;
1716
use crate::traits::SigmaProtocol;
17+
use crate::{codec::Codec, traits::SigmaProtocolSimulator};
1818

1919
use rand::{CryptoRng, RngCore};
2020

@@ -205,7 +205,7 @@ where
205205

206206
impl<P, C> NISigmaProtocol<P, C>
207207
where
208-
P: SigmaProtocol,
208+
P: SigmaProtocol + SigmaProtocolSimulator,
209209
P::Challenge: PartialEq,
210210
C: Codec<Challenge = P::Challenge> + Clone,
211211
{

src/schnorr_protocol.rs

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515

1616
use ff::Field;
1717
use group::{Group, GroupEncoding};
18-
use rand::{CryptoRng, RngCore};
18+
use rand::{CryptoRng, Rng, RngCore};
1919

2020
/// A Schnorr protocol proving knowledge of a witness for a linear group relation.
2121
///
@@ -259,6 +259,43 @@ where
259259
fn protocol_identifier(&self) -> impl AsRef<[u8]> {
260260
b"SchnorrProof"
261261
}
262+
}
263+
264+
impl<G> SigmaProtocolSimulator for SchnorrProof<G>
265+
where
266+
G: Group + GroupEncoding,
267+
{
268+
/// Simulates a valid transcript for a given challenge without a witness.
269+
///
270+
/// # Parameters
271+
/// - `challenge`: A scalar value representing the challenge.
272+
/// - `rng`: A cryptographically secure RNG.
273+
///
274+
/// # Returns
275+
/// - A commitment and response forming a valid proof for the given challenge.
276+
fn simulate_response<R: Rng + CryptoRng>(&self, mut rng: &mut R) -> Self::Response {
277+
let response: Vec<G::Scalar> = (0..self.witness_length())
278+
.map(|_| G::Scalar::random(&mut rng))
279+
.collect();
280+
response
281+
}
282+
283+
/// Simulates a full proof transcript using a randomly generated challenge.
284+
///
285+
/// # Parameters
286+
/// - `rng`: A cryptographically secure RNG.
287+
///
288+
/// # Returns
289+
/// - A tuple `(commitment, challenge, response)` forming a valid proof.
290+
fn simulate_transcript<R: Rng + CryptoRng>(
291+
&self,
292+
rng: &mut R,
293+
) -> Result<(Self::Commitment, Self::Challenge, Self::Response), Error> {
294+
let challenge = G::Scalar::random(&mut *rng);
295+
let response = self.simulate_response(&mut *rng);
296+
let commitment = self.simulate_commitment(&challenge, &response)?;
297+
Ok((commitment, challenge, response))
298+
}
262299

263300
/// Recomputes the commitment from the challenge and response (used in compact proofs).
264301
///
@@ -291,47 +328,3 @@ where
291328
Ok(commitment)
292329
}
293330
}
294-
295-
impl<G> SigmaProtocolSimulator for SchnorrProof<G>
296-
where
297-
G: Group + GroupEncoding,
298-
{
299-
/// Simulates a valid transcript for a given challenge without a witness.
300-
///
301-
/// # Parameters
302-
/// - `challenge`: A scalar value representing the challenge.
303-
/// - `rng`: A cryptographically secure RNG.
304-
///
305-
/// # Returns
306-
/// - A commitment and response forming a valid proof for the given challenge.
307-
fn simulate_proof(
308-
&self,
309-
challenge: &Self::Challenge,
310-
mut rng: &mut (impl RngCore + CryptoRng),
311-
) -> (Self::Commitment, Self::Response) {
312-
let response: Vec<G::Scalar> = (0..self.witness_length())
313-
.map(|_| G::Scalar::random(&mut rng))
314-
.collect();
315-
316-
// Use simulate_commitment to compute the commitment
317-
let commitment = self.simulate_commitment(challenge, &response).unwrap();
318-
319-
(commitment, response)
320-
}
321-
322-
/// Simulates a full proof transcript using a randomly generated challenge.
323-
///
324-
/// # Parameters
325-
/// - `rng`: A cryptographically secure RNG.
326-
///
327-
/// # Returns
328-
/// - A tuple `(commitment, challenge, response)` forming a valid proof.
329-
fn simulate_transcript(
330-
&self,
331-
mut rng: &mut (impl RngCore + CryptoRng),
332-
) -> (Self::Commitment, Self::Challenge, Self::Response) {
333-
let challenge = G::Scalar::random(&mut rng);
334-
let (commitment, response) = self.simulate_proof(&challenge, rng);
335-
(commitment, challenge, response)
336-
}
337-
}

src/tests/spec/custom_schnorr_protocol.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::serialization::{
77
deserialize_elements, deserialize_scalars, serialize_elements, serialize_scalars,
88
};
99
use crate::tests::spec::random::SRandom;
10-
use crate::traits::SigmaProtocol;
10+
use crate::traits::{SigmaProtocol, SigmaProtocolSimulator};
1111

1212
pub struct SchnorrProtocolCustom<G: SRandom + GroupEncoding>(pub LinearRelation<G>);
1313

@@ -113,7 +113,16 @@ where
113113
deserialize_scalars::<G>(data, self.0.linear_map.num_scalars)
114114
.ok_or(Error::VerificationFailure)
115115
}
116+
fn instance_label(&self) -> impl AsRef<[u8]> {
117+
self.0.label()
118+
}
116119

120+
fn protocol_identifier(&self) -> impl AsRef<[u8]> {
121+
b"draft-zkproof-fiat-shamir"
122+
}
123+
}
124+
125+
impl<G: SRandom + GroupEncoding> SigmaProtocolSimulator for SchnorrProtocolCustom<G> {
117126
fn simulate_commitment(
118127
&self,
119128
challenge: &Self::Challenge,
@@ -133,11 +142,19 @@ where
133142
Ok(commitment)
134143
}
135144

136-
fn instance_label(&self) -> impl AsRef<[u8]> {
137-
self.0.label()
145+
fn simulate_response<R: Rng + CryptoRng>(&self, rng: &mut R) -> Self::Response {
146+
(0..self.0.linear_map.num_scalars)
147+
.map(|_| <G as SRandom>::srandom(rng))
148+
.collect()
138149
}
139150

140-
fn protocol_identifier(&self) -> impl AsRef<[u8]> {
141-
b"draft-zkproof-fiat-shamir"
151+
fn simulate_transcript<R: Rng + CryptoRng>(
152+
&self,
153+
rng: &mut R,
154+
) -> Result<(Self::Commitment, Self::Challenge, Self::Response), Error> {
155+
let challenge = <G as SRandom>::srandom(rng);
156+
let response = self.simulate_response(rng);
157+
let commitment = self.simulate_commitment(&challenge, &response)?;
158+
Ok((commitment, challenge, response))
142159
}
143160
}

0 commit comments

Comments
 (0)