idprova_core/crypto/
keys.rs1use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
2use rand::rngs::OsRng;
3use serde::{Deserialize, Serialize};
4use zeroize::ZeroizeOnDrop;
5
6use crate::{IdprovaError, Result};
7
8#[derive(Debug, ZeroizeOnDrop)]
15pub struct KeyPair {
16 signing_key: SigningKey,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub struct PublicKey {
22 #[serde(rename = "type")]
24 pub key_type: String,
25 #[serde(rename = "publicKeyMultibase")]
27 pub public_key_multibase: String,
28}
29
30impl KeyPair {
31 pub fn generate() -> Self {
33 let signing_key = SigningKey::generate(&mut OsRng);
34 Self { signing_key }
35 }
36
37 pub fn from_secret_bytes(bytes: &[u8; 32]) -> Self {
39 let signing_key = SigningKey::from_bytes(bytes);
40 Self { signing_key }
41 }
42
43 #[doc(hidden)]
51 pub fn secret_bytes(&self) -> &[u8; 32] {
52 self.signing_key.as_bytes()
53 }
54
55 pub fn verifying_key(&self) -> VerifyingKey {
57 self.signing_key.verifying_key()
58 }
59
60 pub fn public_key_bytes(&self) -> [u8; 32] {
62 self.verifying_key().to_bytes()
63 }
64
65 pub fn public_key_multibase(&self) -> String {
67 let bytes = self.public_key_bytes();
68 multibase::encode(multibase::Base::Base58Btc, bytes)
69 }
70
71 pub fn public_key(&self) -> PublicKey {
73 PublicKey {
74 key_type: "Ed25519VerificationKey2020".to_string(),
75 public_key_multibase: self.public_key_multibase(),
76 }
77 }
78
79 pub fn sign(&self, message: &[u8]) -> Vec<u8> {
81 let signature = self.signing_key.sign(message);
82 signature.to_bytes().to_vec()
83 }
84
85 pub fn verify(
87 public_key_bytes: &[u8; 32],
88 message: &[u8],
89 signature_bytes: &[u8],
90 ) -> Result<()> {
91 let verifying_key = VerifyingKey::from_bytes(public_key_bytes)
92 .map_err(|e| IdprovaError::InvalidKey(e.to_string()))?;
93
94 let signature_array: [u8; 64] = signature_bytes
95 .try_into()
96 .map_err(|_| IdprovaError::VerificationFailed("invalid signature length".into()))?;
97
98 let signature = Signature::from_bytes(&signature_array);
99
100 verifying_key
101 .verify(message, &signature)
102 .map_err(|e| IdprovaError::VerificationFailed(e.to_string()))
103 }
104
105 pub fn decode_multibase_pubkey(multibase_str: &str) -> Result<[u8; 32]> {
107 let (_, bytes) = multibase::decode(multibase_str)
108 .map_err(|e| IdprovaError::InvalidKey(format!("multibase decode: {e}")))?;
109
110 bytes
111 .try_into()
112 .map_err(|_| IdprovaError::InvalidKey("expected 32-byte public key".into()))
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_generate_and_sign_verify() {
122 let kp = KeyPair::generate();
123 let message = b"hello idprova";
124 let signature = kp.sign(message);
125
126 let pub_bytes = kp.public_key_bytes();
127 assert!(KeyPair::verify(&pub_bytes, message, &signature).is_ok());
128 }
129
130 #[test]
131 fn test_invalid_signature_fails() {
132 let kp = KeyPair::generate();
133 let message = b"hello idprova";
134 let mut signature = kp.sign(message);
135 signature[0] ^= 0xFF; let pub_bytes = kp.public_key_bytes();
138 assert!(KeyPair::verify(&pub_bytes, message, &signature).is_err());
139 }
140
141 #[test]
142 fn test_wrong_key_fails() {
143 let kp1 = KeyPair::generate();
144 let kp2 = KeyPair::generate();
145 let message = b"hello idprova";
146 let signature = kp1.sign(message);
147
148 let wrong_pub = kp2.public_key_bytes();
149 assert!(KeyPair::verify(&wrong_pub, message, &signature).is_err());
150 }
151
152 #[test]
153 fn test_multibase_roundtrip() {
154 let kp = KeyPair::generate();
155 let multibase = kp.public_key_multibase();
156 let decoded = KeyPair::decode_multibase_pubkey(&multibase).unwrap();
157 assert_eq!(decoded, kp.public_key_bytes());
158 }
159
160 #[test]
161 fn test_deterministic_from_bytes() {
162 let kp1 = KeyPair::generate();
163 let secret = *kp1.secret_bytes();
164 let kp2 = KeyPair::from_secret_bytes(&secret);
165 assert_eq!(kp1.public_key_bytes(), kp2.public_key_bytes());
166 }
167}