dubp_documents/
traits.rs

1//  Copyright (C) 2020  Éloïs SANCHEZ.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16//! Define DUBP Documents Traits.
17
18pub mod text;
19
20use crate::*;
21
22/// trait providing commun methods for any documents of any protocol version.
23pub trait Document: Debug + Clone + PartialEq + Eq {
24    /// Type of the `PublicKey` used by the document.
25    type PublicKey: PublicKey;
26
27    /// Get document as bytes for signature verification.
28    ///
29    /// Some documents do not directly store the sequence of bytes that will be signed but generate
30    // it on request, so these types of documents cannot provide a reference to the signed bytes.
31    /// This is why this method must return a `Cow<[u8]>` (we use the beef implementation instead of the std implementation).
32    fn as_bytes(&self) -> BeefCow<[u8]>;
33
34    /// Get document blockstamp
35    fn blockstamp(&self) -> Blockstamp;
36
37    /// Get document currency name.
38    fn currency(&self) -> &str;
39
40    /// Iterate over document issuers.
41    fn issuers(&self) -> SmallVec<[Self::PublicKey; 1]>;
42
43    /// Iterate over document signatures.
44    fn signatures(&self) -> SmallVec<[<Self::PublicKey as PublicKey>::Signature; 1]>;
45
46    /// Verify one signature
47    #[inline]
48    fn verify_one_signature(
49        &self,
50        public_key: &Self::PublicKey,
51        signature: &<Self::PublicKey as PublicKey>::Signature,
52    ) -> Result<(), SigError> {
53        public_key.verify(self.as_bytes().as_ref(), signature)
54    }
55
56    /// Verify signatures of document content
57    fn verify_signatures(&self) -> Result<(), DocumentSigsErr> {
58        let issuers_count = self.issuers().len();
59        let signatures_count = self.signatures().len();
60
61        if issuers_count != signatures_count {
62            Err(DocumentSigsErr::IncompletePairs(
63                issuers_count,
64                signatures_count,
65            ))
66        } else {
67            let issuers = self.issuers();
68            let signatures = self.signatures();
69            let mismatches: HashMap<usize, SigError> = issuers
70                .iter()
71                .zip(signatures)
72                .enumerate()
73                .filter_map(|(i, (key, signature))| {
74                    if let Err(e) = self.verify_one_signature(key, &signature) {
75                        Some((i, e))
76                    } else {
77                        None
78                    }
79                })
80                .collect();
81
82            if mismatches.is_empty() {
83                Ok(())
84            } else {
85                Err(DocumentSigsErr::Invalid(mismatches))
86            }
87        }
88    }
89
90    /// Get document version.
91    fn version(&self) -> usize;
92}
93
94/// Trait helper for building new documents.
95pub trait DocumentBuilder {
96    /// Type of the builded document.
97    type Document: Document;
98
99    /// Type of the signator signing the documents.
100    type Signator: Signator<PublicKey = <Self::Document as Document>::PublicKey>;
101
102    /// Build a document and sign it with the private key.
103    fn build_and_sign(self, signators: Vec<Self::Signator>) -> Self::Document;
104
105    /// Build a document with provided signatures.
106    fn build_with_signature(
107        self,
108        signatures: SmallVec<
109            [<<Self::Document as Document>::PublicKey as PublicKey>::Signature; 1],
110        >,
111    ) -> Self::Document;
112}
113
114/// Stringify a document
115pub trait ToStringObject {
116    /// Generated string object
117    type StringObject: Serialize;
118
119    /// Transforms object fields into string
120    fn to_string_object(&self) -> Self::StringObject;
121}
122
123/// Jsonify a document
124pub trait ToJsonObject: ToStringObject {
125    /// Convert to JSON String
126    fn to_json_string(&self) -> Result<String, serde_json::Error> {
127        serde_json::to_string(&self.to_string_object())
128    }
129    /// Convert to JSON String pretty
130    fn to_json_string_pretty(&self) -> Result<String, serde_json::Error> {
131        serde_json::to_string_pretty(&self.to_string_object())
132    }
133}
134
135impl<T: ToStringObject> ToJsonObject for T {}