1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! `keypair` module provide primary object to generate [`KeyPair`] which hold the [`SigningKey`]
//! data structure
use rst_common::with_cryptography::ed25519_dalek::{pkcs8::DecodePrivateKey, SigningKey};

use rst_common::with_cryptography::rand::{rngs::adapter::ReseedingRng, SeedableRng};
use rst_common::with_cryptography::rand_chacha::{rand_core::OsRng, ChaCha20Core};

use crate::eddsa::privkey::PrivKey;
use crate::eddsa::pubkey::PubKey;
use crate::eddsa::signature::Signature;
use crate::eddsa::types::errors::EddsaError;

/// `KeyPair` actually is main entrypoint used to generate the [`SigningKey`]
///
/// From this signing key we will also able to generate [`PubKey`] and also [`Signature`] objects.
/// Besides to generate all necessary objects, this object also able to import given `PEM` data format
/// into its self
#[derive(Clone, Debug)]
pub struct KeyPair {
    keypair: SigningKey,
}

impl KeyPair {
    pub fn generate() -> Self {
        let prng = ChaCha20Core::from_entropy();
        let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng);
        let sign_key = SigningKey::generate(&mut reseeding_rng);
        Self { keypair: sign_key }
    }

    pub fn pub_key(&self) -> PubKey {
        PubKey::new(self.keypair.verifying_key())
    }

    pub fn priv_key(&self) -> PrivKey {
        PrivKey::new(self.keypair.clone())
    }

    pub fn from_pem(pem: String) -> Result<Self, EddsaError> {
        SigningKey::from_pkcs8_pem(pem.as_str())
            .map(|val| Self { keypair: val })
            .map_err(|err| EddsaError::DecodePemError(err.to_string()))
    }

    pub fn signature(&self, message: &[u8]) -> Signature {
        Signature::new(self.keypair.clone(), message.to_vec())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rst_common::with_cryptography::hex;

    use crate::keysecure::types::ToKeySecure;

    #[test]
    fn test_gen_pub_key_multiple() {
        let keypair1 = KeyPair::generate();
        let keypair2 = KeyPair::generate();
        let keypair3 = KeyPair::generate();

        let pubkey1 = keypair1.pub_key();
        let pubkey2 = keypair2.pub_key();
        let pubkey3 = keypair3.pub_key();

        let pubkeyhex1 = pubkey1.to_hex();
        let pubkeyhex2 = pubkey2.to_hex();
        let pubkeyhex3 = pubkey3.to_hex();

        assert_ne!(pubkeyhex1, pubkeyhex2);
        assert_ne!(pubkeyhex1, pubkeyhex3);
        assert_ne!(pubkeyhex2, pubkeyhex3)
    }

    #[test]
    fn test_gen_pub_key() {
        let keypair = KeyPair::generate();
        let pubkey = keypair.pub_key();
        let pubkeybytes = pubkey.serialize();
        let pubkeyhex = pubkey.to_hex();
        let pubkeytoorig = hex::decode(pubkeyhex.clone());

        assert!(!pubkeytoorig.is_err());
        assert_eq!(pubkeybytes, pubkeytoorig.clone().unwrap().as_slice());
        assert_eq!(
            pubkeyhex,
            hex::encode(pubkeytoorig.clone().unwrap().as_slice())
        )
    }

    #[test]
    fn test_gen_pub_key_from_hex() {
        let keypair = KeyPair::generate();
        let pubkey = keypair.pub_key();
        let pubkeyhex = pubkey.to_hex();

        let pubkey_from_hex = PubKey::from_hex(pubkeyhex);
        assert!(!pubkey_from_hex.is_err());

        let pubkey2 = pubkey_from_hex.unwrap();
        assert_eq!(pubkey2.serialize(), pubkey.serialize());
        assert_eq!(pubkey2.to_hex(), pubkey.to_hex())
    }

    #[test]
    fn test_sign_to_hex() {
        let message = b"hello world";
        let keypair = KeyPair::generate();
        let pubkey = keypair.pub_key();
        let signature = keypair.signature(message);
        let signature_hex = signature.to_hex();

        let verify_hex_valid = pubkey.verify(message, signature_hex.clone());
        assert!(!verify_hex_valid.is_err());

        let verify_hex_invalid = pubkey.verify(b"invalid", signature_hex.clone());
        assert!(verify_hex_invalid.is_err());
        assert!(matches!(
            verify_hex_invalid,
            Err(EddsaError::InvalidSignatureError(_))
        ));
    }

    #[test]
    fn test_encode_priv_key_to_pem() {
        let keypair = KeyPair::generate();
        let priv_key_pem = keypair.priv_key().to_pem();
        assert!(!priv_key_pem.is_err());
        assert!(priv_key_pem.unwrap().contains("BEGIN PRIVATE KEY"))
    }

    #[test]
    fn test_priv_key_to_keysecure() {
        let keypair = KeyPair::generate();
        let priv_key = keypair.priv_key();
        let priv_key_pem = priv_key.to_pem();
        assert!(!priv_key_pem.is_err());

        let priv_key_secure = priv_key.to_keysecure("test".to_string());
        assert!(!priv_key_secure.is_err());

        let keysecure = priv_key_secure.unwrap();
        let keysecure_json = keysecure.to_json();
        assert!(!keysecure_json.is_err())
    }

    #[test]
    fn test_decode_pem() {
        let keypair = KeyPair::generate();
        let priv_key = keypair.priv_key();
        let priv_key_pem = priv_key.to_pem();
        let keypair2 = KeyPair::from_pem(priv_key_pem.unwrap());

        assert!(!keypair2.is_err());
        assert_eq!(
            priv_key.serialize(),
            keypair2.unwrap().clone().priv_key().serialize()
        );
    }
}