Skip to main content

fi_verifiable_data/
proof.rs

1use chrono::Utc;
2use fi_digital_signatures::{
3    algorithms::Algorithm, signer::get_signing_key, verifier::get_verifying_key,
4};
5use serde::{Deserialize, Serialize};
6#[cfg(feature = "wasm")]
7use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
8
9use crate::{document::VerificationDocument, error::FiError};
10
11pub trait Proof {
12    fn sign(&mut self, doc: &mut VerificationDocument, content: String) -> Result<(), FiError>;
13    fn verify(&self, doc: &mut VerificationDocument, content: String) -> Result<bool, FiError>;
14}
15
16#[derive(Serialize, Deserialize, Clone)]
17pub struct FiProof {
18    #[serde(rename = "type")]
19    _type: String,
20    created: String,
21    algorithm: String,
22    #[serde(rename = "proofPurpose")]
23    proof_purpose: String,
24    jws: Option<String>,
25}
26
27impl Proof for FiProof {
28    fn sign(&mut self, doc: &mut VerificationDocument, content: String) -> Result<(), FiError> {
29        let key_bytes = match doc.get_private_key_mut() {
30            None => {
31                return Err(FiError::new(
32                    "No private key was found in the VerificationDocument",
33                ))
34            }
35            Some(val) => val,
36        };
37
38        let alg = match Algorithm::from_str(self.algorithm.as_str()) {
39            Some(val) => val,
40            None => return Err(FiError::new("Algorithm cannot be identified.")),
41        };
42
43        let signing_key = match get_signing_key(alg, key_bytes.as_mut_slice()) {
44            Ok(val) => val,
45            Err(error) => {
46                eprintln!("{}", error);
47                return Err(FiError::new("Failed to get signing key"));
48            }
49        };
50
51        match signing_key.sign(content, alg) {
52            Ok(val) => {
53                self.jws = Some(val);
54                Ok(())
55            }
56            Err(error) => {
57                eprintln!("{}", error);
58                return Err(FiError::new("Failed to sign content"));
59            }
60        }
61    }
62
63    fn verify(&self, doc: &mut VerificationDocument, content: String) -> Result<bool, FiError> {
64        let key_bytes = match doc.get_public_key_mut() {
65            None => {
66                return Err(FiError::new(
67                    "No publuc key was found in the VerificationDocument",
68                ))
69            }
70            Some(val) => val,
71        };
72
73        let alg = match Algorithm::from_str(self.algorithm.as_str()) {
74            None => return Err(FiError::new("Provided algorithm is no supported")),
75            Some(val) => val,
76        };
77
78        let verifying_key = match get_verifying_key(alg, key_bytes.as_mut_slice()) {
79            Ok(val) => val,
80            Err(error) => {
81                eprintln!("{}", error);
82                return Err(FiError::new("Failed to get signing key"));
83            }
84        };
85
86        match self.jws.clone() {
87            Some(val) => match verifying_key.verify(content, val, alg) {
88                Ok(val) => Ok(val),
89                Err(error) => {
90                    eprintln!("{}", error);
91                    return Err(FiError::new("Failed to verify content"));
92                }
93            },
94            None => {
95                return Err(FiError::new("Failed to verify content"));
96            }
97        }
98    }
99}
100
101impl FiProof {
102    pub fn new(alg: Algorithm, purpose: String) -> Self {
103        let datetime = Utc::now().to_rfc3339();
104        return FiProof {
105            _type: String::from("FiProof"),
106            algorithm: String::from(alg.to_str()),
107            proof_purpose: purpose,
108            created: datetime.to_string(),
109            jws: None,
110        };
111    }
112}
113
114#[cfg(feature = "wasm")]
115#[wasm_bindgen]
116pub enum ProofType {
117    FiProof,
118}
119
120#[cfg(feature = "wasm")]
121impl ProofType {
122    pub fn sign(
123        &self,
124        alg: Algorithm,
125        purpose: String,
126        doc: &mut VerificationDocument,
127        content: String,
128    ) -> Result<JsValue, FiError> {
129        match self {
130            ProofType::FiProof => {
131                let mut proof = FiProof::new(alg, purpose);
132                _ = proof.sign(doc, content);
133
134                match serde_wasm_bindgen::to_value(&proof) {
135                    Ok(val) => return Ok(val),
136                    Err(err) => return Err(FiError::new(err.to_string().as_str())),
137                }
138            }
139        }
140    }
141
142    pub fn verify(
143        &self,
144        doc: &mut VerificationDocument,
145        content: String,
146        proof: JsValue,
147    ) -> Result<bool, FiError> {
148        match self {
149            ProofType::FiProof => {
150                let fi_proof: FiProof = match serde_wasm_bindgen::from_value(proof) {
151                    Err(error) => return Err(FiError::new(error.to_string().as_str())),
152                    Ok(val) => val,
153                };
154
155                fi_proof.verify(doc, content)
156            }
157        }
158    }
159}