dubp_documents/certification/
v10.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//! Wrappers around Certification documents V10.
17
18use crate::*;
19
20#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
21/// Wrap an Compact certification document (in block content)
22pub struct CompactCertificationDocumentV10 {
23    /// Issuer
24    pub issuer: ed25519::PublicKey,
25    /// Target
26    pub target: ed25519::PublicKey,
27    /// Blockstamp
28    pub block_number: BlockNumber,
29    /// Signature
30    pub signature: ed25519::Signature,
31}
32
33impl CompactTextDocument for CompactCertificationDocumentV10 {
34    fn as_compact_text(&self) -> String {
35        format!(
36            "{issuer}:{target}:{block_number}:{signature}",
37            issuer = self.issuer,
38            target = self.target,
39            block_number = self.block_number.0,
40            signature = self.signature,
41        )
42    }
43}
44
45#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
46/// identity document for jsonification
47pub struct CompactCertificationDocumentV10Stringified {
48    /// Document issuer
49    pub issuer: String,
50    /// issuer of target identity.
51    pub target: String,
52    /// Block number
53    pub block_number: u64,
54    /// Document signature
55    pub signature: String,
56}
57
58impl ToStringObject for CompactCertificationDocumentV10 {
59    type StringObject = CompactCertificationDocumentV10Stringified;
60    /// Transforms an object into a json object
61    fn to_string_object(&self) -> CompactCertificationDocumentV10Stringified {
62        CompactCertificationDocumentV10Stringified {
63            issuer: format!("{}", self.issuer),
64            target: format!("{}", self.target),
65            block_number: u64::from(self.block_number.0),
66            signature: format!("{}", self.signature),
67        }
68    }
69}
70
71/// Wrap an Certification document.
72///
73/// Must be created by parsing a text document or using a builder.
74#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
75pub struct CertificationDocumentV10 {
76    /// Document as text.
77    ///
78    /// Is used to check signatures, and other values mut be extracted from it.
79    text: String,
80
81    /// Name of the currency.
82    currency: String,
83    /// Document issuer
84    issuer: ed25519::PublicKey,
85    /// issuer of target identity.
86    target: ed25519::PublicKey,
87    /// Username of target identity
88    identity_username: String,
89    /// Target Identity document blockstamp.
90    identity_blockstamp: Blockstamp,
91    /// Target Identity document signature.
92    identity_sig: ed25519::Signature,
93    /// Blockstamp
94    blockstamp: Blockstamp,
95    /// Document signature
96    signature: ed25519::Signature,
97}
98
99#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
100/// identity document for jsonification
101pub struct CertificationDocumentV10Stringified {
102    /// Name of the currency.
103    currency: String,
104    /// Document issuer
105    issuer: String,
106    /// issuer of target identity.
107    target: String,
108    /// Username of target identity
109    identity_username: String,
110    /// Target Identity document blockstamp.
111    identity_blockstamp: String,
112    /// Target Identity document signature.
113    identity_sig: String,
114    /// Blockstamp
115    blockstamp: String,
116    /// Document signature
117    signature: String,
118}
119
120impl ToStringObject for CertificationDocumentV10 {
121    type StringObject = CertificationDocumentV10Stringified;
122    /// Transforms an object into a json object
123    fn to_string_object(&self) -> CertificationDocumentV10Stringified {
124        CertificationDocumentV10Stringified {
125            currency: self.currency.clone(),
126            issuer: self.issuer.to_base58(),
127            target: format!("{}", self.target),
128            identity_username: self.identity_username.clone(),
129            identity_blockstamp: format!("{}", self.identity_blockstamp),
130            blockstamp: format!("{}", self.blockstamp),
131            identity_sig: format!("{}", self.identity_sig),
132            signature: format!("{}", self.signature),
133        }
134    }
135}
136
137impl CertificationDocumentV10 {
138    /// Username of target identity
139    pub fn identity_username(&self) -> &str {
140        &self.identity_username
141    }
142
143    /// PubKey of source identity
144    pub fn source(&self) -> &ed25519::PublicKey {
145        &self.issuer
146    }
147
148    /// PubKey of target identity
149    pub fn target(&self) -> &ed25519::PublicKey {
150        &self.target
151    }
152}
153
154impl Document for CertificationDocumentV10 {
155    type PublicKey = ed25519::PublicKey;
156
157    fn version(&self) -> usize {
158        10
159    }
160
161    fn currency(&self) -> &str {
162        &self.currency
163    }
164
165    fn blockstamp(&self) -> Blockstamp {
166        self.blockstamp
167    }
168
169    fn issuers(&self) -> SmallVec<[Self::PublicKey; 1]> {
170        svec![self.issuer]
171    }
172
173    fn signatures(&self) -> SmallVec<[<Self::PublicKey as PublicKey>::Signature; 1]> {
174        svec![self.signature]
175    }
176
177    fn as_bytes(&self) -> BeefCow<[u8]> {
178        BeefCow::borrowed(self.as_text().as_bytes())
179    }
180}
181
182impl TextDocument for CertificationDocumentV10 {
183    type CompactTextDocument_ = CompactCertificationDocumentV10;
184
185    fn as_text(&self) -> &str {
186        &self.text
187    }
188
189    fn to_compact_document(&self) -> Cow<Self::CompactTextDocument_> {
190        Cow::Owned(CompactCertificationDocumentV10 {
191            issuer: self.issuer,
192            target: self.target,
193            block_number: self.blockstamp().number,
194            signature: self.signatures()[0],
195        })
196    }
197}
198
199/// Certification document builder.
200#[derive(Debug, Copy, Clone)]
201pub struct CertificationDocumentV10Builder<'a> {
202    /// Document currency.
203    pub currency: &'a str,
204    /// Certification issuer (=source).
205    pub issuer: ed25519::PublicKey,
206    /// Reference blockstamp.
207    pub blockstamp: Blockstamp,
208    /// PubKey of target identity.
209    pub target: ed25519::PublicKey,
210    /// Username of target Identity.
211    pub identity_username: &'a str,
212    /// Blockstamp of target Identity.
213    pub identity_blockstamp: Blockstamp,
214    /// Signature of target Identity.
215    pub identity_sig: ed25519::Signature,
216}
217
218impl<'a> TextDocumentBuilder for CertificationDocumentV10Builder<'a> {
219    type Document = CertificationDocumentV10;
220    type Signator = ed25519::Signator;
221
222    fn build_with_text_and_sigs(
223        self,
224        text: String,
225        signatures: SmallVec<
226            [<<Self::Document as Document>::PublicKey as PublicKey>::Signature; 1],
227        >,
228    ) -> CertificationDocumentV10 {
229        CertificationDocumentV10 {
230            text,
231            currency: self.currency.to_string(),
232            issuer: self.issuer,
233            blockstamp: self.blockstamp,
234            target: self.target,
235            identity_username: self.identity_username.to_string(),
236            identity_blockstamp: self.identity_blockstamp,
237            identity_sig: self.identity_sig,
238            signature: signatures[0],
239        }
240    }
241
242    fn generate_text(&self) -> String {
243        format!(
244            "Version: 10
245Type: Certification
246Currency: {currency}
247Issuer: {issuer}
248IdtyIssuer: {target}
249IdtyUniqueID: {idty_uid}
250IdtyTimestamp: {idty_blockstamp}
251IdtySignature: {idty_sig}
252CertTimestamp: {blockstamp}
253",
254            currency = self.currency,
255            issuer = self.issuer,
256            target = self.target,
257            idty_uid = self.identity_username,
258            idty_blockstamp = self.identity_blockstamp,
259            idty_sig = self.identity_sig,
260            blockstamp = self.blockstamp,
261        )
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268    use smallvec::smallvec;
269    use std::str::FromStr;
270    use unwrap::unwrap;
271
272    #[test]
273    fn generate_real_certification_document() {
274        let seed = unwrap!(
275            Seed32::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR"),
276            "fail to build Seed32"
277        );
278        let keypair = ed25519::KeyPairFromSeed32Generator::generate(seed);
279        let pubkey = keypair.public_key();
280        let signator = keypair.generate_signator();
281
282        let sig = unwrap!(ed25519::Signature::from_base64(
283            "sYbaZp3pP9F/CveT1LPiJXECTBHlNurDXqmBo71N7JX/rvmHw6m/sid9bGdIa8cUq+vDD4DMB/F7r7As1p4rAg==",
284        ), "Fail to build Signature");
285
286        let target = unwrap!(
287            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"),
288            "Fail to build PublicKey"
289        );
290
291        let identity_blockstamp = unwrap!(
292            Blockstamp::from_str(
293                "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
294            ),
295            "Fail to build Blockstamp"
296        );
297
298        let identity_sig = unwrap!(ed25519::Signature::from_base64(
299            "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
300        ), "Fail to build Signature");
301
302        let blockstamp = unwrap!(
303            Blockstamp::from_str(
304                "36-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B865",
305            ),
306            "Fail to build Blockstamp"
307        );
308
309        let builder = CertificationDocumentV10Builder {
310            currency: "duniter_unit_test_currency",
311            issuer: pubkey,
312            target,
313            identity_username: "tic",
314            identity_blockstamp,
315            identity_sig,
316            blockstamp,
317        };
318
319        assert!(builder
320            .build_with_signature(smallvec![sig])
321            .verify_signatures()
322            .is_ok());
323
324        assert!(builder
325            .build_and_sign(vec![signator])
326            .verify_signatures()
327            .is_ok());
328    }
329}