did_utils/crypto/
ed25519.rs1use curve25519_dalek::edwards::CompressedEdwardsY;
2use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
3use multibase::Base::Base58Btc;
4use sha2::{Digest, Sha512};
5
6use super::{
7 alg::Algorithm,
8 errors::Error,
9 traits::{CoreSign, Generate, KeyMaterial, ToMultikey, BYTES_LENGTH_32},
10 utils::{clone_slice_to_array, generate_seed},
11 x25519::X25519KeyPair,
12 AsymmetricKey,
13};
14
15pub type Ed25519KeyPair = AsymmetricKey<VerifyingKey, SigningKey>;
16
17impl std::fmt::Debug for Ed25519KeyPair {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.write_fmt(format_args!("{:?}", self.public_key))
23 }
24}
25
26impl KeyMaterial for Ed25519KeyPair {
27 fn public_key_bytes(&self) -> Result<[u8; BYTES_LENGTH_32], Error> {
33 Ok(clone_slice_to_array(self.public_key.as_bytes()))
34 }
35
36 fn private_key_bytes(&self) -> Result<[u8; BYTES_LENGTH_32], Error> {
42 match &self.secret_key {
43 Some(sk) => Ok(clone_slice_to_array(&sk.to_bytes())),
44 None => Err(Error::InvalidSecretKey),
45 }
46 }
47}
48
49impl Generate for Ed25519KeyPair {
50 fn new() -> Result<Ed25519KeyPair, Error> {
58 Self::new_with_seed(vec![].as_slice())
59 }
60
61 fn new_with_seed(seed: &[u8]) -> Result<Ed25519KeyPair, Error> {
73 match generate_seed(seed) {
74 Ok(secret_seed) => {
75 let sk: SigningKey = SigningKey::from_bytes(&secret_seed);
76 Ok(Ed25519KeyPair {
77 public_key: sk.verifying_key(),
78 secret_key: Some(sk),
79 })
80 }
81 Err(_) => Err(Error::InvalidSeed),
82 }
83 }
84
85 fn from_public_key(public_key: &[u8; BYTES_LENGTH_32]) -> Result<Ed25519KeyPair, Error> {
95 match public_key.len() {
96 BYTES_LENGTH_32 => Ok(Ed25519KeyPair {
97 public_key: match VerifyingKey::from_bytes(&clone_slice_to_array(public_key)) {
98 Ok(vk) => vk,
99 Err(_) => return Err(Error::InvalidPublicKey),
100 },
101 secret_key: None,
102 }),
103 _ => Err(Error::InvalidKeyLength),
104 }
105 }
106
107 fn from_secret_key(secret_key: &[u8; BYTES_LENGTH_32]) -> Result<Ed25519KeyPair, Error> {
119 match secret_key.len() {
120 BYTES_LENGTH_32 => {
121 let sk: SigningKey = SigningKey::from_bytes(&clone_slice_to_array(secret_key));
122 Ok(Ed25519KeyPair {
123 public_key: sk.verifying_key(),
124 secret_key: Some(sk),
125 })
126 }
127 _ => Err(Error::InvalidKeyLength),
128 }
129 }
130}
131
132impl CoreSign for Ed25519KeyPair {
133 fn sign(&self, payload: &[u8]) -> Result<Vec<u8>, Error> {
143 match &self.secret_key {
145 Some(sk) => {
146 match sk.try_sign(payload) {
148 Ok(signature) => {
149 Ok(signature.to_bytes().to_vec())
151 }
152 Err(_) => Err(Error::SignatureError),
153 }
154 }
155 None => Err(Error::InvalidSecretKey),
156 }
157 }
158
159 fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<(), Error> {
170 match Signature::try_from(signature) {
173 Ok(sig) => match self.public_key.verify(payload, &sig) {
174 Ok(_) => Ok(()),
175 _ => Err(Error::VerificationError),
176 },
177 Err(_) => Err(Error::CanNotRetrieveSignature),
178 }
179 }
180}
181
182impl ToMultikey for Ed25519KeyPair {
183 fn to_multikey(&self) -> String {
184 let prefix = &Algorithm::Ed25519.muticodec_prefix();
185 let bytes = &self.public_key.as_bytes()[..];
186 multibase::encode(Base58Btc, [prefix, bytes].concat())
187 }
188}
189
190impl Ed25519KeyPair {
191 pub fn get_x25519(&self) -> Result<X25519KeyPair, Error> {
197 match &self.secret_key {
199 Some(sk) => {
200 let bytes: [u8; BYTES_LENGTH_32] = sk.to_bytes();
201 let mut hasher = Sha512::new();
203 hasher.update(bytes);
204 let hash = hasher.finalize();
205 let mut output = [0u8; BYTES_LENGTH_32];
207 output.copy_from_slice(&hash[..BYTES_LENGTH_32]);
208 output[0] &= 248;
210 output[31] &= 127;
211 output[31] |= 64;
212
213 X25519KeyPair::new_with_seed(&output)
215 }
216 None => {
217 match self.public_key_bytes() {
219 Ok(pk_bytes) => {
220 match CompressedEdwardsY(pk_bytes).decompress() {
222 Some(point) => {
223 let montgomery = point.to_montgomery();
225 X25519KeyPair::from_public_key(montgomery.as_bytes())
226 }
227 None => Err(Error::InvalidPublicKey),
228 }
229 }
230 Err(_) => Err(Error::InvalidPublicKey),
231 }
232 }
233 }
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::crypto::traits::{CoreSign, Generate, KeyMaterial, BYTES_LENGTH_32};
241 use crate::jwk::Jwk;
242
243 #[test]
246 fn test_new() {
247 let keypair = Ed25519KeyPair::new().unwrap();
248 assert_eq!(keypair.public_key_bytes().unwrap().len(), BYTES_LENGTH_32);
249 assert_eq!(keypair.private_key_bytes().unwrap().len(), BYTES_LENGTH_32);
250 }
251
252 #[test]
255 fn test_new_with_seed() {
256 let my_string = String::from("Sample seed bytes of thirtytwo!b");
259 let seed: &[u8] = my_string.as_bytes();
260 let keypair = Ed25519KeyPair::new_with_seed(seed).unwrap();
261 let pub_key_hex = hex::encode(keypair.public_key_bytes().unwrap());
262 let pri_key_hex = hex::encode(keypair.private_key_bytes().unwrap());
263 assert_eq!(pub_key_hex, "412328b0201b71d0144a27d028057b6fdf58d22e0f3baaebaa5388140e57bbbd");
264 assert_eq!(pri_key_hex, "53616d706c652073656564206279746573206f662074686972747974776f2162");
265 }
266
267 #[test]
273 fn test_sign_verify() {
274 let keypair = Ed25519KeyPair::new().unwrap();
275
276 let json_file = "test_resources/crypto_ed25519_test_sign_verify.json";
277 let json_data = std::fs::read_to_string(json_file).unwrap();
278
279 let signature = keypair.sign(json_data.as_bytes());
280
281 let verified = keypair.verify(json_data.as_bytes(), &signature.unwrap());
283 assert!(verified.is_ok());
284 }
285
286 #[test]
287 fn test_ed25519_keypair_to_multikey() {
288 let jwk: Jwk = serde_json::from_str(
289 r#"{
290 "kty": "OKP",
291 "crv": "Ed25519",
292 "x": "O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik"
293 }"#,
294 )
295 .unwrap();
296
297 let keypair: Ed25519KeyPair = jwk.try_into().unwrap();
298 let multikey = keypair.to_multikey();
299
300 assert_eq!(&multikey, "z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp");
301 }
302}