1use jf_merkle_tree::MerkleTreeScheme;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7 avidm_gf2::{
8 namespaced::{NsAvidmGf2Commit, NsAvidmGf2Common, NsAvidmGf2Scheme},
9 AvidmGf2Scheme, MerkleProof, MerkleTree,
10 },
11 VerificationResult, VidError, VidResult, VidScheme,
12};
13
14#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
18pub struct NsProof {
19 pub ns_index: usize,
21 #[serde(with = "base64_bytes")]
23 pub ns_payload: Vec<u8>,
24 pub ns_proof: MerkleProof,
26}
27
28impl NsAvidmGf2Scheme {
29 pub fn namespace_proof(
31 common: &NsAvidmGf2Common,
32 payload: &[u8],
33 ns_index: usize,
34 ) -> VidResult<NsProof> {
35 if common.ns_commits.len() != common.ns_lens.len() {
36 return Err(VidError::Internal(anyhow::anyhow!(
37 "Inconsistent common data"
38 )));
39 }
40 if ns_index >= common.ns_lens.len() {
41 return Err(VidError::IndexOutOfBound);
42 }
43 let ns_payload_range_start = common.ns_lens[..ns_index].iter().sum::<usize>();
44 let ns_payload_range_end = ns_payload_range_start + common.ns_lens[ns_index];
45 if ns_payload_range_end > payload.len() {
46 return Err(VidError::Internal(anyhow::anyhow!(
47 "Payload length is inconsistent with namespace lengths"
48 )));
49 }
50
51 let mt = MerkleTree::from_elems(None, common.ns_commits.iter().map(|c| c.commit))?;
52 Ok(NsProof {
53 ns_index,
54 ns_payload: payload[ns_payload_range_start..ns_payload_range_end].to_vec(),
55 ns_proof: mt
56 .lookup(ns_index as u64)
57 .expect_ok()
58 .expect("MT lookup shouldn't fail")
59 .1,
60 })
61 }
62
63 pub fn verify_namespace_proof(
65 commit: &NsAvidmGf2Commit,
66 common: &NsAvidmGf2Common,
67 proof: &NsProof,
68 ) -> VidResult<VerificationResult> {
69 let ns_commit = AvidmGf2Scheme::commit(&common.param, &proof.ns_payload)?;
70 Ok(MerkleTree::verify(
71 &commit.commit,
72 proof.ns_index as u64,
73 &ns_commit.commit,
74 &proof.ns_proof,
75 )?)
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use crate::avidm_gf2::{namespaced::NsAvidmGf2Scheme, AvidmGf2Scheme};
82
83 #[test]
84 fn test_ns_proof() {
85 let param = AvidmGf2Scheme::setup(5usize, 10usize).unwrap();
86 let payload = vec![1u8; 100];
87 let ns_table = vec![(0..10), (10..21), (21..33), (33..48), (48..100)];
88 let (commit, common) =
89 NsAvidmGf2Scheme::commit(¶m, &payload, ns_table.clone()).unwrap();
90
91 for (i, _) in ns_table.iter().enumerate() {
92 let proof = NsAvidmGf2Scheme::namespace_proof(&common, &payload, i).unwrap();
93 assert!(
94 NsAvidmGf2Scheme::verify_namespace_proof(&commit, &common, &proof)
95 .unwrap()
96 .is_ok()
97 );
98 }
99 let mut proof = NsAvidmGf2Scheme::namespace_proof(&common, &payload, 1).unwrap();
100 proof.ns_index = 0;
101 assert!(
102 NsAvidmGf2Scheme::verify_namespace_proof(&commit, &common, &proof)
103 .unwrap()
104 .is_err()
105 );
106 proof.ns_index = 1;
107 proof.ns_payload[0] = 0u8;
108 assert!(
109 NsAvidmGf2Scheme::verify_namespace_proof(&commit, &common, &proof)
110 .unwrap()
111 .is_err()
112 );
113 proof.ns_index = 100;
114 assert!(
115 NsAvidmGf2Scheme::verify_namespace_proof(&commit, &common, &proof)
116 .unwrap()
117 .is_err()
118 );
119 }
120}