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 {}