1use crate::error::{Error, Result};
4use ed25519_dalek::{SigningKey, VerifyingKey};
5use rand::rngs::OsRng;
6use sha2::{Digest, Sha512};
7
8pub const MULTICODEC_ED25519_PUB: [u8; 2] = [0xED, 0x01];
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct KeyPair {
12 pub public_key: [u8; 32],
13 pub private_key: [u8; 32],
14}
15
16pub fn generate_key_pair() -> KeyPair {
17 let signing = SigningKey::generate(&mut OsRng);
18 let verifying: VerifyingKey = signing.verifying_key();
19 KeyPair {
20 public_key: verifying.to_bytes(),
21 private_key: signing.to_bytes(),
22 }
23}
24
25pub fn encode_did_key(public_key: &[u8]) -> Result<String> {
26 if public_key.len() != 32 {
27 return Err(Error::InvalidDid(format!(
28 "Ed25519 pubkey must be 32 bytes, got {}",
29 public_key.len()
30 )));
31 }
32 let mut prefixed = Vec::with_capacity(34);
33 prefixed.extend_from_slice(&MULTICODEC_ED25519_PUB);
34 prefixed.extend_from_slice(public_key);
35 let encoded = bs58::encode(&prefixed).into_string();
36 Ok(format!("did:key:z{}", encoded))
37}
38
39pub fn decode_did_key(did: &str) -> Result<[u8; 32]> {
40 let prefix = "did:key:z";
41 if !did.starts_with(prefix) {
42 return Err(Error::InvalidDid("not a did:key identifier".into()));
43 }
44 let decoded = bs58::decode(&did[prefix.len()..])
45 .into_vec()
46 .map_err(|e| Error::InvalidDid(format!("base58 decode failed: {e}")))?;
47 if decoded.len() < 34
48 || decoded[0] != MULTICODEC_ED25519_PUB[0]
49 || decoded[1] != MULTICODEC_ED25519_PUB[1]
50 {
51 return Err(Error::InvalidDid(
52 "did:key is not an Ed25519 key (wrong multicodec prefix or truncated)".into(),
53 ));
54 }
55 let mut out = [0u8; 32];
56 out.copy_from_slice(&decoded[2..34]);
57 Ok(out)
58}
59
60pub fn ed25519_pub_to_x25519(ed_pub: &[u8; 32]) -> [u8; 32] {
63 let verifying = VerifyingKey::from_bytes(ed_pub).expect("valid Edwards point");
64 let edwards = verifying.to_edwards();
65 let montgomery = edwards.to_montgomery();
66 montgomery.to_bytes()
67}
68
69pub fn ed25519_priv_to_x25519(ed_priv: &[u8; 32]) -> [u8; 32] {
73 let mut h = Sha512::new();
74 h.update(ed_priv);
75 let digest = h.finalize();
76 let mut out = [0u8; 32];
77 out.copy_from_slice(&digest[..32]);
78 out[0] &= 248;
80 out[31] &= 127;
81 out[31] |= 64;
82 out
83}