1use rand::{CryptoRng, Rng};
6
7use crate::ecdh;
8use crate::ecdh::p256;
9use crate::ecdh::p256_derive;
10use crate::ecdh::x25519;
11
12#[derive(Clone, Copy, PartialEq, Debug)]
16pub enum Algorithm {
17 X25519,
18 X448,
19 Secp256r1,
20 Secp384r1,
21 Secp521r1,
22 Kyber512,
23 Kyber768,
24 Kyber768X25519,
25 Kyber1024,
26}
27
28#[derive(Debug, PartialEq, Eq)]
29pub enum Error {
30 EcDhError(ecdh::Error),
31 KeyGen,
32 Encapsulate,
33 Decapsulate,
34 UnsupportedAlgorithm,
35 InvalidPrivateKey,
36 InvalidPublicKey,
37 InvalidCiphertext,
38}
39
40impl TryFrom<Algorithm> for ecdh::Algorithm {
41 type Error = &'static str;
42
43 fn try_from(value: Algorithm) -> Result<Self, Self::Error> {
44 match value {
45 Algorithm::X25519 => Ok(ecdh::Algorithm::X25519),
46 Algorithm::X448 => Ok(ecdh::Algorithm::X448),
47 Algorithm::Secp256r1 => Ok(ecdh::Algorithm::P256),
48 Algorithm::Secp384r1 => Ok(ecdh::Algorithm::P384),
49 Algorithm::Secp521r1 => Ok(ecdh::Algorithm::P521),
50 Algorithm::Kyber768X25519 => Ok(ecdh::Algorithm::X25519),
51 _ => Err("provided algorithm is not an ECDH algorithm"),
52 }
53 }
54}
55
56impl From<ecdh::Error> for Error {
57 fn from(value: ecdh::Error) -> Self {
58 Error::EcDhError(value)
59 }
60}
61
62pub enum PrivateKey {
64 X25519(x25519::PrivateKey),
65 P256(p256::PrivateKey),
66}
67
68pub enum PublicKey {
70 X25519(x25519::PublicKey),
71 P256(p256::PublicKey),
72}
73
74pub enum Ct {
76 X25519(x25519::PublicKey),
77 P256(p256::PublicKey),
78}
79
80pub enum Ss {
82 X25519(x25519::PublicKey),
83 P256(p256::PublicKey),
84}
85
86impl PrivateKey {
87 pub fn encode(&self) -> Vec<u8> {
89 match self {
90 PrivateKey::X25519(k) => k.0.to_vec(),
91 PrivateKey::P256(k) => k.0.to_vec(),
92 }
93 }
94
95 pub fn decode(alg: Algorithm, bytes: &[u8]) -> Result<Self, Error> {
97 match alg {
98 Algorithm::X25519 => bytes
99 .try_into()
100 .map_err(|_| Error::InvalidPrivateKey)
101 .map(|k| Self::X25519(k)),
102 Algorithm::Secp256r1 => bytes
103 .try_into()
104 .map_err(|_| Error::InvalidPrivateKey)
105 .map(|k| Self::P256(k)),
106 _ => Err(Error::UnsupportedAlgorithm),
107 }
108 }
109}
110
111impl PublicKey {
112 pub fn encode(&self) -> Vec<u8> {
114 match self {
115 PublicKey::X25519(k) => k.0.to_vec(),
116 PublicKey::P256(k) => k.0.to_vec(),
117 }
118 }
119
120 pub fn decode(alg: Algorithm, bytes: &[u8]) -> Result<Self, Error> {
122 match alg {
123 Algorithm::X25519 => bytes
124 .try_into()
125 .map_err(|_| Error::InvalidPublicKey)
126 .map(|k| Self::X25519(k)),
127 Algorithm::Secp256r1 => bytes
128 .try_into()
129 .map_err(|_| Error::InvalidPublicKey)
130 .map(|k| Self::P256(k)),
131 _ => Err(Error::UnsupportedAlgorithm),
132 }
133 }
134}
135
136impl Ss {
137 pub fn encode(&self) -> Vec<u8> {
139 match self {
140 Ss::X25519(k) => k.0.to_vec(),
141 Ss::P256(k) => k.0.to_vec(),
142 }
143 }
144}
145
146impl Ct {
147 pub fn encode(&self) -> Vec<u8> {
149 match self {
150 Ct::X25519(k) => k.0.to_vec(),
151 Ct::P256(k) => k.0.to_vec(),
152 }
153 }
154
155 pub fn decode(alg: Algorithm, bytes: &[u8]) -> Result<Self, Error> {
157 match alg {
158 Algorithm::X25519 => bytes
159 .try_into()
160 .map_err(|_| Error::InvalidCiphertext)
161 .map(|ct| Self::X25519(ct)),
162 Algorithm::Secp256r1 => bytes
163 .try_into()
164 .map_err(|_| Error::InvalidCiphertext)
165 .map(|ct| Self::P256(ct)),
166 _ => Err(Error::UnsupportedAlgorithm),
167 }
168 }
169}
170
171pub fn secret_to_public(alg: Algorithm, sk: impl AsRef<[u8]>) -> Result<Vec<u8>, Error> {
174 match alg {
175 Algorithm::X25519 | Algorithm::Secp256r1 => {
176 ecdh::secret_to_public(alg.try_into().unwrap(), sk.as_ref()).map_err(|e| e.into())
177 }
178 _ => Err(Error::UnsupportedAlgorithm),
179 }
180}
181
182pub fn key_gen(
188 alg: Algorithm,
189 rng: &mut (impl CryptoRng + Rng),
190) -> Result<(PrivateKey, PublicKey), Error> {
191 match alg {
192 Algorithm::X25519 => ecdh::x25519_key_gen(rng)
193 .map_err(|e| e.into())
194 .map(|(private, public)| (PrivateKey::X25519(private), PublicKey::X25519(public))),
195 Algorithm::Secp256r1 => ecdh::p256_key_gen(rng)
196 .map_err(|e| e.into())
197 .map(|(private, public)| (PrivateKey::P256(private), PublicKey::P256(public))),
198 _ => Err(Error::UnsupportedAlgorithm),
199 }
200}
201
202pub fn encapsulate(pk: &PublicKey, rng: &mut (impl CryptoRng + Rng)) -> Result<(Ss, Ct), Error> {
204 match pk {
205 PublicKey::X25519(pk) => {
206 let (new_sk, new_pk) = ecdh::x25519_key_gen(rng)?;
207 let gxy = x25519::derive(pk, &new_sk)?;
208 Ok((Ss::X25519(gxy), Ct::X25519(new_pk)))
209 }
210 PublicKey::P256(pk) => {
211 let (new_sk, new_pk) = ecdh::p256_key_gen(rng)?;
212 let gxy = p256_derive(pk, &new_sk)?;
213 Ok((Ss::P256(gxy), Ct::P256(new_pk)))
214 }
215 }
216}
217
218pub fn decapsulate(ct: &Ct, sk: &PrivateKey) -> Result<Ss, Error> {
220 match ct {
221 Ct::X25519(ct) => {
222 let sk = if let PrivateKey::X25519(k) = sk {
223 k
224 } else {
225 return Err(Error::InvalidPrivateKey);
226 };
227 x25519::derive(ct, sk)
228 .map_err(|e| e.into())
229 .map(|k| Ss::X25519(k))
230 }
231 Ct::P256(ct) => {
232 let sk = if let PrivateKey::P256(k) = sk {
233 k
234 } else {
235 return Err(Error::InvalidPrivateKey);
236 };
237 p256_derive(ct, sk)
238 .map_err(|e| e.into())
239 .map(|k| Ss::P256(k))
240 }
241 }
242}