1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "kebab-case")]
9pub enum SignatureAlgorithm {
10 Ed25519,
12 EcdsaSecp256k1,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct Signature {
24 pub algorithm: SignatureAlgorithm,
25 #[serde(with = "hex_bytes")]
26 pub bytes: Vec<u8>,
27}
28
29mod hex_bytes {
31 use serde::{Deserialize, Deserializer, Serializer};
32
33 pub fn serialize<S: Serializer>(bytes: &[u8], ser: S) -> Result<S::Ok, S::Error> {
34 ser.serialize_str(&hex_encode(bytes))
35 }
36
37 pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Vec<u8>, D::Error> {
38 let s = String::deserialize(de)?;
39 hex_decode(&s).map_err(serde::de::Error::custom)
40 }
41
42 fn hex_encode(bytes: &[u8]) -> String {
43 let mut s = String::with_capacity(bytes.len() * 2);
44 for b in bytes {
45 s.push_str(&format!("{:02x}", b));
46 }
47 s
48 }
49
50 fn hex_decode(s: &str) -> Result<Vec<u8>, String> {
51 if !s.len().is_multiple_of(2) {
52 return Err(format!("odd hex length: {}", s.len()));
53 }
54 let mut out = Vec::with_capacity(s.len() / 2);
55 for i in (0..s.len()).step_by(2) {
56 let byte = u8::from_str_radix(&s[i..i + 2], 16)
57 .map_err(|e| format!("invalid hex at {}: {}", i, e))?;
58 out.push(byte);
59 }
60 Ok(out)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn serde_roundtrip_ed25519() {
70 let sig = Signature {
71 algorithm: SignatureAlgorithm::Ed25519,
72 bytes: vec![0xde, 0xad, 0xbe, 0xef],
73 };
74 let json = serde_json::to_string(&sig).unwrap();
75 assert!(json.contains("deadbeef"));
76 assert!(json.contains("ed25519"));
77 let back: Signature = serde_json::from_str(&json).unwrap();
78 assert_eq!(sig, back);
79 }
80
81 #[test]
82 fn serde_roundtrip_ecdsa() {
83 let sig = Signature {
84 algorithm: SignatureAlgorithm::EcdsaSecp256k1,
85 bytes: vec![0x01, 0x02, 0x03],
86 };
87 let json = serde_json::to_string(&sig).unwrap();
88 assert!(json.contains("ecdsa-secp256k1"));
89 let back: Signature = serde_json::from_str(&json).unwrap();
90 assert_eq!(sig, back);
91 }
92}