Skip to content

Commit b458383

Browse files
committed
MultiRoundNIZK
1 parent fc8aaf0 commit b458383

File tree

3 files changed

+178
-36
lines changed

3 files changed

+178
-36
lines changed

src/compressed.rs

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::errors::Error as ProofError;
44
use crate::errors::Result as ProofResult;
55
use crate::linear_relation;
6+
use crate::serialization::deserialize_elements;
67
use crate::serialization::deserialize_scalars;
78
use crate::traits::InteractiveProof;
89
use ff::Field;
@@ -74,24 +75,18 @@ fn fold_scalars<F: Field>(left: &[F], right: &[F], x: &F, x_inv: &F) -> Vec<F> {
7475
.collect()
7576
}
7677

77-
struct CompressedProofMessage<G: PrimeGroup> {
78-
final_message: Option<G::Scalar>,
79-
intermediate_message: Option<[G; 2]>,
78+
enum CompressedProofMessage<G: PrimeGroup> {
79+
FinalMessage(G::Scalar),
80+
IntermediateMessage([G; 2]),
8081
}
8182

8283
impl<G: PrimeGroup> CompressedProofMessage<G> {
8384
fn new_from_intermediate_message(intermediate_message: [G; 2]) -> Self {
84-
Self {
85-
final_message: None,
86-
intermediate_message: Some(intermediate_message),
87-
}
85+
Self::IntermediateMessage(intermediate_message)
8886
}
8987

9088
fn new_from_final_message(final_message: G::Scalar) -> Self {
91-
Self {
92-
final_message: Some(final_message),
93-
intermediate_message: None,
94-
}
89+
Self::FinalMessage(final_message)
9590
}
9691
}
9792

@@ -104,6 +99,25 @@ impl<G: PrimeGroup> InteractiveProof for SquashedLinearRelation<G> {
10499

105100
type Challenge = G::Scalar;
106101

102+
type Witness = Vec<G::Scalar>;
103+
104+
fn get_initial_prover_state(&self, witness: &Self::Witness) -> Self::ProverState {
105+
(
106+
witness.to_vec(),
107+
SquashedLinearRelation {
108+
generators: self.generators.clone(),
109+
image: self.image,
110+
},
111+
)
112+
}
113+
114+
fn get_initial_verifier_state(&self) -> Self::VerifierState {
115+
SquashedLinearRelation {
116+
generators: self.generators.clone(),
117+
image: self.image,
118+
}
119+
}
120+
107121
fn prover_message(
108122
&self,
109123
state: &mut Self::ProverState,
@@ -148,44 +162,71 @@ impl<G: PrimeGroup> InteractiveProof for SquashedLinearRelation<G> {
148162
challenge: &Self::Challenge,
149163
) -> Result<(), ProofError> {
150164
if state.generators.len() == 1 {
151-
if prover_message.final_message.is_none() {
152-
return Err(ProofError::VerificationFailure);
165+
match prover_message {
166+
CompressedProofMessage::FinalMessage(witness) => {
167+
let computed = state.generators[0] * witness;
168+
if computed == state.image {
169+
return Ok(());
170+
} else {
171+
return Err(ProofError::VerificationFailure);
172+
}
173+
}
174+
CompressedProofMessage::IntermediateMessage(_) => {
175+
return Err(ProofError::VerificationFailure);
176+
}
153177
}
154-
let witness = prover_message.final_message.unwrap();
155-
let computed = state.generators[0] * witness[0];
156-
if computed == state.image {
157-
return Ok(());
158-
} else {
178+
}
179+
match prover_message {
180+
CompressedProofMessage::FinalMessage(_) => {
159181
return Err(ProofError::VerificationFailure);
160182
}
183+
CompressedProofMessage::IntermediateMessage([A, B]) => {
184+
let n = state.generators.len() / 2;
185+
let (g_left, g_right) = state.generators.split_at(n);
186+
let new_generators = fold_generators(g_left, g_right, &challenge, &G::Scalar::ONE);
187+
let new_image = *A + state.image * challenge + *B * challenge.square();
188+
state.generators = new_generators;
189+
state.image = new_image;
190+
Ok(())
191+
}
161192
}
162-
if prover_message.intermediate_message.is_none() {
163-
return Err(ProofError::VerificationFailure);
164-
}
165-
let [A, B] = prover_message.intermediate_message.unwrap();
166-
let n = state.generators.len() / 2;
167-
let (g_left, g_right) = state.generators.split_at(n);
168-
let new_generators = fold_generators(g_left, g_right, &challenge, &G::Scalar::ONE);
169-
let new_image = A + state.image * challenge + B * challenge.square();
170-
state.generators = new_generators;
171-
state.image = new_image;
172-
Ok(())
173193
}
174194

175195
fn serialize_message(&self, prover_message: &Self::ProverMessage) -> Vec<u8> {
176-
todo!()
196+
match prover_message {
197+
CompressedProofMessage::FinalMessage(witness) => serialize_scalars::<G>(&[*witness]),
198+
CompressedProofMessage::IntermediateMessage(prover_message) => {
199+
serialize_elements(prover_message)
200+
}
201+
}
177202
}
178203

179204
fn serialize_challenge(&self, challenge: &Self::Challenge) -> Vec<u8> {
180-
todo!()
205+
serialize_scalars::<G>(&[*challenge])
181206
}
182207

183-
fn deserialize_message(&self, data: &[u8]) -> Result<Self::ProverMessage, ProofError> {
184-
todo!()
208+
fn deserialize_message(
209+
&self,
210+
data: &[u8],
211+
is_final_message: bool,
212+
) -> Result<Self::ProverMessage, ProofError> {
213+
if is_final_message {
214+
let witness =
215+
deserialize_scalars::<G>(data, 1).ok_or(ProofError::VerificationFailure)?;
216+
Ok(CompressedProofMessage::new_from_final_message(witness[0]))
217+
} else {
218+
let elements =
219+
deserialize_elements::<G>(data, 2).ok_or(ProofError::VerificationFailure)?;
220+
let intermediate_message: [G; 2] = [elements[0], elements[1]];
221+
Ok(CompressedProofMessage::IntermediateMessage(
222+
intermediate_message,
223+
))
224+
}
185225
}
186226

187227
fn deserialize_challenge(&self, data: &[u8]) -> Result<Self::Challenge, ProofError> {
188-
todo!()
228+
let scalars = deserialize_scalars::<G>(data, 1).ok_or(ProofError::VerificationFailure)?;
229+
Ok(scalars[0])
189230
}
190231

191232
fn protocol_identifier(&self) -> impl AsRef<[u8]> {
@@ -195,6 +236,10 @@ impl<G: PrimeGroup> InteractiveProof for SquashedLinearRelation<G> {
195236
fn instance_label(&self) -> impl AsRef<[u8]> {
196237
"TODO"
197238
}
239+
240+
fn num_rounds(&self) -> usize {
241+
self.generators.len().next_power_of_two().ilog2() as usize + 1
242+
}
198243
}
199244

200245
impl<G: PrimeGroup> SquashedLinearRelation<G> {

src/fiat_shamir.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! - `C`: the codec ([`Codec`] trait).
1414
1515
use crate::errors::Error;
16-
use crate::traits::SigmaProtocol;
16+
use crate::traits::{InteractiveProof, SigmaProtocol};
1717
use crate::{codec::Codec, traits::SigmaProtocolSimulator};
1818
use alloc::vec::Vec;
1919

@@ -28,6 +28,11 @@ type Transcript<P> = (
2828
<P as SigmaProtocol>::Response,
2929
);
3030

31+
type MultiRoundTranscript<P> = (
32+
Vec<<P as InteractiveProof>::ProverMessage>,
33+
Vec<<P as InteractiveProof>::Challenge>,
34+
);
35+
3136
/// A Fiat-Shamir transformation of a [`SigmaProtocol`] into a non-interactive proof.
3237
///
3338
/// [`Nizk`] wraps an interactive Sigma protocol `P`
@@ -304,3 +309,84 @@ where
304309
self.verify(&commitment, &challenge, &response)
305310
}
306311
}
312+
313+
pub struct MultiRoundNizk<P, C>
314+
where
315+
P: InteractiveProof,
316+
P::Challenge: PartialEq,
317+
C: Codec<Challenge = P::Challenge>,
318+
{
319+
/// Current codec state.
320+
pub hash_state: C,
321+
/// Underlying interactive proof.
322+
pub interactive_proof: P,
323+
}
324+
325+
impl<P, C> MultiRoundNizk<P, C>
326+
where
327+
P: InteractiveProof,
328+
P::Challenge: PartialEq,
329+
C: Codec<Challenge = P::Challenge> + Clone,
330+
{
331+
/// Constructs a new [`MultiRoundNizk`] instance.
332+
///
333+
/// # Parameters
334+
/// - `iv`: Domain separation tag for the hash function (e.g., protocol name or context).
335+
/// - `instance`: An instance of the [`InteractiveProof`].
336+
///
337+
/// # Returns
338+
/// A new [`MultiRoundNizk`] that can generate and verify non-interactive proofs.
339+
pub fn new(session_identifier: &[u8], interactive_proof: P) -> Self {
340+
let hash_state = C::new(
341+
interactive_proof.protocol_identifier().as_ref(),
342+
session_identifier,
343+
interactive_proof.instance_label().as_ref(),
344+
);
345+
Self {
346+
hash_state,
347+
interactive_proof,
348+
}
349+
}
350+
351+
pub fn from_iv(iv: [u8; 64], interactive_proof: P) -> Self {
352+
let hash_state = C::from_iv(iv);
353+
Self {
354+
hash_state,
355+
interactive_proof,
356+
}
357+
}
358+
359+
fn prove(&self, witness: &P::Witness) -> Result<MultiRoundTranscript<P>, Error> {
360+
let mut hash_state = self.hash_state.clone();
361+
let num_rounds = self.interactive_proof.num_rounds();
362+
let mut statement = self.interactive_proof.get_initial_prover_state(witness);
363+
let mut messages = vec![];
364+
let mut challenges = vec![];
365+
(0..num_rounds).for_each(|_| {
366+
let challenge = hash_state.verifier_challenge();
367+
let message = self
368+
.interactive_proof
369+
.prover_message(&mut statement, &challenge)
370+
.unwrap();
371+
let serialized_message = self.interactive_proof.serialize_message(&message);
372+
hash_state.prover_message(&serialized_message);
373+
messages.push(message);
374+
challenges.push(challenge);
375+
});
376+
Ok((messages, challenges))
377+
}
378+
379+
fn verify(&self, prover_messages: &[P::ProverMessage]) -> Result<(), Error> {
380+
let mut hash_state = self.hash_state.clone();
381+
let num_rounds = self.interactive_proof.num_rounds();
382+
assert_eq!(prover_messages.len(), num_rounds);
383+
let mut statement = self.interactive_proof.get_initial_verifier_state();
384+
for message in prover_messages {
385+
let challenge = hash_state.verifier_challenge();
386+
P::update_verifier_state(message, &mut statement, &challenge)?;
387+
let serialized_message = self.interactive_proof.serialize_message(&message);
388+
hash_state.prover_message(&serialized_message);
389+
}
390+
Ok(())
391+
}
392+
}

src/traits.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ pub trait InteractiveProof {
148148
type ProverMessage;
149149
type VerifierState;
150150
type Challenge;
151+
type Witness;
152+
153+
fn get_initial_prover_state(&self, witness: &Self::Witness) -> Self::ProverState;
154+
155+
fn get_initial_verifier_state(&self) -> Self::VerifierState;
151156

152157
fn prover_message(
153158
&self,
@@ -166,12 +171,18 @@ pub trait InteractiveProof {
166171
/// Serializes a challenge to bytes.
167172
fn serialize_challenge(&self, challenge: &Self::Challenge) -> Vec<u8>;
168173

169-
fn deserialize_message(&self, data: &[u8]) -> Result<Self::ProverMessage, Error>;
174+
fn deserialize_message(
175+
&self,
176+
data: &[u8],
177+
is_final_message: bool,
178+
) -> Result<Self::ProverMessage, Error>;
170179

171180
/// Deserializes a challenge from bytes.
172181
fn deserialize_challenge(&self, data: &[u8]) -> Result<Self::Challenge, Error>;
173182

174183
fn protocol_identifier(&self) -> impl AsRef<[u8]>;
175184

176185
fn instance_label(&self) -> impl AsRef<[u8]>;
186+
187+
fn num_rounds(&self) -> usize;
177188
}

0 commit comments

Comments
 (0)