rock_n_rollup/plugins/
crypto.rs

1use base58::{FromBase58, ToBase58};
2use sha2::{Digest, Sha256};
3
4use crate::core::Runtime;
5use crate::plugins::hasher::Hasher;
6
7/// TODO: extract this function in the core module
8/// And find a way to have a generic way to generate to_b58 and from_b58
9fn from_base58(prefix_size: usize, encoded: &str) -> Result<Vec<u8>, ()> {
10    let check_sum_size = 4;
11    let decoded = encoded.from_base58().map_err(|_| ())?;
12    let _payload = &decoded[..decoded.len() - check_sum_size]; // Remove the check sum
13    let bytes = decoded[prefix_size..].to_vec();
14    let bytes = bytes[..bytes.len() - check_sum_size].to_vec();
15    Ok(bytes)
16}
17
18/// TODO: extract this
19fn to_base58(prefix: Vec<u8>, data: &[u8]) -> String {
20    let mut result = prefix;
21    result.extend(data);
22    let checksum = Sha256::digest(&Sha256::digest(&result)).to_vec()[..4].to_vec();
23    result.extend(checksum);
24    result.to_base58()
25}
26
27#[derive(Clone)]
28pub enum PublicKey {
29    /// tz1 address
30    Ed25519(ed25519_compact::PublicKey),
31}
32
33#[derive(Clone)]
34pub enum Signature {
35    Ed25519(ed25519_compact::Signature),
36}
37
38impl TryFrom<String> for PublicKey {
39    type Error = ();
40
41    fn try_from(value: String) -> Result<Self, Self::Error> {
42        let public_key = from_base58(4, &value)?;
43        let ed25519 = ed25519_compact::PublicKey::from_slice(&public_key).map_err(|_| ())?;
44        Ok(PublicKey::Ed25519(ed25519))
45    }
46}
47
48impl ToString for PublicKey {
49    fn to_string(&self) -> String {
50        match self {
51            PublicKey::Ed25519(ed25519) => {
52                let bytes = ed25519.as_ref();
53
54                to_base58(vec![13, 15, 37, 217], bytes)
55            }
56        }
57    }
58}
59
60impl TryFrom<String> for Signature {
61    type Error = ();
62    fn try_from(value: String) -> Result<Self, Self::Error> {
63        let signature = from_base58(5, &value)?;
64        let sig = ed25519_compact::Signature::from_slice(&signature).map_err(|_| ())?;
65        Ok(Signature::Ed25519(sig))
66    }
67}
68
69pub trait Verifier {
70    /// Verify the signature for a given public key over the hash of the given data
71    ///
72    /// The data passed as parameter will be hashed
73    /// Then the public will be used to verify that the signature is indeed the signature of the generated hash
74    fn verify_signature(
75        &mut self,
76        signature: &Signature,
77        public_key: &PublicKey,
78        data: &[u8],
79    ) -> bool;
80}
81
82impl<R> Verifier for R
83where
84    R: Runtime + Hasher,
85{
86    fn verify_signature(
87        &mut self,
88        signature: &Signature,
89        public_key: &PublicKey,
90        data: &[u8],
91    ) -> bool {
92        let data = self.hash(data);
93
94        match (signature, public_key) {
95            (Signature::Ed25519(sig), PublicKey::Ed25519(pkey)) => {
96                let res = pkey.verify(data, sig);
97                res.is_ok()
98            }
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::{PublicKey, Signature, Verifier};
106    use crate::core::MockRuntime;
107
108    #[test]
109    fn test_ed25519_pkey_deserialization() {
110        let string = "edpkuDMUm7Y53wp4gxeLBXuiAhXZrLn8XB1R83ksvvesH8Lp8bmCfK".to_string();
111        let pkey = PublicKey::try_from(string);
112
113        assert!(pkey.is_ok())
114    }
115
116    #[test]
117    fn test_ed25519_pkey_serialization() {
118        let string = "edpkuDMUm7Y53wp4gxeLBXuiAhXZrLn8XB1R83ksvvesH8Lp8bmCfK".to_string();
119        let pkey = PublicKey::try_from(string.clone()).unwrap().to_string();
120
121        assert_eq!(string, pkey);
122    }
123
124    #[test]
125    fn test_ed25519_signature_deserialization() {
126        let encoded = "edsigtuU5nUqBniorqTFXFixkG6ZkfvEPrfc9aT9DnMAeims2AX2yjpgYaedXBoKzAGHE3ZXSi1hZz6piZ3itTE7f2F4FoaxXtM";
127        let signature = Signature::try_from(encoded.to_string());
128
129        assert!(signature.is_ok())
130    }
131
132    #[test]
133    fn test_verify_ed25519_signature() {
134        let mut rt = MockRuntime::default();
135
136        let encoded = "edpkuDMUm7Y53wp4gxeLBXuiAhXZrLn8XB1R83ksvvesH8Lp8bmCfK";
137        let public_key = PublicKey::try_from(encoded.to_string()).unwrap();
138
139        /////////
140        let encoded = "edsigtuU5nUqBniorqTFXFixkG6ZkfvEPrfc9aT9DnMAeims2AX2yjpgYaedXBoKzAGHE3ZXSi1hZz6piZ3itTE7f2F4FoaxXtM";
141        let signature = Signature::try_from(encoded.to_string()).unwrap();
142
143        //// Check the signature
144        let data = "hello world".as_bytes();
145
146        let is_ok = rt.verify_signature(&signature, &public_key, data);
147
148        assert!(is_ok);
149    }
150}