1use blake3;
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12
13#[derive(Debug, Error, Clone, PartialEq, Eq)]
15pub enum ZkProofError {
16 #[error("Proof verification failed")]
17 VerificationFailed,
18 #[error("Invalid proof composition")]
19 InvalidComposition,
20 #[error("Proof not found")]
21 ProofNotFound,
22 #[error("Invalid proof type")]
23 InvalidProofType,
24}
25
26pub type ZkProofResult<T> = Result<T, ZkProofError>;
27
28#[derive(Clone, Debug, Serialize, Deserialize)]
30pub struct ZkProof {
31 proof_type: String,
33 proof_data: Vec<u8>,
35 public_inputs: Vec<Vec<u8>>,
37 metadata: Vec<(String, Vec<u8>)>,
39}
40
41impl ZkProof {
42 pub fn new(
44 proof_type: impl Into<String>,
45 proof_data: Vec<u8>,
46 public_inputs: Vec<Vec<u8>>,
47 ) -> Self {
48 Self {
49 proof_type: proof_type.into(),
50 proof_data,
51 public_inputs,
52 metadata: Vec::new(),
53 }
54 }
55
56 pub fn with_metadata(mut self, key: impl Into<String>, value: Vec<u8>) -> Self {
58 self.metadata.push((key.into(), value));
59 self
60 }
61
62 pub fn proof_type(&self) -> &str {
64 &self.proof_type
65 }
66
67 pub fn proof_data(&self) -> &[u8] {
69 &self.proof_data
70 }
71
72 pub fn public_inputs(&self) -> &[Vec<u8>] {
74 &self.public_inputs
75 }
76
77 pub fn get_metadata(&self, key: &str) -> Option<&[u8]> {
79 self.metadata
80 .iter()
81 .find(|(k, _)| k == key)
82 .map(|(_, v)| v.as_slice())
83 }
84
85 pub fn commitment(&self) -> [u8; 32] {
87 let mut hasher = blake3::Hasher::new();
88 hasher.update(b"ZK_PROOF_COMMITMENT:");
89 hasher.update(self.proof_type.as_bytes());
90 hasher.update(&self.proof_data);
91 for input in &self.public_inputs {
92 hasher.update(input);
93 }
94 *hasher.finalize().as_bytes()
95 }
96}
97
98#[derive(Clone, Debug, Serialize, Deserialize)]
102pub struct AndProof {
103 proofs: Vec<ZkProof>,
104 binding: Option<[u8; 32]>,
106}
107
108impl AndProof {
109 pub fn new(proofs: Vec<ZkProof>) -> Self {
111 Self {
112 proofs,
113 binding: None,
114 }
115 }
116
117 pub fn with_binding(mut self, binding: [u8; 32]) -> Self {
119 self.binding = Some(binding);
120 self
121 }
122
123 pub fn proofs(&self) -> &[ZkProof] {
125 &self.proofs
126 }
127
128 pub fn get_proof(&self, proof_type: &str) -> Option<&ZkProof> {
130 self.proofs.iter().find(|p| p.proof_type() == proof_type)
131 }
132
133 pub fn verify_binding(&self) -> ZkProofResult<()> {
135 if let Some(binding) = self.binding {
136 let mut hasher = blake3::Hasher::new();
138 hasher.update(b"AND_PROOF_BINDING:");
139 for proof in &self.proofs {
140 hasher.update(&proof.commitment());
141 }
142 let expected = hasher.finalize();
143
144 if expected.as_bytes() != &binding {
145 return Err(ZkProofError::VerificationFailed);
146 }
147 }
148 Ok(())
149 }
150
151 pub fn commitment(&self) -> [u8; 32] {
153 let mut hasher = blake3::Hasher::new();
154 hasher.update(b"AND_COMPOSITION:");
155 for proof in &self.proofs {
156 hasher.update(&proof.commitment());
157 }
158 if let Some(binding) = &self.binding {
159 hasher.update(binding);
160 }
161 *hasher.finalize().as_bytes()
162 }
163}
164
165#[derive(Clone, Debug, Serialize, Deserialize)]
169pub struct OrProof {
170 proof: ZkProof,
172 commitments: Vec<[u8; 32]>,
174 revealed_index: usize,
176}
177
178impl OrProof {
179 pub fn new(all_proofs: Vec<ZkProof>, revealed_index: usize) -> ZkProofResult<Self> {
181 if revealed_index >= all_proofs.len() {
182 return Err(ZkProofError::InvalidComposition);
183 }
184
185 let commitments: Vec<[u8; 32]> = all_proofs.iter().map(|p| p.commitment()).collect();
186
187 Ok(Self {
188 proof: all_proofs[revealed_index].clone(),
189 commitments,
190 revealed_index,
191 })
192 }
193
194 pub fn proof(&self) -> &ZkProof {
196 &self.proof
197 }
198
199 pub fn commitments(&self) -> &[[u8; 32]] {
201 &self.commitments
202 }
203
204 pub fn revealed_index(&self) -> usize {
206 self.revealed_index
207 }
208
209 pub fn verify_commitment(&self) -> ZkProofResult<()> {
211 let commitment = self.proof.commitment();
212 if commitment != self.commitments[self.revealed_index] {
213 return Err(ZkProofError::VerificationFailed);
214 }
215 Ok(())
216 }
217}
218
219pub struct ZkProofBuilder {
221 proofs: Vec<ZkProof>,
222}
223
224impl ZkProofBuilder {
225 pub fn new() -> Self {
227 Self { proofs: Vec::new() }
228 }
229
230 pub fn add_proof(mut self, proof: ZkProof) -> Self {
232 self.proofs.push(proof);
233 self
234 }
235
236 pub fn build_and(self) -> AndProof {
238 AndProof::new(self.proofs)
239 }
240
241 pub fn build_and_with_binding(self, binding: [u8; 32]) -> AndProof {
243 AndProof::new(self.proofs).with_binding(binding)
244 }
245
246 pub fn build_or(self, revealed_index: usize) -> ZkProofResult<OrProof> {
248 OrProof::new(self.proofs, revealed_index)
249 }
250}
251
252impl Default for ZkProofBuilder {
253 fn default() -> Self {
254 Self::new()
255 }
256}
257
258pub trait ZkProvable {
260 fn prove(&self) -> ZkProofResult<ZkProof>;
262
263 fn verify(proof: &ZkProof) -> ZkProofResult<bool>;
265}
266
267pub fn create_binding(proofs: &[&ZkProof]) -> [u8; 32] {
269 let mut hasher = blake3::Hasher::new();
270 hasher.update(b"AND_PROOF_BINDING:");
271 for proof in proofs {
272 hasher.update(&proof.commitment());
273 }
274 *hasher.finalize().as_bytes()
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 fn create_test_proof(proof_type: &str, data: &[u8]) -> ZkProof {
282 ZkProof::new(proof_type, data.to_vec(), vec![b"public_input".to_vec()])
283 }
284
285 #[test]
286 fn test_zkproof_creation() {
287 let proof = create_test_proof("range", b"proof_data");
288 assert_eq!(proof.proof_type(), "range");
289 assert_eq!(proof.proof_data(), b"proof_data");
290 assert_eq!(proof.public_inputs().len(), 1);
291 }
292
293 #[test]
294 fn test_zkproof_metadata() {
295 let proof = create_test_proof("range", b"proof_data")
296 .with_metadata("key1", b"value1".to_vec())
297 .with_metadata("key2", b"value2".to_vec());
298
299 assert_eq!(proof.get_metadata("key1"), Some(b"value1".as_slice()));
300 assert_eq!(proof.get_metadata("key2"), Some(b"value2".as_slice()));
301 assert_eq!(proof.get_metadata("key3"), None);
302 }
303
304 #[test]
305 fn test_zkproof_commitment() {
306 let proof1 = create_test_proof("range", b"proof_data");
307 let proof2 = create_test_proof("range", b"proof_data");
308 let proof3 = create_test_proof("range", b"different_data");
309
310 assert_eq!(proof1.commitment(), proof2.commitment());
312
313 assert_ne!(proof1.commitment(), proof3.commitment());
315 }
316
317 #[test]
318 fn test_and_proof_basic() {
319 let proof1 = create_test_proof("range", b"proof1");
320 let proof2 = create_test_proof("membership", b"proof2");
321 let proof3 = create_test_proof("signature", b"proof3");
322
323 let and_proof = AndProof::new(vec![proof1, proof2, proof3]);
324
325 assert_eq!(and_proof.proofs().len(), 3);
326 assert!(and_proof.get_proof("range").is_some());
327 assert!(and_proof.get_proof("membership").is_some());
328 assert!(and_proof.get_proof("signature").is_some());
329 assert!(and_proof.get_proof("nonexistent").is_none());
330 }
331
332 #[test]
333 fn test_and_proof_binding() {
334 let proof1 = create_test_proof("range", b"proof1");
335 let proof2 = create_test_proof("membership", b"proof2");
336
337 let binding = create_binding(&[&proof1, &proof2]);
339 let and_proof = AndProof::new(vec![proof1.clone(), proof2.clone()]).with_binding(binding);
340
341 assert!(and_proof.verify_binding().is_ok());
343 }
344
345 #[test]
346 fn test_and_proof_invalid_binding() {
347 let proof1 = create_test_proof("range", b"proof1");
348 let proof2 = create_test_proof("membership", b"proof2");
349
350 let wrong_binding = [0u8; 32];
352 let and_proof = AndProof::new(vec![proof1, proof2]).with_binding(wrong_binding);
353
354 assert!(and_proof.verify_binding().is_err());
356 }
357
358 #[test]
359 fn test_or_proof_basic() {
360 let proof1 = create_test_proof("option1", b"proof1");
361 let proof2 = create_test_proof("option2", b"proof2");
362 let proof3 = create_test_proof("option3", b"proof3");
363
364 let or_proof = OrProof::new(vec![proof1, proof2.clone(), proof3], 1).unwrap();
365
366 assert_eq!(or_proof.revealed_index(), 1);
367 assert_eq!(or_proof.proof().proof_type(), "option2");
368 assert_eq!(or_proof.commitments().len(), 3);
369 }
370
371 #[test]
372 fn test_or_proof_commitment_verification() {
373 let proof1 = create_test_proof("option1", b"proof1");
374 let proof2 = create_test_proof("option2", b"proof2");
375
376 let or_proof = OrProof::new(vec![proof1, proof2], 0).unwrap();
377
378 assert!(or_proof.verify_commitment().is_ok());
380 }
381
382 #[test]
383 fn test_or_proof_invalid_index() {
384 let proof1 = create_test_proof("option1", b"proof1");
385 let proof2 = create_test_proof("option2", b"proof2");
386
387 let result = OrProof::new(vec![proof1, proof2], 5);
389 assert!(result.is_err());
390 }
391
392 #[test]
393 fn test_proof_builder_and() {
394 let proof1 = create_test_proof("range", b"proof1");
395 let proof2 = create_test_proof("membership", b"proof2");
396
397 let and_proof = ZkProofBuilder::new()
398 .add_proof(proof1)
399 .add_proof(proof2)
400 .build_and();
401
402 assert_eq!(and_proof.proofs().len(), 2);
403 }
404
405 #[test]
406 fn test_proof_builder_and_with_binding() {
407 let proof1 = create_test_proof("range", b"proof1");
408 let proof2 = create_test_proof("membership", b"proof2");
409
410 let binding = create_binding(&[&proof1, &proof2]);
411 let and_proof = ZkProofBuilder::new()
412 .add_proof(proof1.clone())
413 .add_proof(proof2.clone())
414 .build_and_with_binding(binding);
415
416 assert!(and_proof.verify_binding().is_ok());
417 }
418
419 #[test]
420 fn test_proof_builder_or() {
421 let proof1 = create_test_proof("option1", b"proof1");
422 let proof2 = create_test_proof("option2", b"proof2");
423 let proof3 = create_test_proof("option3", b"proof3");
424
425 let or_proof = ZkProofBuilder::new()
426 .add_proof(proof1)
427 .add_proof(proof2)
428 .add_proof(proof3)
429 .build_or(1)
430 .unwrap();
431
432 assert_eq!(or_proof.revealed_index(), 1);
433 assert_eq!(or_proof.proof().proof_type(), "option2");
434 }
435
436 #[test]
437 fn test_serialization() {
438 let proof1 = create_test_proof("range", b"proof1");
439 let proof2 = create_test_proof("membership", b"proof2");
440
441 let and_proof = AndProof::new(vec![proof1, proof2]);
442
443 let serialized = crate::codec::encode(&and_proof).unwrap();
445 let deserialized: AndProof = crate::codec::decode(&serialized).unwrap();
446
447 assert_eq!(deserialized.proofs().len(), 2);
448 assert_eq!(deserialized.commitment(), and_proof.commitment());
449 }
450}