1#[cfg(feature = "ed25519")]
13use core::convert::TryFrom;
14use core::convert::TryInto;
15
16use zeroize::{Zeroize, ZeroizeOnDrop};
17
18#[cfg(feature = "ed25519")]
19use crate::signatures::ed25519;
20
21pub const PUBLIC_KEY_LENGTH: usize = 32;
22pub const SECRET_KEY_LENGTH: usize = 32;
23
24pub type SharedSecret = x25519_dalek::SharedSecret;
28
29#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
31pub struct PublicKey(x25519_dalek::PublicKey);
32
33impl PublicKey {
34 pub fn from_bytes(bytes: [u8; PUBLIC_KEY_LENGTH]) -> Self {
35 Self(bytes.into())
36 }
37
38 pub fn try_from_slice(slice: &[u8]) -> crate::Result<Self> {
40 let bytes: [u8; PUBLIC_KEY_LENGTH] = slice.try_into().map_err(|_| crate::Error::ConvertError {
41 from: "bytes",
42 to: "X25519 Public Key",
43 })?;
44
45 Ok(Self::from_bytes(bytes))
46 }
47
48 pub fn to_bytes(self) -> [u8; PUBLIC_KEY_LENGTH] {
50 self.0.to_bytes()
51 }
52
53 pub fn as_slice(&self) -> &[u8] {
55 self.0.as_bytes()
56 }
57}
58
59#[cfg(feature = "ed25519")]
60impl TryFrom<&ed25519::PublicKey> for PublicKey {
61 type Error = crate::Error;
62 fn try_from(pk: &ed25519::PublicKey) -> crate::Result<Self> {
63 let mut y_bytes = [0_u8; 32];
66 y_bytes.copy_from_slice(pk.as_slice());
67 match curve25519_dalek::edwards::CompressedEdwardsY(y_bytes).decompress() {
69 Some(decompressed_edwards) => {
70 Ok(PublicKey::from_bytes(decompressed_edwards.to_montgomery().to_bytes()))
76 }
77 None => Err(crate::error::Error::ConvertError {
78 from: "ed25519 public key",
79 to: "x25519 public key",
80 }),
81 }
82 }
83}
84
85impl AsRef<[u8]> for PublicKey {
86 fn as_ref(&self) -> &[u8] {
87 self.0.as_bytes()
88 }
89}
90
91impl From<[u8; PUBLIC_KEY_LENGTH]> for PublicKey {
92 fn from(bytes: [u8; PUBLIC_KEY_LENGTH]) -> Self {
93 Self::from_bytes(bytes)
94 }
95}
96
97impl From<PublicKey> for [u8; PUBLIC_KEY_LENGTH] {
98 fn from(pk: PublicKey) -> Self {
99 pk.to_bytes()
100 }
101}
102
103#[derive(Zeroize, ZeroizeOnDrop)]
105pub struct SecretKey(x25519_dalek::StaticSecret);
106
107impl SecretKey {
108 #[cfg(feature = "random")]
110 #[cfg_attr(docsrs, doc(cfg(feature = "random")))]
111 pub fn generate() -> crate::Result<Self> {
112 let mut bytes: [u8; SECRET_KEY_LENGTH] = [0; SECRET_KEY_LENGTH];
113 crate::utils::rand::fill(&mut bytes[..])?;
114 Ok(Self::from_bytes(bytes))
115 }
116
117 #[cfg(feature = "rand")]
118 pub fn generate_with<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> Self {
119 let mut bs = [0_u8; SECRET_KEY_LENGTH];
120 rng.fill_bytes(&mut bs);
121 Self::from_bytes(bs)
122 }
123
124 pub fn from_bytes(bytes: [u8; SECRET_KEY_LENGTH]) -> Self {
125 Self(bytes.into())
126 }
127
128 pub fn try_from_slice(slice: &[u8]) -> crate::Result<Self> {
130 let bytes: [u8; SECRET_KEY_LENGTH] = slice.try_into().map_err(|_| crate::Error::ConvertError {
131 from: "bytes",
132 to: "X25519 Secret Key",
133 })?;
134
135 Ok(Self::from_bytes(bytes))
136 }
137
138 pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
140 self.0.to_bytes()
141 }
142
143 pub fn public_key(&self) -> PublicKey {
145 PublicKey((&self.0).into())
146 }
147
148 pub fn diffie_hellman(&self, public: &PublicKey) -> SharedSecret {
150 self.0.diffie_hellman(&public.0)
151 }
152}
153
154#[cfg(all(feature = "ed25519", feature = "sha"))]
155impl From<&ed25519::SecretKey> for SecretKey {
156 fn from(sk: &ed25519::SecretKey) -> SecretKey {
157 use crate::hashes::Digest;
163 let h = crate::hashes::sha::Sha512::digest(sk.as_slice());
164 let mut scalar_bytes = [0u8; 32];
166 scalar_bytes[..].copy_from_slice(&h.as_slice()[0..32]);
167 SecretKey::from_bytes(scalar_bytes)
169 }
170}