1use crate::curve::{Curve, CurveInfoLock, CurveLock, PrivateKey, PublicKey};
2use crate::hasher::{HashingAlgorithm, Sha2, Sha3, Sha3k};
3use crate::hd_node::{HDNODE_PRIVKEY_LEN, HDNODE_PUBKEY_LEN};
4use crate::signature::{Signature, SIG_LEN};
5use generic_array::typenum::U32;
6use generic_array::GenericArray;
7
8pub const ED25519_PUBKEY_LEN: usize = 32;
9pub const ED25519_PRIVKEY_LEN: usize = 32;
10
11#[derive(Debug, Clone, Copy)]
12pub struct Ed25519;
13
14#[doc(hidden)]
15pub struct Ed25519Lock;
17
18const STATIC_ED25519_LOCK_DOES_NOTHING: Ed25519Lock = Ed25519Lock;
19
20impl CurveLock for Ed25519Lock {}
21
22#[doc(hidden)]
23pub struct Ed25519InfoLock;
25
26impl CurveInfoLock for Ed25519InfoLock {
27 type CurveLock = Ed25519Lock;
28 unsafe fn curve(&self) -> &Self::CurveLock {
29 &STATIC_ED25519_LOCK_DOES_NOTHING
30 }
31}
32
33impl Curve for Ed25519 {
34 type PublicKey = Ed25519PublicKey;
35 type PrivateKey = Ed25519PrivateKey;
36 type CurveInfoLock = Ed25519InfoLock;
37 unsafe fn curve_info_lock() -> Self::CurveInfoLock {
38 Ed25519InfoLock
39 }
40 unsafe fn name_ptr() -> *const std::os::raw::c_char {
41 sys::ED25519_NAME.as_ptr()
42 }
43}
44
45pub struct Ed25519Cardano;
46
47impl Curve for Ed25519Cardano {
48 type PublicKey = Ed25519PublicKey;
49 type PrivateKey = Ed25519PrivateKey;
50 type CurveInfoLock = Ed25519InfoLock;
51 unsafe fn curve_info_lock() -> Self::CurveInfoLock {
52 Ed25519InfoLock
53 }
54 fn is_cardano() -> bool {
55 true
56 }
57 unsafe fn name_ptr() -> *const std::os::raw::c_char {
58 sys::ED25519_CARDANO_NAME.as_ptr()
59 }
60}
61
62#[doc(hidden)]
63pub type Ed25519SignAlgo = unsafe extern "C" fn(*const u8, u64, *mut u8, *mut u8, *mut u8);
64#[doc(hidden)]
65pub type Ed25519VerifyAlgo = unsafe extern "C" fn(*const u8, u64, *mut u8, *mut u8) -> i32;
66
67pub trait Ed25519HashingAlgorithm: HashingAlgorithm {
68 #[doc(hidden)]
69 fn sign_algo() -> Ed25519SignAlgo;
70 #[doc(hidden)]
71 fn verify_algo() -> Ed25519VerifyAlgo;
72}
73
74macro_rules! ed25519_hashing_algo {
75 ($algo:ident, $sign_algo:path, $verify_algo:path) => {
76 impl Ed25519HashingAlgorithm for $algo {
77 fn sign_algo() -> Ed25519SignAlgo {
78 $sign_algo
79 }
80 fn verify_algo() -> Ed25519VerifyAlgo {
81 $verify_algo
82 }
83 }
84 };
85}
86
87ed25519_hashing_algo!(Sha2, sys::ed25519_sign, sys::ed25519_sign_open);
88ed25519_hashing_algo!(Sha3, sys::ed25519_sign_sha3, sys::ed25519_sign_open_sha3);
89ed25519_hashing_algo!(
90 Sha3k,
91 sys::ed25519_sign_keccak,
92 sys::ed25519_sign_open_keccak
93);
94
95#[derive(Clone)]
96pub struct Ed25519PrivateKey {
97 bytes: [u8; ED25519_PRIVKEY_LEN],
98}
99
100impl Ed25519PrivateKey {
101 #[inline]
102 pub fn from_bytes(bytes: [u8; ED25519_PRIVKEY_LEN]) -> Self {
103 Self { bytes }
104 }
105 pub fn from_slice(slice: &[u8]) -> Option<Self> {
106 if slice.len() == ED25519_PRIVKEY_LEN {
107 let mut bytes = [0; ED25519_PRIVKEY_LEN];
108 bytes.copy_from_slice(slice);
109 Some(Self::from_bytes(bytes))
110 } else {
111 None
112 }
113 }
114 pub fn public_key(&self) -> Ed25519PublicKey {
115 let mut bytes = [0; ED25519_PUBKEY_LEN];
116 unsafe { sys::ed25519_publickey(self.bytes.as_ptr() as *mut u8, bytes.as_mut_ptr()) }
117 Ed25519PublicKey::from_bytes(bytes)
118 }
119 pub fn sign<H: Ed25519HashingAlgorithm, D: AsRef<[u8]>>(&self, data: D) -> Signature<Ed25519> {
120 let data = data.as_ref();
121 let mut public_key = self.public_key();
122 let mut signature = [0; SIG_LEN];
123 unsafe {
124 H::sign_algo()(
125 data.as_ptr(),
126 data.len() as u64,
127 self.bytes.as_ptr() as *mut u8,
128 public_key.bytes.as_mut_ptr(),
129 signature.as_mut_ptr(),
130 );
131 }
132 Signature::from_bytes(signature)
133 }
134 pub fn public_key_ext(&self, private_key_ext: &Ed25519PrivateKey) -> Ed25519PublicKey {
135 let mut pk = [0; ED25519_PUBKEY_LEN];
136 let mut sk = self.bytes;
137 let mut sk_ext = private_key_ext.bytes;
138 unsafe {
139 sys::ed25519_publickey_ext(sk.as_mut_ptr(), sk_ext.as_mut_ptr(), pk.as_mut_ptr());
140 }
141 Ed25519PublicKey::from_bytes(pk)
142 }
143 pub fn sign_ext<D: AsRef<[u8]>>(
144 &self,
145 private_key_ext: &Ed25519PrivateKey,
146 data: D,
147 ) -> Signature<Ed25519> {
148 let data = data.as_ref();
149 let mut pk = [0; ED25519_PUBKEY_LEN];
150 let mut sk = self.bytes;
151 let mut sk_ext = private_key_ext.bytes;
152 let mut sig = [0; SIG_LEN];
153 unsafe {
154 sys::ed25519_publickey_ext(sk.as_mut_ptr(), sk_ext.as_mut_ptr(), pk.as_mut_ptr());
155 sys::ed25519_sign_ext(
156 data.as_ptr(),
157 data.len() as u64,
158 sk.as_mut_ptr(),
159 sk_ext.as_mut_ptr(),
160 pk.as_mut_ptr(),
161 sig.as_mut_ptr(),
162 )
163 }
164 Signature::from_bytes(sig)
165 }
166}
167
168impl PrivateKey for Ed25519PrivateKey {
169 type SerializedSize = U32;
170 #[inline]
171 fn from_bytes_unchecked(bytes: [u8; HDNODE_PRIVKEY_LEN]) -> Self {
172 Self::from_bytes(bytes)
173 }
174 #[inline]
175 fn to_bytes(self) -> [u8; HDNODE_PRIVKEY_LEN] {
176 self.bytes
177 }
178 #[inline]
179 fn serialize(&self) -> GenericArray<u8, Self::SerializedSize> {
180 self.bytes.into()
181 }
182}
183
184#[derive(Clone, Debug, PartialEq, Eq)]
185pub struct Ed25519PublicKey {
186 bytes: [u8; ED25519_PUBKEY_LEN],
187}
188
189impl Ed25519PublicKey {
190 #[inline]
191 pub fn from_bytes(bytes: [u8; ED25519_PUBKEY_LEN]) -> Self {
192 Self { bytes }
193 }
194 pub fn from_slice(slice: &[u8]) -> Option<Self> {
195 if slice.len() == ED25519_PUBKEY_LEN {
196 let mut bytes = [0; ED25519_PUBKEY_LEN];
197 bytes.copy_from_slice(slice);
198 Some(Self::from_bytes(bytes))
199 } else {
200 None
201 }
202 }
203 pub fn serialize(&self) -> [u8; ED25519_PUBKEY_LEN] {
204 self.bytes.clone()
205 }
206 pub fn verify<H: Ed25519HashingAlgorithm, D: AsRef<[u8]>>(
207 &self,
208 signature: &Signature<Ed25519>,
209 data: D,
210 ) -> bool {
211 let data = data.as_ref();
212 let res = unsafe {
213 H::verify_algo()(
214 data.as_ptr(),
215 data.len() as u64,
216 self.bytes.as_ptr() as *mut u8,
217 signature.bytes.as_ptr() as *mut u8,
218 )
219 };
220 res == 0
221 }
222}
223
224impl PublicKey for Ed25519PublicKey {
225 type SerializedSize = U32;
226 type UncompressedSize = U32;
227 #[inline]
228 fn from_bytes_unchecked(bytes: [u8; HDNODE_PUBKEY_LEN]) -> Self {
229 let mut pubkey = [0; 32];
230 pubkey.copy_from_slice(&bytes[1..]);
231 Self::from_bytes(pubkey)
232 }
233 #[inline]
234 fn to_bytes(self) -> [u8; HDNODE_PUBKEY_LEN] {
235 let mut out = [0; HDNODE_PUBKEY_LEN];
236 out[..ED25519_PUBKEY_LEN].copy_from_slice(&self.bytes);
237 out
238 }
239 fn serialize(&self) -> GenericArray<u8, Self::SerializedSize> {
240 GenericArray::clone_from_slice(&self.serialize())
241 }
242 fn serialize_uncompressed(&self) -> GenericArray<u8, Self::UncompressedSize> {
243 GenericArray::clone_from_slice(&self.serialize())
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn curve_name() {
253 assert_eq!("ed25519", Ed25519::name());
254 }
255
256 fn public_key_test_vector(priv_key_hex: &str, public_key_hex: &str) {
257 let private_key =
258 Ed25519PrivateKey::from_slice(&hex::decode(priv_key_hex).unwrap()).unwrap();
259 assert_eq!(
260 &private_key.public_key().serialize(),
261 hex::decode(public_key_hex).unwrap().as_slice()
262 );
263 }
264
265 #[test]
266 fn ed25519_public_key() {
267 public_key_test_vector(
268 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
269 "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
270 );
271 public_key_test_vector(
272 "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
273 "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
274 );
275 public_key_test_vector(
276 "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
277 "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
278 );
279 }
280
281 fn signature_test_vector(priv_key_hex: &str, message_hex: &str, signature_hex: &str) {
282 let private_key =
283 Ed25519PrivateKey::from_slice(&hex::decode(priv_key_hex).unwrap()).unwrap();
284 let message = hex::decode(message_hex).unwrap();
285 let signature = private_key.sign::<Sha2, _>(&message);
286 assert_eq!(
287 signature.serialize(),
288 hex::decode(signature_hex).unwrap().as_slice()
289 );
290 let public_key = private_key.public_key();
291 assert!(public_key.verify::<Sha2, _>(&signature, &message));
292 }
293
294 #[test]
295 fn ed25519_sign() {
296 signature_test_vector(
297 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
298 "",
299 "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"
300 );
301 signature_test_vector(
302 "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
303 "72",
304 "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00",
305 );
306 signature_test_vector(
307 "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
308 "af82",
309 "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a",
310 );
311 }
312
313 #[test]
314 fn ed25519_multi_thread() {
315 let mut children = Vec::new();
316 for _ in 0..10 {
317 children.push(std::thread::spawn(|| {
318 ed25519_public_key();
319 ed25519_sign();
320 }))
321 }
322 for child in children {
323 child.join().unwrap();
324 }
325 }
326
327 fn sign_ext_test_vector(
328 private_key_hex: &str,
329 private_key_ext_hex: &str,
330 public_key_ext_hex: &str,
331 signature_hex: &str,
332 ) {
333 let message = "Hello World";
334 let private_key =
335 Ed25519PrivateKey::from_slice(&hex::decode(private_key_hex).unwrap()).unwrap();
336 let private_key_ext =
337 Ed25519PrivateKey::from_slice(&hex::decode(private_key_ext_hex).unwrap()).unwrap();
338 let public_key_ext =
339 Ed25519PublicKey::from_slice(&hex::decode(public_key_ext_hex).unwrap()).unwrap();
340 let signature =
341 Signature::<Ed25519>::from_slice(&hex::decode(signature_hex).unwrap()).unwrap();
342 assert_eq!(private_key.public_key_ext(&private_key_ext), public_key_ext);
343 assert_eq!(private_key.sign_ext(&private_key_ext, message), signature);
344 }
345
346 #[test]
347 fn sign_ext_test_vectors() {
348 sign_ext_test_vector(
349 "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53",
350 "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e",
351 "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1",
352 "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d"
353 );
354 sign_ext_test_vector(
355 "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c",
356 "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803",
357 "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6",
358 "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602"
359 );
360 sign_ext_test_vector(
361 "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d",
362 "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02",
363 "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00",
364 "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901"
365 );
366 }
367}