cml_crypto/chain_crypto/algorithms/
ed25519.rs

1use crate::chain_crypto::key::{
2    AsymmetricKey, AsymmetricPublicKey, PublicKeyError, SecretKeyError, SecretKeySizeStatic,
3};
4use crate::chain_crypto::sign::{
5    SignatureError, SigningAlgorithm, Verification, VerificationAlgorithm,
6};
7use cryptoxide::ed25519;
8use rand::{CryptoRng, RngCore};
9
10use ed25519_bip32::XPub;
11
12/// ED25519 Signing Algorithm
13pub struct Ed25519;
14
15#[derive(Clone)]
16pub struct Priv([u8; ed25519::PRIVATE_KEY_LENGTH]);
17
18#[derive(Clone, PartialEq, Eq, Hash)]
19pub struct Pub(pub(crate) [u8; ed25519::PUBLIC_KEY_LENGTH]);
20
21#[derive(Clone)]
22pub struct Sig(pub(crate) [u8; ed25519::SIGNATURE_LENGTH]);
23
24impl Pub {
25    pub fn from_xpub(xpub: &XPub) -> Self {
26        let mut buf = [0; ed25519::PUBLIC_KEY_LENGTH];
27        xpub.get_without_chaincode(&mut buf);
28        Pub(buf)
29    }
30}
31
32impl AsRef<[u8]> for Priv {
33    fn as_ref(&self) -> &[u8] {
34        &self.0[..]
35    }
36}
37
38impl AsRef<[u8]> for Pub {
39    fn as_ref(&self) -> &[u8] {
40        &self.0
41    }
42}
43
44impl AsRef<[u8]> for Sig {
45    fn as_ref(&self) -> &[u8] {
46        &self.0
47    }
48}
49
50impl AsymmetricPublicKey for Ed25519 {
51    type Public = Pub;
52
53    const PUBLIC_BECH32_HRP: &'static str = "ed25519_pk";
54    const PUBLIC_KEY_SIZE: usize = ed25519::PUBLIC_KEY_LENGTH;
55
56    fn public_from_binary(data: &[u8]) -> Result<Self::Public, PublicKeyError> {
57        if data.len() != ed25519::PUBLIC_KEY_LENGTH {
58            return Err(PublicKeyError::SizeInvalid);
59        }
60        let mut buf = [0; ed25519::PUBLIC_KEY_LENGTH];
61        buf[0..ed25519::PUBLIC_KEY_LENGTH].clone_from_slice(data);
62        Ok(Pub(buf))
63    }
64}
65
66impl AsymmetricKey for Ed25519 {
67    type Secret = Priv;
68    type PubAlg = Ed25519;
69
70    const SECRET_BECH32_HRP: &'static str = "ed25519_sk";
71
72    fn generate<T: RngCore + CryptoRng>(mut rng: T) -> Self::Secret {
73        let mut priv_bytes = [0u8; ed25519::PRIVATE_KEY_LENGTH];
74        rng.fill_bytes(&mut priv_bytes);
75        Priv(priv_bytes)
76    }
77
78    fn compute_public(key: &Self::Secret) -> <Self::PubAlg as AsymmetricPublicKey>::Public {
79        let (_, pk) = ed25519::keypair(&key.0);
80        Pub(pk)
81    }
82
83    fn secret_from_binary(data: &[u8]) -> Result<Self::Secret, SecretKeyError> {
84        if data.len() != ed25519::PRIVATE_KEY_LENGTH {
85            return Err(SecretKeyError::SizeInvalid);
86        }
87        let mut buf = [0; ed25519::PRIVATE_KEY_LENGTH];
88        buf[0..ed25519::PRIVATE_KEY_LENGTH].clone_from_slice(data);
89        Ok(Priv(buf))
90    }
91}
92
93impl SecretKeySizeStatic for Ed25519 {
94    const SECRET_KEY_SIZE: usize = ed25519::PRIVATE_KEY_LENGTH;
95}
96
97impl VerificationAlgorithm for Ed25519 {
98    type Signature = Sig;
99
100    const SIGNATURE_SIZE: usize = ed25519::SIGNATURE_LENGTH;
101    const SIGNATURE_BECH32_HRP: &'static str = "ed25519_sig";
102
103    fn signature_from_bytes(data: &[u8]) -> Result<Self::Signature, SignatureError> {
104        if data.len() != ed25519::SIGNATURE_LENGTH {
105            return Err(SignatureError::SizeInvalid {
106                expected: ed25519::SIGNATURE_LENGTH,
107                got: data.len(),
108            });
109        }
110        let mut buf = [0; ed25519::SIGNATURE_LENGTH];
111        buf[0..ed25519::SIGNATURE_LENGTH].clone_from_slice(data);
112        Ok(Sig(buf))
113    }
114
115    fn verify_bytes(
116        pubkey: &Self::Public,
117        signature: &Self::Signature,
118        msg: &[u8],
119    ) -> Verification {
120        ed25519::verify(msg, &pubkey.0, &signature.0).into()
121    }
122}
123
124impl SigningAlgorithm for Ed25519 {
125    fn sign(key: &Self::Secret, msg: &[u8]) -> Sig {
126        let (sk, _) = ed25519::keypair(&key.0);
127        Sig(ed25519::signature(msg, &sk))
128    }
129}
130
131#[cfg(test)]
132mod test {
133    use super::*;
134
135    use crate::chain_crypto::key::KeyPair;
136    use crate::chain_crypto::sign::test::{keypair_signing_ko, keypair_signing_ok};
137    use quickcheck_macros::quickcheck;
138
139    #[quickcheck]
140    fn sign_ok(input: (KeyPair<Ed25519>, Vec<u8>)) -> bool {
141        keypair_signing_ok(input)
142    }
143
144    #[quickcheck]
145    fn sign_ko(input: (KeyPair<Ed25519>, KeyPair<Ed25519>, Vec<u8>)) -> bool {
146        keypair_signing_ko(input)
147    }
148}