astrid_crypto/
signature.rs1use ed25519_dalek::{Signature as DalekSignature, Verifier, VerifyingKey};
9use serde::{Deserialize, Serialize};
10use std::fmt;
11
12use crate::error::{CryptoError, CryptoResult};
13
14#[derive(Clone, Copy, PartialEq, Eq)]
16pub struct Signature([u8; 64]);
17
18impl Signature {
19 #[must_use]
21 pub const fn from_bytes(bytes: [u8; 64]) -> Self {
22 Self(bytes)
23 }
24
25 pub fn try_from_slice(slice: &[u8]) -> CryptoResult<Self> {
31 if slice.len() != 64 {
32 return Err(CryptoError::InvalidSignatureLength {
33 expected: 64,
34 actual: slice.len(),
35 });
36 }
37 let mut bytes = [0u8; 64];
38 bytes.copy_from_slice(slice);
39 Ok(Self(bytes))
40 }
41
42 #[must_use]
44 pub const fn as_bytes(&self) -> &[u8; 64] {
45 &self.0
46 }
47
48 #[must_use]
50 pub fn to_hex(&self) -> String {
51 hex::encode(self.0)
52 }
53
54 pub fn from_hex(s: &str) -> CryptoResult<Self> {
60 let bytes = hex::decode(s).map_err(|_| CryptoError::InvalidHexEncoding)?;
61 Self::try_from_slice(&bytes)
62 }
63
64 #[must_use]
66 pub fn to_base64(&self) -> String {
67 use base64::Engine;
68 base64::engine::general_purpose::STANDARD.encode(self.0)
69 }
70
71 pub fn from_base64(s: &str) -> CryptoResult<Self> {
77 use base64::Engine;
78 let bytes = base64::engine::general_purpose::STANDARD
79 .decode(s)
80 .map_err(|_| CryptoError::InvalidBase64Encoding)?;
81 Self::try_from_slice(&bytes)
82 }
83
84 pub fn verify(&self, message: &[u8], public_key: &[u8; 32]) -> CryptoResult<()> {
90 let verifying_key = VerifyingKey::from_bytes(public_key)
91 .map_err(|e| CryptoError::InvalidPublicKey(e.to_string()))?;
92
93 let sig = DalekSignature::from_bytes(&self.0);
94
95 verifying_key
96 .verify(message, &sig)
97 .map_err(|_| CryptoError::SignatureVerificationFailed)
98 }
99
100 #[must_use]
102 pub fn to_dalek(&self) -> DalekSignature {
103 DalekSignature::from_bytes(&self.0)
104 }
105}
106
107impl fmt::Debug for Signature {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "Signature({}...)", &self.to_hex()[..16])
110 }
111}
112
113impl fmt::Display for Signature {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(f, "{}", self.to_hex())
116 }
117}
118
119impl Serialize for Signature {
120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121 where
122 S: serde::Serializer,
123 {
124 serializer.serialize_str(&self.to_base64())
125 }
126}
127
128impl<'de> Deserialize<'de> for Signature {
129 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130 where
131 D: serde::Deserializer<'de>,
132 {
133 let s = String::deserialize(deserializer)?;
134 Self::from_base64(&s).map_err(serde::de::Error::custom)
135 }
136}
137
138impl From<DalekSignature> for Signature {
139 fn from(sig: DalekSignature) -> Self {
140 Self(sig.to_bytes())
141 }
142}
143
144impl From<Signature> for DalekSignature {
145 fn from(sig: Signature) -> Self {
146 DalekSignature::from_bytes(&sig.0)
147 }
148}
149
150impl From<[u8; 64]> for Signature {
151 fn from(bytes: [u8; 64]) -> Self {
152 Self(bytes)
153 }
154}
155
156impl From<Signature> for [u8; 64] {
157 fn from(sig: Signature) -> Self {
158 sig.0
159 }
160}
161
162impl AsRef<[u8]> for Signature {
163 fn as_ref(&self) -> &[u8] {
164 &self.0
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use crate::KeyPair;
172
173 #[test]
174 fn test_signature_encoding() {
175 let keypair = KeyPair::generate();
176 let message = b"test message";
177 let sig = keypair.sign(message);
178
179 let hex = sig.to_hex();
181 let decoded = Signature::from_hex(&hex).unwrap();
182 assert_eq!(sig, decoded);
183
184 let b64 = sig.to_base64();
186 let decoded = Signature::from_base64(&b64).unwrap();
187 assert_eq!(sig, decoded);
188 }
189
190 #[test]
191 fn test_signature_verification() {
192 let keypair = KeyPair::generate();
193 let message = b"test message";
194 let sig = keypair.sign(message);
195
196 assert!(sig.verify(message, keypair.public_key_bytes()).is_ok());
198
199 assert!(
201 sig.verify(b"wrong message", keypair.public_key_bytes())
202 .is_err()
203 );
204
205 let other_keypair = KeyPair::generate();
207 assert!(
208 sig.verify(message, other_keypair.public_key_bytes())
209 .is_err()
210 );
211 }
212
213 #[test]
214 fn test_invalid_signature_length() {
215 let result = Signature::try_from_slice(&[0u8; 63]);
216 assert!(matches!(
217 result,
218 Err(CryptoError::InvalidSignatureLength { .. })
219 ));
220 }
221}