Skip to content

Commit a47ba99

Browse files
author
GOURIOU Lénaïck
committed
Merge
1 parent a20606a commit a47ba99

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ pub enum ProofError {
1616
/// Occurs during batch verification if the batch parameters do not have the right size.
1717
#[error("Mismatched parameter sizes for batch verification.")]
1818
BatchSizeMismatch,
19+
/// Occurs when a feature is not implemented yet.
20+
#[error("The method is not yet implemented for this struct")]
21+
NotImplemented(&'static str),
1922
}

src/proof_composition.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//!
1010
//! These constructions preserve zero-knowledge properties and follow standard Sigma protocol composition techniques.
1111
12+
use std::convert::TryInto;
13+
1214
use crate::{
1315
SigmaProtocol,
1416
SigmaProtocolSimulator,
@@ -99,6 +101,43 @@ where
99101
_ => Err(ProofError::VerificationFailure),
100102
}
101103
}
104+
105+
fn serialize_batchable(
106+
&self,
107+
commitment: &Self::Commitment,
108+
challenge: &Self::Challenge,
109+
response: &Self::Response,
110+
) -> Vec<u8> {
111+
let ser0 = self.protocol0.serialize_batchable(&commitment.0, challenge, &response.0);
112+
let ser1 = self.protocol1.serialize_batchable(&commitment.1, challenge, &response.1);
113+
let len0 = ser0.len() as u32;
114+
115+
let mut out = ser0;
116+
out.extend(ser1);
117+
out.extend(&len0.to_le_bytes()); // append length hint as trailer
118+
out
119+
}
120+
121+
fn deserialize_batchable(&self, data: &[u8]) -> Option<(Self::Commitment, Self::Response)> {
122+
if data.len() < 4 {
123+
return None; // not enough bytes to contain the length suffix
124+
}
125+
126+
// Split off the last 4 bytes as the trailer
127+
let (proof_data, len_bytes) = data.split_at(data.len() - 4);
128+
let len0 = u32::from_le_bytes(len_bytes.try_into().ok()?) as usize;
129+
130+
if proof_data.len() < len0 {
131+
return None; // length hint exceeds available bytes
132+
}
133+
134+
let (ser0, ser1) = proof_data.split_at(len0);
135+
136+
let (commitment0, response0) = self.protocol0.deserialize_batchable(ser0)?;
137+
let (commitment1, response1) = self.protocol1.deserialize_batchable(ser1)?;
138+
139+
Some(((commitment0, commitment1), (response0, response1)))
140+
}
102141
}
103142

104143
/// Logical OR composition of two Sigma protocols.
@@ -241,4 +280,56 @@ where
241280
_ => Err(ProofError::VerificationFailure),
242281
}
243282
}
283+
284+
fn serialize_batchable(
285+
&self,
286+
commitment: &Self::Commitment,
287+
challenge: &Self::Challenge,
288+
response: &Self::Response,
289+
) -> Vec<u8> {
290+
let (ch0, resp0, resp1) = response;
291+
let ch1 = *challenge - *ch0;
292+
293+
let ser0 = self.protocol0.serialize_batchable(&commitment.0, ch0, resp0);
294+
let ser1 = self.protocol1.serialize_batchable(&commitment.1, &ch1, resp1);
295+
296+
let mut out = ser0.clone();
297+
out.extend(&ser1);
298+
out.extend(ch0.to_repr().as_ref()); // serialize ch0
299+
out.extend(&(ser0.len() as u32).to_le_bytes()); // append len0 (length of ser0)
300+
301+
out
302+
}
303+
304+
fn deserialize_batchable(&self, data: &[u8]) -> Option<(Self::Commitment, Self::Response)> {
305+
// The challenge is appended as `Challenge::Repr`, which must be a fixed size
306+
let repr_len = <C as PrimeField>::Repr::default().as_ref().len();
307+
if data.len() < repr_len + 4 {
308+
return None;
309+
}
310+
311+
let len0_bytes = &data[data.len() - 4..];
312+
let ch0_bytes = &data[data.len() - 4 - repr_len..data.len() - 4];
313+
let proof_data = &data[..data.len() - repr_len - 4];
314+
315+
let len0 = u32::from_le_bytes(len0_bytes.try_into().ok()?) as usize;
316+
if proof_data.len() < len0 {
317+
return None;
318+
}
319+
320+
let mut repr = <C as PrimeField>::Repr::default();
321+
repr.as_mut().copy_from_slice(ch0_bytes);
322+
323+
let result_ctoption = C::from_repr(repr);
324+
if (!result_ctoption.is_some()).into() {
325+
return None;
326+
}
327+
let ch0 = result_ctoption.unwrap();
328+
329+
let (proof0_bytes, proof1_bytes) = proof_data.split_at(len0);
330+
let (commitment0, response0) = self.protocol0.deserialize_batchable(proof0_bytes)?;
331+
let (commitment1, response1) = self.protocol1.deserialize_batchable(proof1_bytes)?;
332+
333+
Some(((commitment0, commitment1), (ch0, response0, response1)))
334+
}
244335
}

src/trait.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,18 @@ pub trait SigmaProtocol {
6666
/// Panics if serialization is not supported for this protocol.
6767
fn serialize_batchable(
6868
&self,
69-
_commitment: &Self::Commitment,
70-
_challenge: &Self::Challenge,
71-
_response: &Self::Response,
72-
) -> Vec<u8> {
73-
panic!("serialize_batchable not implemented for this protocol")
74-
}
69+
commitment: &Self::Commitment,
70+
challenge: &Self::Challenge,
71+
response: &Self::Response,
72+
) -> Vec<u8>;
7573

7674
/// Deserializes a proof transcript from bytes.
7775
///
7876
/// Returns `Some((commitment, response))` if parsing is successful, otherwise `None`.
7977
///
8078
/// # Panics
8179
/// Panics if deserialization is not supported for this protocol.
82-
fn deserialize_batchable(
83-
&self,
84-
_data: &[u8]
85-
) -> Option<(Self::Commitment, Self::Response)> {
86-
panic!("deserialize_batchable not implemented for this protocol")
87-
}
80+
fn deserialize_batchable(&self, _data: &[u8]) -> Option<(Self::Commitment, Self::Response)>;
8881
}
8982

9083
pub trait CompactProtocol: SigmaProtocol {

tests/proof_composition_test.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,19 @@ impl SigmaProtocol for SchnorrZkp {
5353
false => Err(ProofError::VerificationFailure),
5454
}
5555
}
56+
57+
fn serialize_batchable(
58+
&self,
59+
_commitment: &Self::Commitment,
60+
_challenge: &Self::Challenge,
61+
_response: &Self::Response,
62+
) -> Vec<u8> {
63+
todo!()
64+
}
65+
66+
fn deserialize_batchable(&self, _data: &[u8]) -> Option<(Self::Commitment, Self::Response)> {
67+
todo!()
68+
}
5669
}
5770

5871
#[allow(non_snake_case)]

0 commit comments

Comments
 (0)