ssi_data_integrity_core/proof/
mod.rs

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;
25// mod prepared;
26mod reference;
27mod r#type;
28
29pub use configuration::*;
30// pub use prepared::*;
31pub use r#type::*;
32pub use reference::*;
33
34/// Data Integrity Proof.
35///
36/// A data integrity proof provides information about the proof mechanism,
37/// parameters required to verify that proof, and the proof value itself.
38#[derive(Serialize)]
39#[serde(bound = "S: SerializeCryptographicSuite", rename_all = "camelCase")]
40pub struct Proof<S: CryptographicSuite> {
41    /// Proof context.
42    #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")]
43    pub context: Option<ssi_json_ld::syntax::Context>,
44
45    /// Proof type.
46    ///
47    /// Also includes the cryptographic suite variant.
48    #[serde(flatten, serialize_with = "S::serialize_type")]
49    pub type_: S,
50
51    /// Date a creation of the proof.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub created: Option<Lexical<xsd_types::DateTimeStamp>>,
54
55    /// Verification method.
56    #[serde(serialize_with = "S::serialize_verification_method_ref")]
57    pub verification_method: ReferenceOrOwned<S::VerificationMethod>,
58
59    /// Purpose of the proof.
60    pub proof_purpose: ProofPurpose,
61
62    /// Specifies when the proof expires.
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub expires: Option<Lexical<xsd_types::DateTimeStamp>>,
65
66    #[allow(rustdoc::bare_urls)]
67    /// Conveys one or more security domains in which the proof is meant to be
68    /// used.
69    ///
70    /// A verifier SHOULD use the value to ensure that the proof was intended to
71    /// be used in the security domain in which the verifier is operating. The
72    /// specification of the domain parameter is useful in challenge-response
73    /// protocols where the verifier is operating from within a security domain
74    /// known to the creator of the proof.
75    ///
76    /// Example domain values include: `domain.example`` (DNS domain),
77    /// `https://domain.example:8443` (Web origin), `mycorp-intranet` (bespoke
78    /// text string), and `b31d37d4-dd59-47d3-9dd8-c973da43b63a` (UUID).
79    #[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    /// Used to mitigate replay attacks.
87    ///
88    /// Used once for a particular domain and window of time. Examples of a
89    /// challenge value include: `1235abcd6789`,
90    /// `79d34551-ae81-44ae-823b-6dadbab9ebd4`, and `ruby`.
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub challenge: Option<String>,
93
94    /// Arbitrary string supplied by the proof creator.
95    ///
96    /// One use of this field is to increase privacy by decreasing linkability
97    /// that is the result of deterministically generated signatures.
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub nonce: Option<String>,
100
101    /// Additional proof options required by the cryptographic suite.
102    ///
103    /// For instance, tezos cryptosuites requires the public key associated with
104    /// the verification method, which is a blockchain account id.
105    #[serde(flatten, serialize_with = "S::serialize_proof_options")]
106    pub options: S::ProofOptions,
107
108    /// Proof signature.
109    #[serde(flatten, serialize_with = "S::serialize_signature")]
110    pub signature: S::Signature,
111
112    /// Extra properties unrelated to the cryptographic suite.
113    #[serde(flatten)]
114    pub extra_properties: BTreeMap<String, json_syntax::Value>,
115}
116
117impl<T: CryptographicSuite> Proof<T> {
118    /// Creates a new proof.
119    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/// Set of Data-Integrity proofs.
280#[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}