1use crate::suite::bounds::{OptionsRefOf, SignatureRefOf, VerificationMethodRefOf};
2use crate::suite::{
3 CryptographicSuiteVerification, InputVerificationOptions, SerializeCryptographicSuite,
4};
5use crate::{
6 CloneCryptographicSuite, CryptographicSuite, DataIntegrity, DebugCryptographicSuite,
7 DeserializeCryptographicSuite,
8};
9use educe::Educe;
10use serde::{Deserialize, Serialize};
11use ssi_claims_core::{AttachProof, ProofValidationError, ProofValidity, ResourceProvider};
12use ssi_core::Lexical;
13use ssi_core::{one_or_many::OneOrManyRef, OneOrMany};
14use ssi_verification_methods::{ProofPurpose, ReferenceOrOwned};
15use std::collections::BTreeMap;
16use std::{
17 borrow::{Borrow, BorrowMut},
18 fmt,
19 ops::{Deref, DerefMut},
20};
21
22mod de;
23
24mod configuration;
25mod reference;
27mod r#type;
28
29pub use configuration::*;
30pub use r#type::*;
32pub use reference::*;
33
34#[derive(Serialize)]
39#[serde(bound = "S: SerializeCryptographicSuite", rename_all = "camelCase")]
40pub struct Proof<S: CryptographicSuite> {
41 #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")]
43 pub context: Option<ssi_json_ld::syntax::Context>,
44
45 #[serde(flatten, serialize_with = "S::serialize_type")]
49 pub type_: S,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub created: Option<Lexical<xsd_types::DateTimeStamp>>,
54
55 #[serde(serialize_with = "S::serialize_verification_method_ref")]
57 pub verification_method: ReferenceOrOwned<S::VerificationMethod>,
58
59 pub proof_purpose: ProofPurpose,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub expires: Option<Lexical<xsd_types::DateTimeStamp>>,
65
66 #[allow(rustdoc::bare_urls)]
67 #[serde(
80 with = "crate::value_or_array",
81 skip_serializing_if = "Vec::is_empty",
82 rename = "domain"
83 )]
84 pub domains: Vec<String>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
92 pub challenge: Option<String>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
99 pub nonce: Option<String>,
100
101 #[serde(flatten, serialize_with = "S::serialize_proof_options")]
106 pub options: S::ProofOptions,
107
108 #[serde(flatten, serialize_with = "S::serialize_signature")]
110 pub signature: S::Signature,
111
112 #[serde(flatten)]
114 pub extra_properties: BTreeMap<String, json_syntax::Value>,
115}
116
117impl<T: CryptographicSuite> Proof<T> {
118 pub fn new(
120 type_: T,
121 created: Lexical<xsd_types::DateTimeStamp>,
122 verification_method: ReferenceOrOwned<T::VerificationMethod>,
123 proof_purpose: ProofPurpose,
124 options: T::ProofOptions,
125 signature: T::Signature,
126 ) -> Self {
127 Self {
128 context: None,
129 type_,
130 created: Some(created),
131 verification_method,
132 proof_purpose,
133 expires: None,
134 domains: Vec::new(),
135 challenge: None,
136 nonce: None,
137 options,
138 signature,
139 extra_properties: Default::default(),
140 }
141 }
142
143 pub fn borrowed(&self) -> ProofRef<T> {
144 ProofRef {
145 context: self.context.as_ref(),
146 type_: &self.type_,
147 created: self.created.as_ref(),
148 verification_method: self.verification_method.borrowed(),
149 proof_purpose: self.proof_purpose,
150 expires: self.expires.as_ref(),
151 domains: &self.domains,
152 challenge: self.challenge.as_deref(),
153 nonce: self.nonce.as_deref(),
154 options: &self.options,
155 signature: &self.signature,
156 extra_properties: &self.extra_properties,
157 }
158 }
159
160 pub fn with_context(self, context: ssi_json_ld::syntax::Context) -> Self {
161 Self {
162 context: Some(context),
163 ..self
164 }
165 }
166
167 pub fn suite(&self) -> &T {
168 &self.type_
169 }
170
171 pub fn configuration(&self) -> ProofConfigurationRef<T> {
172 ProofConfigurationRef {
173 context: self.context.as_ref(),
174 type_: &self.type_,
175 created: self.created.as_ref(),
176 verification_method: self.verification_method.borrowed(),
177 proof_purpose: self.proof_purpose,
178 expires: self.expires.as_ref(),
179 domains: &self.domains,
180 challenge: self.challenge.as_deref(),
181 nonce: self.nonce.as_deref(),
182 options: &self.options,
183 extra_properties: &self.extra_properties,
184 }
185 }
186
187 pub fn map_type<U: CryptographicSuite>(
188 self,
189 type_: impl FnOnce(T) -> U,
190 verification_method: impl FnOnce(T::VerificationMethod) -> U::VerificationMethod,
191 options: impl FnOnce(T::ProofOptions) -> U::ProofOptions,
192 signature: impl FnOnce(T::Signature) -> U::Signature,
193 ) -> Proof<U> {
194 Proof {
195 context: self.context,
196 type_: type_(self.type_),
197 created: self.created,
198 verification_method: self.verification_method.map(verification_method),
199 proof_purpose: self.proof_purpose,
200 expires: self.expires,
201 domains: self.domains,
202 challenge: self.challenge,
203 nonce: self.nonce,
204 options: options(self.options),
205 signature: signature(self.signature),
206 extra_properties: self.extra_properties,
207 }
208 }
209}
210
211impl<S: CloneCryptographicSuite> Clone for Proof<S> {
212 fn clone(&self) -> Self {
213 Self {
214 context: self.context.clone(),
215 type_: self.type_.clone(),
216 created: self.created.clone(),
217 verification_method: S::clone_verification_method_ref(&self.verification_method),
218 proof_purpose: self.proof_purpose,
219 expires: self.expires.clone(),
220 domains: self.domains.clone(),
221 challenge: self.challenge.clone(),
222 nonce: self.nonce.clone(),
223 options: S::clone_proof_options(&self.options),
224 signature: S::clone_signature(&self.signature),
225 extra_properties: self.extra_properties.clone(),
226 }
227 }
228}
229
230impl<S: DebugCryptographicSuite> fmt::Debug for Proof<S> {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 f.debug_struct("Proof")
233 .field("context", &self.context)
234 .field("type_", &self.type_)
235 .field("created", &self.created)
236 .field(
237 "verification_method",
238 &VerificationMethodRefOf::<S>(self.verification_method.borrowed()),
239 )
240 .field("proof_purpose", &self.proof_purpose)
241 .field("expires", &self.expires)
242 .field("domains", &self.domains)
243 .field("challenge", &self.challenge)
244 .field("nonce", &self.nonce)
245 .field("options", &OptionsRefOf::<S>(&self.options))
246 .field("signature", &SignatureRefOf::<S>(&self.signature))
247 .field("extra_properties", &self.extra_properties)
248 .finish()
249 }
250}
251
252impl<S: CryptographicSuite, T, V> ssi_claims_core::ValidateProof<V, T> for Proof<S>
253where
254 S: CryptographicSuiteVerification<T, V>,
255 V: ResourceProvider<InputVerificationOptions<S>>,
256{
257 async fn validate_proof<'a>(
258 &'a self,
259 verifier: &'a V,
260 claims: &'a T,
261 ) -> Result<ProofValidity, ProofValidationError> {
262 let transformation_options = self
263 .suite()
264 .configure_verification(verifier.get_resource())?;
265 self.suite()
266 .verify_proof(verifier, claims, self.borrowed(), transformation_options)
267 .await
268 }
269}
270
271impl<T, S: CryptographicSuite> AttachProof<T> for Proof<S> {
272 type Attached = DataIntegrity<T, S>;
273
274 fn attach_to(self, claims: T) -> Self::Attached {
275 DataIntegrity::new(claims, self.into())
276 }
277}
278
279#[derive(Educe)]
281#[educe(Debug(bound("S: DebugCryptographicSuite")))]
282#[educe(Clone(bound("S: CloneCryptographicSuite")))]
283#[educe(Default)]
284pub struct Proofs<S: CryptographicSuite>(pub(crate) Vec<Proof<S>>);
285
286impl<S: CryptographicSuite> Proofs<S> {
287 pub fn new() -> Self {
288 Self::default()
289 }
290
291 pub fn is_empty(&self) -> bool {
292 self.0.is_empty()
293 }
294
295 pub fn as_slice(&self) -> &[Proof<S>] {
296 &self.0
297 }
298
299 pub fn as_mut_slice(&mut self) -> &mut [Proof<S>] {
300 &mut self.0
301 }
302
303 pub fn iter(&self) -> std::slice::Iter<Proof<S>> {
304 self.0.iter()
305 }
306
307 pub fn iter_mut(&mut self) -> std::slice::IterMut<Proof<S>> {
308 self.0.iter_mut()
309 }
310}
311
312impl<S: CryptographicSuite> Deref for Proofs<S> {
313 type Target = Vec<Proof<S>>;
314
315 fn deref(&self) -> &Self::Target {
316 &self.0
317 }
318}
319
320impl<S: CryptographicSuite> DerefMut for Proofs<S> {
321 fn deref_mut(&mut self) -> &mut Self::Target {
322 &mut self.0
323 }
324}
325
326impl<S: CryptographicSuite> Borrow<[Proof<S>]> for Proofs<S> {
327 fn borrow(&self) -> &[Proof<S>] {
328 self.as_slice()
329 }
330}
331
332impl<S: CryptographicSuite> BorrowMut<[Proof<S>]> for Proofs<S> {
333 fn borrow_mut(&mut self) -> &mut [Proof<S>] {
334 self.as_mut_slice()
335 }
336}
337
338impl<S: CryptographicSuite> AsRef<[Proof<S>]> for Proofs<S> {
339 fn as_ref(&self) -> &[Proof<S>] {
340 self.as_slice()
341 }
342}
343
344impl<S: CryptographicSuite> AsMut<[Proof<S>]> for Proofs<S> {
345 fn as_mut(&mut self) -> &mut [Proof<S>] {
346 self.as_mut_slice()
347 }
348}
349
350impl<S: CryptographicSuite> From<Proof<S>> for Proofs<S> {
351 fn from(value: Proof<S>) -> Self {
352 Self(vec![value])
353 }
354}
355
356impl<S: CryptographicSuite> From<Vec<Proof<S>>> for Proofs<S> {
357 fn from(value: Vec<Proof<S>>) -> Self {
358 Self(value)
359 }
360}
361
362impl<S: CryptographicSuite> FromIterator<Proof<S>> for Proofs<S> {
363 fn from_iter<T: IntoIterator<Item = Proof<S>>>(iter: T) -> Self {
364 Proofs(Vec::from_iter(iter))
365 }
366}
367
368impl<S: CryptographicSuite, T, V> ssi_claims_core::ValidateProof<V, T> for Proofs<S>
369where
370 S: CryptographicSuiteVerification<T, V>,
371 V: ResourceProvider<InputVerificationOptions<S>>,
372{
373 async fn validate_proof<'a>(
374 &'a self,
375 verifier: &'a V,
376 claims: &'a T,
377 ) -> Result<ProofValidity, ProofValidationError> {
378 self.0.validate_proof(verifier, claims).await
379 }
380}
381
382impl<T, S: CryptographicSuite> AttachProof<T> for Proofs<S> {
383 type Attached = DataIntegrity<T, S>;
384
385 fn attach_to(self, claims: T) -> Self::Attached {
386 DataIntegrity::new(claims, self)
387 }
388}
389
390impl<S: CryptographicSuite> Extend<Proof<S>> for Proofs<S> {
391 fn extend<T: IntoIterator<Item = Proof<S>>>(&mut self, iter: T) {
392 self.0.extend(iter)
393 }
394}
395
396impl<S: CryptographicSuite> IntoIterator for Proofs<S> {
397 type IntoIter = std::vec::IntoIter<Proof<S>>;
398 type Item = Proof<S>;
399
400 fn into_iter(self) -> Self::IntoIter {
401 self.0.into_iter()
402 }
403}
404
405impl<'a, S: CryptographicSuite> IntoIterator for &'a Proofs<S> {
406 type IntoIter = std::slice::Iter<'a, Proof<S>>;
407 type Item = &'a Proof<S>;
408
409 fn into_iter(self) -> Self::IntoIter {
410 self.iter()
411 }
412}
413
414impl<'a, S: CryptographicSuite> IntoIterator for &'a mut Proofs<S> {
415 type IntoIter = std::slice::IterMut<'a, Proof<S>>;
416 type Item = &'a mut Proof<S>;
417
418 fn into_iter(self) -> Self::IntoIter {
419 self.iter_mut()
420 }
421}
422
423impl<T: SerializeCryptographicSuite> Serialize for Proofs<T> {
424 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
425 where
426 S: serde::Serializer,
427 {
428 OneOrManyRef::from_slice(&self.0).serialize(serializer)
429 }
430}
431
432impl<'de, S: DeserializeCryptographicSuite<'de>> Deserialize<'de> for Proofs<S> {
433 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
434 where
435 D: serde::Deserializer<'de>,
436 {
437 match OneOrMany::<Proof<S>>::deserialize(deserializer)? {
438 OneOrMany::One(proof) => Ok(Self(vec![proof])),
439 OneOrMany::Many(proofs) => Ok(Self(proofs)),
440 }
441 }
442}
443
444pub mod value_or_array {
445 use serde::{Deserialize, Serialize};
446 use ssi_core::OneOrMany;
447
448 pub fn serialize<T: Serialize, S>(value: &[T], serializer: S) -> Result<S::Ok, S::Error>
449 where
450 S: serde::Serializer,
451 {
452 match value.split_first() {
453 Some((first, [])) => first.serialize(serializer),
454 _ => value.serialize(serializer),
455 }
456 }
457
458 pub fn deserialize<'de, T: Deserialize<'de>, D>(deserializer: D) -> Result<Vec<T>, D::Error>
459 where
460 D: serde::Deserializer<'de>,
461 {
462 Ok(OneOrMany::deserialize(deserializer)?.into_vec())
463 }
464}