ssi_data_integrity_core/proof/configuration/
mod.rs

1use iref::Iri;
2use serde::Serialize;
3use ssi_core::Lexical;
4use ssi_verification_methods::{ProofPurpose, ReferenceOrOwned};
5use static_iref::iri;
6use std::collections::BTreeMap;
7
8use crate::{CryptographicSuite, Proof, ProofOptions, SerializeCryptographicSuite};
9
10pub const DC_CREATED_IRI: &Iri = iri!("http://purl.org/dc/terms/created");
11
12pub const XSD_DATETIME_IRI: &Iri = iri!("http://www.w3.org/2001/XMLSchema#dateTime");
13
14mod expansion;
15mod reference;
16
17pub use expansion::*;
18pub use reference::*;
19
20/// Proof configuration.
21///
22/// Proof object without the signature value.
23#[derive(Debug, Clone, Serialize)]
24#[serde(rename_all = "camelCase", bound = "S: SerializeCryptographicSuite")]
25pub struct ProofConfiguration<S: CryptographicSuite> {
26    #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")]
27    pub context: Option<ssi_json_ld::syntax::Context>,
28
29    /// Proof type.
30    #[serde(flatten, serialize_with = "S::serialize_type")]
31    pub type_: S,
32
33    /// Date a creation of the proof.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub created: Option<Lexical<xsd_types::DateTimeStamp>>,
36
37    /// Verification method.
38    #[serde(serialize_with = "S::serialize_verification_method_ref")]
39    pub verification_method: ReferenceOrOwned<S::VerificationMethod>,
40
41    /// Purpose of the proof.
42    pub proof_purpose: ProofPurpose,
43
44    /// Specifies when the proof expires.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub expires: Option<Lexical<xsd_types::DateTimeStamp>>,
47
48    #[allow(rustdoc::bare_urls)]
49    /// Conveys one or more security domains in which the proof is meant to be
50    /// used.
51    ///
52    /// A verifier SHOULD use the value to ensure that the proof was intended to
53    /// be used in the security domain in which the verifier is operating. The
54    /// specification of the domain parameter is useful in challenge-response
55    /// protocols where the verifier is operating from within a security domain
56    /// known to the creator of the proof.
57    ///
58    /// Example domain values include: `domain.example`` (DNS domain),
59    /// `https://domain.example:8443` (Web origin), `mycorp-intranet` (bespoke
60    /// text string), and `b31d37d4-dd59-47d3-9dd8-c973da43b63a` (UUID).
61    #[serde(
62        with = "crate::value_or_array",
63        skip_serializing_if = "Vec::is_empty",
64        rename = "domain"
65    )]
66    pub domains: Vec<String>,
67
68    /// Used to mitigate replay attacks.
69    ///
70    /// Used once for a particular domain and window of time. Examples of a
71    /// challenge value include: `1235abcd6789`,
72    /// `79d34551-ae81-44ae-823b-6dadbab9ebd4`, and `ruby`.
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub challenge: Option<String>,
75
76    /// Arbitrary string supplied by the proof creator.
77    ///
78    /// One use of this field is to increase privacy by decreasing linkability
79    /// that is the result of deterministically generated signatures.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub nonce: Option<String>,
82
83    /// Additional proof options required by the cryptographic suite.
84    ///
85    /// For instance, tezos cryptosuites requires the public key associated with
86    /// the verification method, which is a blockchain account id.
87    #[serde(flatten, serialize_with = "S::serialize_proof_options")]
88    pub options: S::ProofOptions,
89
90    /// Extra properties.
91    #[serde(flatten)]
92    pub extra_properties: BTreeMap<String, json_syntax::Value>,
93}
94
95impl<S: CryptographicSuite> ProofConfiguration<S> {
96    pub fn new(
97        type_: S,
98        created: Lexical<xsd_types::DateTimeStamp>,
99        verification_method: ReferenceOrOwned<S::VerificationMethod>,
100        proof_purpose: ProofPurpose,
101        options: S::ProofOptions,
102    ) -> Self {
103        Self {
104            context: None,
105            type_,
106            created: Some(created),
107            verification_method,
108            proof_purpose,
109            expires: None,
110            domains: Vec::new(),
111            challenge: None,
112            nonce: None,
113            options,
114            extra_properties: BTreeMap::new(),
115        }
116    }
117
118    pub fn from_method_and_options(
119        type_: S,
120        verification_method: ReferenceOrOwned<S::VerificationMethod>,
121        options: S::ProofOptions,
122    ) -> Self {
123        Self {
124            context: None,
125            type_,
126            created: Some(xsd_types::DateTimeStamp::now_ms().into()),
127            verification_method,
128            proof_purpose: ProofPurpose::default(),
129            expires: None,
130            domains: Vec::new(),
131            challenge: None,
132            nonce: None,
133            options,
134            extra_properties: BTreeMap::new(),
135        }
136    }
137
138    pub fn from_method(
139        type_: S,
140        verification_method: ReferenceOrOwned<S::VerificationMethod>,
141    ) -> Self
142    where
143        S::ProofOptions: Default,
144    {
145        Self::from_method_and_options(type_, verification_method, Default::default())
146    }
147
148    pub fn into_suite_and_options(
149        self,
150    ) -> (S, ProofOptions<S::VerificationMethod, S::ProofOptions>) {
151        (
152            self.type_,
153            ProofOptions {
154                context: self.context,
155                created: self.created,
156                verification_method: Some(self.verification_method),
157                proof_purpose: self.proof_purpose,
158                expires: self.expires,
159                domains: self.domains,
160                challenge: self.challenge,
161                nonce: self.nonce,
162                options: self.options,
163                extra_properties: self.extra_properties,
164            },
165        )
166    }
167
168    pub fn into_options(self) -> ProofOptions<S::VerificationMethod, S::ProofOptions> {
169        ProofOptions {
170            context: self.context,
171            created: self.created,
172            verification_method: Some(self.verification_method),
173            proof_purpose: self.proof_purpose,
174            expires: self.expires,
175            domains: self.domains,
176            challenge: self.challenge,
177            nonce: self.nonce,
178            options: self.options,
179            extra_properties: self.extra_properties,
180        }
181    }
182
183    pub fn into_proof(self, signature: S::Signature) -> Proof<S> {
184        Proof {
185            context: self.context,
186            type_: self.type_,
187            created: self.created,
188            verification_method: self.verification_method,
189            proof_purpose: self.proof_purpose,
190            expires: self.expires,
191            domains: self.domains,
192            challenge: self.challenge,
193            nonce: self.nonce,
194            options: self.options,
195            signature,
196            extra_properties: self.extra_properties,
197        }
198    }
199
200    pub fn map<T: CryptographicSuite>(
201        self,
202        map_type: impl FnOnce(S) -> T,
203        map_verification_method: impl FnOnce(S::VerificationMethod) -> T::VerificationMethod,
204        map_options: impl FnOnce(S::ProofOptions) -> T::ProofOptions,
205    ) -> ProofConfiguration<T> {
206        ProofConfiguration {
207            context: self.context,
208            type_: map_type(self.type_),
209            created: self.created,
210            verification_method: self.verification_method.map(map_verification_method),
211            proof_purpose: self.proof_purpose,
212            expires: self.expires,
213            domains: self.domains,
214            challenge: self.challenge,
215            nonce: self.nonce,
216            options: map_options(self.options),
217            extra_properties: self.extra_properties,
218        }
219    }
220
221    pub fn borrowed(&'_ self) -> ProofConfigurationRef<'_, S> {
222        ProofConfigurationRef {
223            context: self.context.as_ref(),
224            type_: &self.type_,
225            created: self.created.as_ref(),
226            verification_method: self.verification_method.borrowed(),
227            proof_purpose: self.proof_purpose,
228            expires: self.expires.as_ref(),
229            domains: &self.domains,
230            challenge: self.challenge.as_deref(),
231            nonce: self.nonce.as_deref(),
232            options: &self.options,
233            extra_properties: &self.extra_properties,
234        }
235    }
236}
237
238#[derive(Debug, thiserror::Error)]
239pub enum ProofConfigurationCastError<M, O> {
240    #[error("invalid verification method")]
241    VerificationMethod(M),
242
243    #[error("invalid options")]
244    Options(O),
245}