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 let commitment_bytes = serialize_messages(&commitment);
86 transcript.public_message(commitment_bytes.as_slice());
87 let challenge = transcript.verifier_message::<P::Challenge>();
88 let response = self
89 .interactive_proof
90 .prover_response(ip_state, &challenge)?;
91 let mut proof = commitment_bytes;
92 serialize_messages_into(&response, &mut proof);
93 Ok(proof)
94 }
95
96 pub fn verify_batchable(&self, narg_string: &[u8]) -> Result<(), Error> {
110 let protocol_id = self.interactive_proof.protocol_identifier();
111 let instance_label = self.interactive_proof.instance_label();
112 let commitment_len = self.interactive_proof.commitment_len();
113 let response_len = self.interactive_proof.response_len();
114 let mut transcript = initialize_verifier_state(
115 protocol_id,
116 &self.session_id,
117 instance_label.as_ref(),
118 narg_string,
119 );
120 let commitment = transcript.prover_messages_vec::<P::Commitment>(commitment_len)?;
121 let challenge = transcript.verifier_message::<P::Challenge>();
122 let response = transcript.prover_messages_vec::<P::Response>(response_len)?;
123 transcript.check_eof()?;
124 self.interactive_proof
125 .verifier(&commitment, &challenge, &response)
126 }
127}
128
129impl<P> Nizk<P>
130where
131 P: SigmaProtocol + SigmaProtocolSimulator,
132 P::Challenge: PartialEq + NargDeserialize + NargSerialize,
133{
134 pub fn prove_compact(
148 &self,
149 witness: &P::Witness,
150 rng: &mut impl ScalarRng,
151 ) -> Result<Vec<u8>, Error> {
152 let protocol_id = self.interactive_proof.protocol_identifier();
153 let instance_label = self.interactive_proof.instance_label();
154 let mut transcript =
155 initialize_prover_state(protocol_id, &self.session_id, instance_label.as_ref());
156 let (commitment, ip_state) = self.interactive_proof.prover_commit(witness, rng)?;
157 let commitment_bytes = serialize_messages(&commitment);
158 transcript.public_message(commitment_bytes.as_slice());
159 let challenge = transcript.verifier_message::<P::Challenge>();
160 let response = self
161 .interactive_proof
162 .prover_response(ip_state, &challenge)?;
163
164 let mut proof = Vec::new();
166 challenge.serialize_into_narg(&mut proof);
167 serialize_messages_into(&response, &mut proof);
168 Ok(proof)
169 }
170
171 pub fn verify_compact(&self, proof: &[u8]) -> Result<(), Error> {
187 let mut cursor = proof;
189 let protocol_id = self.interactive_proof.protocol_identifier();
190 let instance_label = self.interactive_proof.instance_label();
191 let challenge = P::Challenge::deserialize_from_narg(&mut cursor)?;
192 let response_len = self.interactive_proof.response_len();
193 let response = deserialize_messages(response_len, &mut cursor)?;
194
195 if !cursor.is_empty() {
197 return Err(Error::VerificationFailure);
198 }
199
200 let commitment = self
202 .interactive_proof
203 .simulate_commitment(&challenge, &response)?;
204
205 let commitment_bytes = serialize_messages(&commitment);
208 let mut transcript =
209 initialize_verifier_state(protocol_id, &self.session_id, instance_label.as_ref(), &[]);
210 transcript.public_message(commitment_bytes.as_slice());
211 let recomputed_challenge = transcript.verifier_message::<P::Challenge>();
212 if challenge != recomputed_challenge {
213 return Err(Error::VerificationFailure);
214 }
215
216 Ok(())
223 }
224}
225
226fn initialize_prover_state(
227 protocol_id: [u8; 64],
228 session_id: &[u8],
229 instance_label: &[u8],
230) -> ProverState {
231 let instance_label = instance_label.to_vec();
232 DomainSeparator::new(protocol_id)
233 .session(derive_session_id(session_id))
234 .instance(&instance_label)
235 .std_prover()
236}
237
238fn initialize_verifier_state<'a>(
239 protocol_id: [u8; 64],
240 session_id: &[u8],
241 instance_label: &[u8],
242 narg_string: &'a [u8],
243) -> VerifierState<'a> {
244 let instance_label = instance_label.to_vec();
245 DomainSeparator::new(protocol_id)
246 .session(derive_session_id(session_id))
247 .instance(&instance_label)
248 .std_verifier(narg_string)
249}
250
251fn derive_session_id(session_id: &[u8]) -> [u8; 64] {
252 const RATE: usize = 168;
253 const DOMAIN: &[u8] = b"fiat-shamir/session-id";
254
255 let mut initial_block = [0u8; RATE];
256 initial_block[..DOMAIN.len()].copy_from_slice(DOMAIN);
257
258 let mut shake = sha3::Shake128::default();
259 shake.update(&initial_block);
260 shake.update(session_id);
261
262 let mut reader = shake.finalize_xof();
263 let mut derived = [0u8; 64];
264 reader.read(&mut derived[32..]);
265 derived
266}
267
268fn serialize_messages_into<T: NargSerialize>(messages: &[T], out: &mut Vec<u8>) {
269 for message in messages {
270 message.serialize_into_narg(out);
271 }
272}
273
274fn serialize_messages<T: NargSerialize>(messages: &[T]) -> Vec<u8> {
275 let mut out = Vec::new();
276 serialize_messages_into(messages, &mut out);
277 out
278}
279
280fn deserialize_messages<T: NargDeserialize>(len: usize, buf: &mut &[u8]) -> Result<Vec<T>, Error> {
281 let mut out = Vec::with_capacity(len);
282 for _ in 0..len {
283 out.push(T::deserialize_from_narg(buf).map_err(|_| Error::VerificationFailure)?);
284 }
285 Ok(out)
286}