1use miden_protocol::Word;
2use miden_protocol::crypto::dsa::falcon512_poseidon2::{PublicKey, Signature};
3use miden_protocol::utils::serde::{Deserializable, Serializable};
4
5pub trait IntoHex {
7 fn into_hex(self) -> String;
8}
9
10pub trait FromHex: Sized {
12 fn from_hex(hex: &str) -> Result<Self, String>;
13}
14
15impl IntoHex for &PublicKey {
16 fn into_hex(self) -> String {
17 let mut pubkey_bytes = Vec::new();
18 self.write_into(&mut pubkey_bytes);
19 format!("0x{}", hex::encode(pubkey_bytes))
20 }
21}
22
23impl IntoHex for PublicKey {
24 fn into_hex(self) -> String {
25 (&self).into_hex()
26 }
27}
28
29impl FromHex for PublicKey {
30 fn from_hex(hex: &str) -> Result<Self, String> {
31 let hex_str = hex.strip_prefix("0x").unwrap_or(hex);
32 let bytes = hex::decode(hex_str).map_err(|e| format!("Invalid public key hex: {e}"))?;
33 PublicKey::read_from_bytes(&bytes)
34 .map_err(|e| format!("Failed to deserialize public key: {e}"))
35 }
36}
37
38impl IntoHex for Signature {
39 fn into_hex(self) -> String {
40 let signature_bytes = self.to_bytes();
41 format!("0x{}", hex::encode(&signature_bytes))
42 }
43}
44
45impl FromHex for Signature {
46 fn from_hex(hex: &str) -> Result<Self, String> {
47 let hex_str = hex.strip_prefix("0x").unwrap_or(hex);
48 let bytes = hex::decode(hex_str).map_err(|e| format!("Invalid signature hex: {e}"))?;
49
50 const EXPECTED_SIG_LEN: usize = 1524;
51 if bytes.len() != EXPECTED_SIG_LEN {
52 return Err(format!(
53 "Signature must be exactly {EXPECTED_SIG_LEN} bytes, got {} bytes",
54 bytes.len()
55 ));
56 }
57
58 Signature::read_from_bytes(&bytes)
59 .map_err(|e| format!("Failed to deserialize signature: {e}"))
60 }
61}
62
63impl IntoHex for Word {
64 fn into_hex(self) -> String {
65 format!("0x{}", hex::encode(self.as_bytes()))
66 }
67}
68
69impl IntoHex for &Word {
70 fn into_hex(self) -> String {
71 format!("0x{}", hex::encode(self.as_bytes()))
72 }
73}
74
75impl FromHex for Word {
76 fn from_hex(hex: &str) -> Result<Self, String> {
77 let hex_str = hex.strip_prefix("0x").unwrap_or(hex);
78 let bytes = hex::decode(hex_str).map_err(|e| format!("Invalid word hex: {e}"))?;
79
80 Word::read_from_bytes(&bytes).map_err(|e| format!("Failed to deserialize word: {e}"))
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use miden_protocol::crypto::dsa::falcon512_poseidon2::SecretKey;
88
89 #[test]
90 fn test_public_key_into_hex() {
91 let secret_key = SecretKey::new();
92 let public_key = secret_key.public_key();
93
94 let hex1 = (&public_key).into_hex();
96 assert!(hex1.starts_with("0x"));
97 assert_eq!(hex1.len(), 2 + (897 * 2));
98
99 let hex2 = public_key.into_hex();
101 assert_eq!(hex1, hex2);
102 }
103
104 #[test]
105 fn test_public_key_from_hex_roundtrip() {
106 let secret_key = SecretKey::new();
107 let original_pubkey = secret_key.public_key();
108
109 let hex = original_pubkey.into_hex();
111
112 let parsed_pubkey = PublicKey::from_hex(&hex).expect("Failed to parse public key");
114
115 assert_eq!(hex, parsed_pubkey.into_hex());
117 }
118
119 #[test]
120 fn test_public_key_from_hex_without_prefix() {
121 let secret_key = SecretKey::new();
122 let public_key = secret_key.public_key();
123 let hex_with_prefix = public_key.into_hex();
124
125 let hex_without_prefix = hex_with_prefix.strip_prefix("0x").unwrap();
127
128 let pubkey1 = PublicKey::from_hex(&hex_with_prefix).unwrap();
130 let pubkey2 = PublicKey::from_hex(hex_without_prefix).unwrap();
131
132 assert_eq!(pubkey1.into_hex(), pubkey2.into_hex());
133 }
134
135 #[test]
136 fn test_signature_into_hex() {
137 use miden_protocol::Word;
138 let secret_key = SecretKey::new();
139 let message = Word::from([1u32, 2, 3, 4]);
140 let signature = secret_key.sign(message);
141
142 let hex = signature.into_hex();
143 assert!(hex.starts_with("0x"));
144 assert_eq!(hex.len(), 2 + (1524 * 2));
145 }
146
147 #[test]
148 fn test_signature_from_hex_roundtrip() {
149 use miden_protocol::Word;
150 let secret_key = SecretKey::new();
151 let message = Word::from([1u32, 2, 3, 4]);
152 let original_sig = secret_key.sign(message);
153
154 let hex = original_sig.into_hex();
156
157 let parsed_sig = Signature::from_hex(&hex).expect("Failed to parse signature");
159
160 assert_eq!(hex, parsed_sig.into_hex());
162 }
163
164 #[test]
165 fn test_signature_from_hex_validates_length() {
166 let result = Signature::from_hex("0x1234");
168 assert!(result.is_err());
169 assert!(result.unwrap_err().contains("1524 bytes"));
170 }
171
172 #[test]
173 fn test_word_into_hex() {
174 let word = Word::from([1u32, 2, 3, 4]);
175 let hex = word.into_hex();
176 assert!(hex.starts_with("0x"));
177 assert_eq!(hex.len(), 2 + (32 * 2));
179 }
180
181 #[test]
182 fn test_word_from_hex_roundtrip() {
183 let original = Word::from([0xdeadbeefu32, 0xcafebabe, 0x12345678, 0x87654321]);
184 let hex = original.into_hex();
185 let parsed = Word::from_hex(&hex).expect("Failed to parse word");
186 assert_eq!(original, parsed);
187 }
188
189 #[test]
190 fn test_word_from_hex_without_prefix() {
191 let word = Word::from([1u32, 2, 3, 4]);
192 let hex_with_prefix = word.into_hex();
193 let hex_without_prefix = hex_with_prefix.strip_prefix("0x").unwrap();
194
195 let word1 = Word::from_hex(&hex_with_prefix).unwrap();
196 let word2 = Word::from_hex(hex_without_prefix).unwrap();
197 assert_eq!(word1, word2);
198 }
199
200 #[test]
201 fn test_word_reference_into_hex() {
202 let word = Word::from([1u32, 2, 3, 4]);
203 let hex1 = (&word).into_hex();
204 let hex2 = word.into_hex();
205 assert_eq!(hex1, hex2);
206 }
207}