1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7use crate::credential::AnonCredsCredential;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ProofRequest {
12 pub name: String,
14 pub version: String,
16 pub nonce: String,
18 pub requested_attributes: BTreeMap<String, RequestedAttribute>,
20 pub requested_predicates: BTreeMap<String, RequestedPredicate>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct RequestedAttribute {
27 pub name: Option<String>,
29 pub names: Option<Vec<String>>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub restrictions: Option<Vec<serde_json::Value>>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct RequestedPredicate {
39 pub name: String,
41 pub p_type: String,
43 pub p_value: i64,
45}
46
47impl ProofRequest {
48 pub fn matches_credential(&self, credential: &AnonCredsCredential) -> bool {
53 for attr in self.requested_attributes.values() {
55 if let Some(ref name) = attr.name {
56 if !credential.values.contains_key(name) {
57 return false;
58 }
59 }
60 if let Some(ref names) = attr.names {
61 for name in names {
62 if !credential.values.contains_key(name) {
63 return false;
64 }
65 }
66 }
67 }
68
69 for pred in self.requested_predicates.values() {
71 if !credential.values.contains_key(&pred.name) {
72 return false;
73 }
74 }
75
76 true
77 }
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct ProofResponse {
83 pub revealed_attrs: BTreeMap<String, RevealedAttribute>,
85 pub self_attested_attrs: BTreeMap<String, String>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct RevealedAttribute {
92 pub sub_proof_index: u32,
94 pub raw: String,
96 pub encoded: String,
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::credential::{AnonCredsCredential, AttributeValue};
104
105 fn sample_credential() -> AnonCredsCredential {
106 let mut values = BTreeMap::new();
107 values.insert(
108 "name".to_string(),
109 AttributeValue {
110 raw: "Alice".to_string(),
111 encoded: "123".to_string(),
112 },
113 );
114 values.insert(
115 "age".to_string(),
116 AttributeValue {
117 raw: "30".to_string(),
118 encoded: "30".to_string(),
119 },
120 );
121 values.insert(
122 "degree".to_string(),
123 AttributeValue {
124 raw: "CS".to_string(),
125 encoded: "456".to_string(),
126 },
127 );
128 AnonCredsCredential {
129 schema_id: "schema:1".to_string(),
130 cred_def_id: "cred_def:1".to_string(),
131 rev_reg_id: None,
132 issuer_did: "did:sov:issuer".to_string(),
133 values,
134 }
135 }
136
137 #[test]
138 fn proof_request_matches_credential() {
139 let mut requested_attributes = BTreeMap::new();
140 requested_attributes.insert(
141 "attr1_referent".to_string(),
142 RequestedAttribute {
143 name: Some("name".to_string()),
144 names: None,
145 restrictions: None,
146 },
147 );
148
149 let request = ProofRequest {
150 name: "proof-req".to_string(),
151 version: "1.0".to_string(),
152 nonce: "12345".to_string(),
153 requested_attributes,
154 requested_predicates: BTreeMap::new(),
155 };
156
157 let cred = sample_credential();
158 assert!(request.matches_credential(&cred));
159 }
160
161 #[test]
162 fn proof_request_does_not_match_missing_attr() {
163 let mut requested_attributes = BTreeMap::new();
164 requested_attributes.insert(
165 "attr1_referent".to_string(),
166 RequestedAttribute {
167 name: Some("missing_field".to_string()),
168 names: None,
169 restrictions: None,
170 },
171 );
172
173 let request = ProofRequest {
174 name: "proof-req".to_string(),
175 version: "1.0".to_string(),
176 nonce: "99999".to_string(),
177 requested_attributes,
178 requested_predicates: BTreeMap::new(),
179 };
180
181 let cred = sample_credential();
182 assert!(!request.matches_credential(&cred));
183 }
184
185 #[test]
186 fn proof_request_matches_group_names() {
187 let mut requested_attributes = BTreeMap::new();
188 requested_attributes.insert(
189 "group_referent".to_string(),
190 RequestedAttribute {
191 name: None,
192 names: Some(vec!["name".to_string(), "degree".to_string()]),
193 restrictions: None,
194 },
195 );
196
197 let request = ProofRequest {
198 name: "proof-req".to_string(),
199 version: "1.0".to_string(),
200 nonce: "55555".to_string(),
201 requested_attributes,
202 requested_predicates: BTreeMap::new(),
203 };
204
205 let cred = sample_credential();
206 assert!(request.matches_credential(&cred));
207 }
208
209 #[test]
210 fn proof_response_create() {
211 let mut revealed = BTreeMap::new();
212 revealed.insert(
213 "attr1_referent".to_string(),
214 RevealedAttribute {
215 sub_proof_index: 0,
216 raw: "Alice".to_string(),
217 encoded: "123".to_string(),
218 },
219 );
220
221 let response = ProofResponse {
222 revealed_attrs: revealed,
223 self_attested_attrs: BTreeMap::new(),
224 };
225
226 assert_eq!(response.revealed_attrs.len(), 1);
227 assert_eq!(response.revealed_attrs["attr1_referent"].raw, "Alice");
228 }
229}