sigma_proofs/
fiat_shamir.rs1use crate::errors::Error;
14use crate::traits::ScalarRng;
15use crate::traits::SigmaProtocol;
16use crate::traits::SigmaProtocolSimulator;
17use alloc::vec::Vec;
18use sha3::digest::{ExtendableOutput, Update, XofReader};
19use spongefish::{
20 DomainSeparator, Encoding, NargDeserialize, NargSerialize, ProverState, VerifierState,
21};
22
23#[derive(Debug)]
32pub struct Nizk<P>
33where
34 P: SigmaProtocol,
35 P::Challenge: PartialEq,
36{
37 pub session_id: Vec<u8>,
38 pub interactive_proof: P,
40}
41
42impl<P> Nizk<P>
43where
44 P: SigmaProtocol,
45 P::Challenge: PartialEq,
46 P::Commitment: NargSerialize + NargDeserialize + Encoding,
47 P::Response: NargSerialize + NargDeserialize + Encoding,
48{
49 pub fn new(session_identifier: &[u8], interactive_proof: P) -> Self {
58 Self {
59 session_id: session_identifier.to_vec(),
60 interactive_proof,
61 }
62 }
63
64 pub fn prove_batchable(
76 &self,
77 witness: &P::Witness,
78 rng: &mut impl ScalarRng,
79 ) -> Result<Vec<u8>, Error> {
80 let protocol_id = self.interactive_proof.protocol_identifier();
81 let instance_label = self.interactive_proof.instance_label();
82 let mut transcript =
83 initialize_prover_state(protocol_id, &self.session_id, instance_label.as_ref());
84 let (commitment, ip_state) = self.interactive_proof.prover_commit(witness, rng)?;
85 transcript.prover_messages(&commitment);
86 let challenge = transcript.verifier_message::<P::Challenge>();
87 let response = self
88 .interactive_proof
89 .prover_response(ip_state, &challenge)?;
90 transcript.prover_messages(&response);
91 Ok(transcript.narg_string().to_vec())
92 }
93
94 pub fn verify_batchable(&self, narg_string: &[u8]) -> Result<(), Error> {
108 let protocol_id = self.interactive_proof.protocol_identifier();
109 let instance_label = self.interactive_proof.instance_label();
110 let commitment_len = self.interactive_proof.commitment_len();
111 let response_len = self.interactive_proof.response_len();
112 let mut transcript = initialize_verifier_state(
113 protocol_id,
114 &self.session_id,
115 instance_label.as_ref(),
116 narg_string,
117 );
118 let commitment = transcript.prover_messages_vec::<P::Commitment>(commitment_len)?;
119 let challenge = transcript.verifier_message::<P::Challenge>();
120 let response = transcript.prover_messages_vec::<P::Response>(response_len)?;
121 transcript.check_eof()?;
122 self.interactive_proof
123 .verifier(&commitment, &challenge, &response)
124 }
125}
126
127impl<P> Nizk<P>
128where
129 P: SigmaProtocol + SigmaProtocolSimulator,
130 P::Challenge: PartialEq + NargDeserialize + NargSerialize,
131{
132 pub fn prove_compact(
146 &self,
147 witness: &P::Witness,
148 rng: &mut impl ScalarRng,
149 ) -> Result<Vec<u8>, Error> {
150 let protocol_id = self.interactive_proof.protocol_identifier();
151 let instance_label = self.interactive_proof.instance_label();
152 let mut transcript =
153 initialize_prover_state(protocol_id, &self.session_id, instance_label.as_ref());
154 let (commitment, ip_state) = self.interactive_proof.prover_commit(witness, rng)?;
155 let commitment_bytes = serialize_messages(&commitment);
156 transcript.public_message(commitment_bytes.as_slice());
157 let challenge = transcript.verifier_message::<P::Challenge>();
158 let response = self
159 .interactive_proof
160 .prover_response(ip_state, &challenge)?;
161
162 let mut proof = Vec::new();
164 challenge.serialize_into_narg(&mut proof);
165 serialize_messages_into(&response, &mut proof);
166 Ok(proof)
167 }
168
169 pub fn verify_compact(&self, proof: &[u8]) -> Result<(), Error> {
185 let mut cursor = proof;
187 let protocol_id = self.interactive_proof.protocol_identifier();
188 let instance_label = self.interactive_proof.instance_label();
189 let challenge = P::Challenge::deserialize_from_narg(&mut cursor)?;
190 let response_len = self.interactive_proof.response_len();
191 let response = deserialize_messages(response_len, &mut cursor)?;
192
193 if !cursor.is_empty() {
195 return Err(Error::VerificationFailure);
196 }
197
198 let commitment = self
200 .interactive_proof
201 .simulate_commitment(&challenge, &response)?;
202
203 let commitment_bytes = serialize_messages(&commitment);
206 let mut transcript =
207 initialize_verifier_state(protocol_id, &self.session_id, instance_label.as_ref(), &[]);
208 transcript.public_message(commitment_bytes.as_slice());
209 let recomputed_challenge = transcript.verifier_message::<P::Challenge>();
210 if challenge != recomputed_challenge {
211 return Err(Error::VerificationFailure);
212 }
213
214 Ok(())
221 }
222}
223
224fn initialize_prover_state(
225 protocol_id: [u8; 64],
226 session_id: &[u8],
227 instance_label: &[u8],
228) -> ProverState {
229 let instance_label = instance_label.to_vec();
230 DomainSeparator::new(protocol_id)
231 .session(derive_session_id(session_id))
232 .instance(&instance_label)
233 .std_prover()
234}
235
236fn initialize_verifier_state<'a>(
237 protocol_id: [u8; 64],
238 session_id: &[u8],
239 instance_label: &[u8],
240 narg_string: &'a [u8],
241) -> VerifierState<'a> {
242 let instance_label = instance_label.to_vec();
243 DomainSeparator::new(protocol_id)
244 .session(derive_session_id(session_id))
245 .instance(&instance_label)
246 .std_verifier(narg_string)
247}
248
249fn derive_session_id(session_id: &[u8]) -> [u8; 64] {
250 const RATE: usize = 168;
251 const DOMAIN: &[u8] = b"fiat-shamir/session-id";
252
253 let mut initial_block = [0u8; RATE];
254 initial_block[..DOMAIN.len()].copy_from_slice(DOMAIN);
255
256 let mut shake = sha3::Shake128::default();
257 shake.update(&initial_block);
258 shake.update(session_id);
259
260 let mut reader = shake.finalize_xof();
261 let mut derived = [0u8; 64];
262 reader.read(&mut derived[32..]);
263 derived
264}
265
266fn serialize_messages_into<T: NargSerialize>(messages: &[T], out: &mut Vec<u8>) {
267 for message in messages {
268 message.serialize_into_narg(out);
269 }
270}
271
272fn serialize_messages<T: NargSerialize>(messages: &[T]) -> Vec<u8> {
273 let mut out = Vec::new();
274 serialize_messages_into(messages, &mut out);
275 out
276}
277
278fn deserialize_messages<T: NargDeserialize>(len: usize, buf: &mut &[u8]) -> Result<Vec<T>, Error> {
279 let mut out = Vec::new();
280 for _ in 0..len {
281 out.push(T::deserialize_from_narg(buf).map_err(|_| Error::VerificationFailure)?);
282 }
283 Ok(out)
284}