|
9 | 9 | //! |
10 | 10 | //! These constructions preserve zero-knowledge properties and follow standard Sigma protocol composition techniques. |
11 | 11 |
|
| 12 | +use std::convert::TryInto; |
| 13 | + |
12 | 14 | use crate::{ |
13 | 15 | SigmaProtocol, |
14 | 16 | SigmaProtocolSimulator, |
@@ -99,6 +101,43 @@ where |
99 | 101 | _ => Err(ProofError::VerificationFailure), |
100 | 102 | } |
101 | 103 | } |
| 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 | + } |
102 | 141 | } |
103 | 142 |
|
104 | 143 | /// Logical OR composition of two Sigma protocols. |
@@ -241,4 +280,56 @@ where |
241 | 280 | _ => Err(ProofError::VerificationFailure), |
242 | 281 | } |
243 | 282 | } |
| 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 | + } |
244 | 335 | } |
0 commit comments