trezor_crypto/
ed25519.rs

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)]
15/// Does nothing
16pub struct Ed25519Lock;
17
18const STATIC_ED25519_LOCK_DOES_NOTHING: Ed25519Lock = Ed25519Lock;
19
20impl CurveLock for Ed25519Lock {}
21
22#[doc(hidden)]
23/// Does nothing
24pub 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}