keri_core/keys/
mod.rs

1use ed25519_dalek::{ExpandedSecretKey, SecretKey};
2use k256::ecdsa::{signature::Signer as EcdsaSigner, Signature as EcdsaSignature, SigningKey};
3use k256::ecdsa::{signature::Verifier as EcdsaVerifier, VerifyingKey};
4use serde_derive::{Deserialize, Serialize};
5use zeroize::Zeroize;
6
7#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
8pub enum KeysError {
9    #[error("ED25519Dalek signature error")]
10    Ed25519DalekSignatureError,
11}
12
13impl From<ed25519_dalek::SignatureError> for KeysError {
14    fn from(_: ed25519_dalek::SignatureError) -> Self {
15        KeysError::Ed25519DalekSignatureError
16    }
17}
18
19#[derive(
20    Debug, Clone, PartialEq, Hash, Eq, Default, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize,
21)]
22#[rkyv(compare(PartialEq), derive(Debug))]
23pub struct PublicKey {
24    pub public_key: Vec<u8>,
25}
26
27impl PublicKey {
28    pub fn new(key: Vec<u8>) -> Self {
29        PublicKey {
30            public_key: key.to_vec(),
31        }
32    }
33
34    pub fn key(&self) -> Vec<u8> {
35        self.public_key.clone()
36    }
37
38    pub fn verify_ed(&self, msg: &[u8], sig: &[u8]) -> bool {
39        if let Ok(key) = ed25519_dalek::PublicKey::from_bytes(&self.key()) {
40            use arrayref::array_ref;
41            if sig.len() != 64 {
42                return false;
43            }
44            let sig = ed25519_dalek::Signature::from(array_ref!(sig, 0, 64).to_owned());
45            match key.verify(msg, &sig) {
46                Ok(()) => true,
47                Err(_) => false,
48            }
49        } else {
50            false
51        }
52    }
53
54    pub fn verify_ecdsa(&self, msg: &[u8], sig: &[u8]) -> bool {
55        match VerifyingKey::from_sec1_bytes(&self.key()) {
56            Ok(k) => {
57                use k256::ecdsa::Signature;
58                if let Ok(sig) = Signature::try_from(sig) {
59                    match k.verify(msg, &sig) {
60                        Ok(()) => true,
61                        Err(_) => false,
62                    }
63                } else {
64                    false
65                }
66            }
67            Err(_) => false,
68        }
69    }
70}
71
72#[derive(Debug, PartialEq, Clone)]
73pub struct PrivateKey {
74    key: Vec<u8>,
75}
76
77impl PrivateKey {
78    pub fn new(key: Vec<u8>) -> Self {
79        Self { key }
80    }
81
82    pub fn sign_ecdsa(&self, msg: &[u8]) -> Result<Vec<u8>, KeysError> {
83        let sig: EcdsaSignature = EcdsaSigner::sign(&SigningKey::from_bytes(&self.key)?, msg);
84        Ok(sig.as_ref().to_vec())
85    }
86
87    pub fn sign_ed(&self, msg: &[u8]) -> Result<Vec<u8>, KeysError> {
88        let sk = SecretKey::from_bytes(&self.key).map_err(KeysError::from)?;
89        let pk = ed25519_dalek::PublicKey::from(&sk);
90        Ok(ExpandedSecretKey::from(&sk)
91            .sign(msg, &pk)
92            .as_ref()
93            .to_vec())
94    }
95
96    pub fn key(&self) -> Vec<u8> {
97        self.key.clone()
98    }
99}
100
101impl Drop for PrivateKey {
102    fn drop(&mut self) {
103        self.key.zeroize()
104    }
105}
106
107#[test]
108fn libsodium_to_ed25519_dalek_compat() {
109    use ed25519_dalek::Signature;
110    use rand::rngs::OsRng;
111
112    let kp = ed25519_dalek::Keypair::generate(&mut OsRng);
113
114    let msg = b"are libsodium and dalek compatible?";
115
116    let dalek_sig = kp.sign(msg);
117
118    use sodiumoxide::crypto::sign;
119
120    let sodium_pk = sign::ed25519::PublicKey::from_slice(&kp.public.to_bytes());
121    assert!(sodium_pk.is_some());
122    let sodium_pk = sodium_pk.unwrap();
123    let mut sodium_sk_concat = kp.secret.to_bytes().to_vec();
124    sodium_sk_concat.append(&mut kp.public.to_bytes().to_vec().clone());
125    let sodium_sk = sign::ed25519::SecretKey::from_slice(&sodium_sk_concat);
126    assert!(sodium_sk.is_some());
127    let sodium_sk = sodium_sk.unwrap();
128
129    let sodium_sig = sign::sign(msg, &sodium_sk);
130
131    assert!(sign::verify_detached(
132        &sign::ed25519::Signature::from_bytes(&dalek_sig.to_bytes()).unwrap(),
133        msg,
134        &sodium_pk
135    ));
136
137    assert!(kp
138        .verify(
139            msg,
140            &Signature::from_bytes(&arrayref::array_ref!(sodium_sig, 0, 64).to_owned()).unwrap()
141        )
142        .is_ok());
143}