linera_base/crypto/
ed25519.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Defines Ed25519 signature primitives used by the Linera protocol.
6
7use std::{borrow::Cow, fmt, str::FromStr};
8
9use ed25519_dalek::{self as dalek, Signer, Verifier};
10use linera_witty::{
11    GuestPointer, HList, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory,
12    WitLoad, WitStore, WitType,
13};
14use serde::{Deserialize, Serialize};
15
16use super::{
17    le_bytes_to_u64_array, u64_array_to_le_bytes, BcsHashable, BcsSignable, CryptoError,
18    CryptoHash, HasTypeName, Hashable,
19};
20use crate::doc_scalar;
21
22/// The label for the Ed25519 scheme.
23const ED25519_SCHEME_LABEL: &str = "Ed25519";
24
25/// An Ed25519 secret key.
26pub struct Ed25519SecretKey(pub(crate) dalek::SigningKey);
27
28/// An Ed25519 signature public key.
29#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash)]
30pub struct Ed25519PublicKey(pub [u8; dalek::PUBLIC_KEY_LENGTH]);
31
32/// An Ed25519 signature.
33#[derive(Eq, PartialEq, Copy, Clone)]
34pub struct Ed25519Signature(pub dalek::Signature);
35
36impl Ed25519SecretKey {
37    #[cfg(all(with_getrandom, with_testing))]
38    /// Generates a new key pair using the operating system's RNG.
39    ///
40    /// If you want control over the RNG, use [`Ed25519SecretKey::generate_from`].
41    pub fn generate() -> Self {
42        let mut rng = rand::rngs::OsRng;
43        Self::generate_from(&mut rng)
44    }
45
46    #[cfg(with_getrandom)]
47    /// Generates a new key pair from the given RNG. Use with care.
48    pub fn generate_from<R: super::CryptoRng>(rng: &mut R) -> Self {
49        let keypair = dalek::SigningKey::generate(rng);
50        Ed25519SecretKey(keypair)
51    }
52
53    /// Obtains the public key of a key pair.
54    pub fn public(&self) -> Ed25519PublicKey {
55        Ed25519PublicKey(self.0.verifying_key().to_bytes())
56    }
57
58    /// Copies the key pair, **including the secret key**.
59    ///
60    /// The `Clone` and `Copy` traits are deliberately not implemented for `KeyPair` to prevent
61    /// accidental copies of secret keys.
62    pub fn copy(&self) -> Ed25519SecretKey {
63        Ed25519SecretKey(self.0.clone())
64    }
65}
66
67impl Ed25519PublicKey {
68    /// A fake public key used for testing.
69    #[cfg(with_testing)]
70    pub fn test_key(name: u8) -> Ed25519PublicKey {
71        let addr = [name; dalek::PUBLIC_KEY_LENGTH];
72        Ed25519PublicKey(addr)
73    }
74
75    /// Returns bytes of the public key.
76    pub fn as_bytes(&self) -> Vec<u8> {
77        self.0.to_vec()
78    }
79
80    /// Parses bytes to a public key.
81    ///
82    /// Returns error if input bytes are not of the correct length.
83    pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
84        let key = bytes
85            .try_into()
86            .map_err(|_| CryptoError::IncorrectPublicKeySize {
87                scheme: ED25519_SCHEME_LABEL,
88                len: bytes.len(),
89                expected: dalek::PUBLIC_KEY_LENGTH,
90            })?;
91        Ok(Ed25519PublicKey(key))
92    }
93}
94
95impl Serialize for Ed25519PublicKey {
96    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
97    where
98        S: serde::ser::Serializer,
99    {
100        if serializer.is_human_readable() {
101            serializer.serialize_str(&hex::encode(self.as_bytes()))
102        } else {
103            serializer.serialize_newtype_struct("Ed25519PublicKey", &self.0)
104        }
105    }
106}
107
108impl<'de> Deserialize<'de> for Ed25519PublicKey {
109    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
110    where
111        D: serde::de::Deserializer<'de>,
112    {
113        if deserializer.is_human_readable() {
114            let s = String::deserialize(deserializer)?;
115            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
116            Ok(Self::from_slice(&value).map_err(serde::de::Error::custom)?)
117        } else {
118            #[derive(Deserialize)]
119            #[serde(rename = "Ed25519PublicKey")]
120            struct PublicKey([u8; dalek::PUBLIC_KEY_LENGTH]);
121
122            let value = PublicKey::deserialize(deserializer)?;
123            Ok(Self(value.0))
124        }
125    }
126}
127
128impl Serialize for Ed25519SecretKey {
129    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
130    where
131        S: serde::ser::Serializer,
132    {
133        // This is only used for JSON configuration.
134        assert!(serializer.is_human_readable());
135        serializer.serialize_str(&hex::encode(self.0.to_bytes()))
136    }
137}
138
139impl<'de> Deserialize<'de> for Ed25519SecretKey {
140    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141    where
142        D: serde::de::Deserializer<'de>,
143    {
144        // This is only used for JSON configuration.
145        assert!(deserializer.is_human_readable());
146        let s = String::deserialize(deserializer)?;
147        let value = hex::decode(s).map_err(serde::de::Error::custom)?;
148        let key =
149            dalek::SigningKey::from_bytes(value[..].try_into().map_err(serde::de::Error::custom)?);
150        Ok(Ed25519SecretKey(key))
151    }
152}
153
154impl FromStr for Ed25519PublicKey {
155    type Err = CryptoError;
156
157    fn from_str(s: &str) -> Result<Self, Self::Err> {
158        let value = hex::decode(s)?;
159        (value.as_slice()).try_into()
160    }
161}
162
163impl TryFrom<&[u8]> for Ed25519PublicKey {
164    type Error = CryptoError;
165
166    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
167        if value.len() != dalek::PUBLIC_KEY_LENGTH {
168            return Err(CryptoError::IncorrectPublicKeySize {
169                scheme: ED25519_SCHEME_LABEL,
170                len: value.len(),
171                expected: dalek::PUBLIC_KEY_LENGTH,
172            });
173        }
174        let mut pubkey = [0u8; dalek::PUBLIC_KEY_LENGTH];
175        pubkey.copy_from_slice(value);
176        Ok(Ed25519PublicKey(pubkey))
177    }
178}
179
180impl From<[u64; 4]> for Ed25519PublicKey {
181    fn from(integers: [u64; 4]) -> Self {
182        Ed25519PublicKey(u64_array_to_le_bytes(integers))
183    }
184}
185
186impl From<Ed25519PublicKey> for [u64; 4] {
187    fn from(pub_key: Ed25519PublicKey) -> Self {
188        le_bytes_to_u64_array(&pub_key.0)
189    }
190}
191
192impl fmt::Display for Ed25519PublicKey {
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        write!(f, "{}", hex::encode(&self.0[..]))
195    }
196}
197
198impl fmt::Debug for Ed25519PublicKey {
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        write!(f, "{}", hex::encode(&self.0[..8]))
201    }
202}
203
204impl WitType for Ed25519PublicKey {
205    const SIZE: u32 = <(u64, u64, u64, u64) as WitType>::SIZE;
206    type Layout = <(u64, u64, u64, u64) as WitType>::Layout;
207    type Dependencies = HList![];
208
209    fn wit_type_name() -> Cow<'static, str> {
210        "ed25519-public-key".into()
211    }
212
213    fn wit_type_declaration() -> Cow<'static, str> {
214        concat!(
215            "    record ed25519-public-key {\n",
216            "        part1: u64,\n",
217            "        part2: u64,\n",
218            "        part3: u64,\n",
219            "        part4: u64,\n",
220            "    }\n",
221        )
222        .into()
223    }
224}
225
226impl WitLoad for Ed25519PublicKey {
227    fn load<Instance>(
228        memory: &Memory<'_, Instance>,
229        location: GuestPointer,
230    ) -> Result<Self, RuntimeError>
231    where
232        Instance: InstanceWithMemory,
233        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
234    {
235        let (part1, part2, part3, part4) = WitLoad::load(memory, location)?;
236        Ok(Self::from([part1, part2, part3, part4]))
237    }
238
239    fn lift_from<Instance>(
240        flat_layout: <Self::Layout as Layout>::Flat,
241        memory: &Memory<'_, Instance>,
242    ) -> Result<Self, RuntimeError>
243    where
244        Instance: InstanceWithMemory,
245        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
246    {
247        let (part1, part2, part3, part4) = WitLoad::lift_from(flat_layout, memory)?;
248        Ok(Self::from([part1, part2, part3, part4]))
249    }
250}
251
252impl WitStore for Ed25519PublicKey {
253    fn store<Instance>(
254        &self,
255        memory: &mut Memory<'_, Instance>,
256        location: GuestPointer,
257    ) -> Result<(), RuntimeError>
258    where
259        Instance: InstanceWithMemory,
260        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
261    {
262        let [part1, part2, part3, part4] = (*self).into();
263        (part1, part2, part3, part4).store(memory, location)
264    }
265
266    fn lower<Instance>(
267        &self,
268        memory: &mut Memory<'_, Instance>,
269    ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
270    where
271        Instance: InstanceWithMemory,
272        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
273    {
274        let [part1, part2, part3, part4] = (*self).into();
275        (part1, part2, part3, part4).lower(memory)
276    }
277}
278
279impl BcsHashable<'_> for Ed25519PublicKey {}
280
281impl Ed25519Signature {
282    /// Computes a signature.
283    pub fn new<'de, T>(value: &T, secret: &Ed25519SecretKey) -> Self
284    where
285        T: BcsSignable<'de>,
286    {
287        Self::sign_prehash(secret, CryptoHash::new(value))
288    }
289
290    /// Computes a signature from a prehash.
291    pub fn sign_prehash(secret: &Ed25519SecretKey, prehash: CryptoHash) -> Self {
292        let signature = secret.0.sign(&prehash.as_bytes().0);
293        Ed25519Signature(signature)
294    }
295
296    /// Parses bytes to a signature.
297    ///
298    /// Returns error if input slice is not 64 bytes.
299    pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
300        let sig = dalek::Signature::from_slice(bytes).map_err(|_| {
301            CryptoError::IncorrectSignatureBytes {
302                scheme: ED25519_SCHEME_LABEL,
303                len: bytes.len(),
304                expected: dalek::SIGNATURE_LENGTH,
305            }
306        })?;
307        Ok(Ed25519Signature(sig))
308    }
309
310    fn check_internal<'de, T>(
311        &self,
312        value: &T,
313        author: Ed25519PublicKey,
314    ) -> Result<(), dalek::SignatureError>
315    where
316        T: BcsSignable<'de>,
317    {
318        let prehash = CryptoHash::new(value).as_bytes().0;
319        let public_key = dalek::VerifyingKey::from_bytes(&author.0)?;
320        public_key.verify(&prehash, &self.0)
321    }
322
323    /// Checks a signature.
324    pub fn check<'de, T>(&self, value: &T, author: Ed25519PublicKey) -> Result<(), CryptoError>
325    where
326        T: BcsSignable<'de> + fmt::Debug,
327    {
328        self.check_internal(value, author)
329            .map_err(|error| CryptoError::InvalidSignature {
330                error: error.to_string(),
331                type_name: T::type_name().to_string(),
332            })
333    }
334
335    fn verify_batch_internal<'a, 'de, T, I>(
336        value: &'a T,
337        votes: I,
338    ) -> Result<(), dalek::SignatureError>
339    where
340        T: BcsSignable<'de>,
341        I: IntoIterator<Item = (&'a Ed25519PublicKey, &'a Ed25519Signature)>,
342    {
343        let mut msg = Vec::new();
344        value.write(&mut msg);
345        let mut messages = Vec::new();
346        let mut signatures = Vec::new();
347        let mut public_keys = Vec::new();
348        for (addr, sig) in votes {
349            messages.push(msg.as_slice());
350            signatures.push(sig.0);
351            public_keys.push(dalek::VerifyingKey::from_bytes(&addr.0)?);
352        }
353        dalek::verify_batch(&messages[..], &signatures[..], &public_keys[..])
354    }
355
356    /// Verifies a batch of signatures.
357    // NOTE: This is unused now since we don't use ed25519 in consensus layer.
358    #[allow(unused)]
359    pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
360    where
361        T: BcsSignable<'de>,
362        I: IntoIterator<Item = (&'a Ed25519PublicKey, &'a Ed25519Signature)>,
363    {
364        Ed25519Signature::verify_batch_internal(value, votes).map_err(|error| {
365            CryptoError::InvalidSignature {
366                error: format!("batched {}", error),
367                type_name: T::type_name().to_string(),
368            }
369        })
370    }
371
372    /// Returns bytes of the signature.
373    pub fn as_bytes(&self) -> Vec<u8> {
374        self.0.to_bytes().to_vec()
375    }
376}
377
378impl Serialize for Ed25519Signature {
379    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
380    where
381        S: serde::ser::Serializer,
382    {
383        if serializer.is_human_readable() {
384            serializer.serialize_str(&hex::encode(self.0.to_bytes()))
385        } else {
386            serializer.serialize_newtype_struct("Ed25519Signature", &self.0)
387        }
388    }
389}
390
391impl<'de> Deserialize<'de> for Ed25519Signature {
392    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
393    where
394        D: serde::de::Deserializer<'de>,
395    {
396        if deserializer.is_human_readable() {
397            let s = String::deserialize(deserializer)?;
398            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
399            Self::from_slice(&value).map_err(serde::de::Error::custom)
400        } else {
401            #[derive(Deserialize)]
402            #[serde(rename = "Ed25519Signature")]
403            struct Signature(dalek::Signature);
404
405            let value = Signature::deserialize(deserializer)?;
406            Ok(Self(value.0))
407        }
408    }
409}
410
411impl fmt::Display for Ed25519Signature {
412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413        let s = hex::encode(self.0.to_bytes());
414        write!(f, "{}", s)
415    }
416}
417
418impl fmt::Debug for Ed25519Signature {
419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420        write!(f, "{}", hex::encode(&self.0.to_bytes()[0..8]))
421    }
422}
423
424doc_scalar!(Ed25519Signature, "An Ed25519 signature value");
425doc_scalar!(Ed25519PublicKey, "A Ed25519 signature public key");
426
427#[cfg(with_testing)]
428mod tests {
429    #[test]
430    fn test_signatures() {
431        use serde::{Deserialize, Serialize};
432
433        use crate::crypto::{
434            ed25519::{Ed25519SecretKey, Ed25519Signature},
435            BcsSignable, TestString,
436        };
437
438        #[derive(Debug, Serialize, Deserialize)]
439        struct Foo(String);
440
441        impl BcsSignable<'_> for Foo {}
442
443        let key1 = Ed25519SecretKey::generate();
444        let addr1 = key1.public();
445        let key2 = Ed25519SecretKey::generate();
446        let addr2 = key2.public();
447
448        let ts = TestString("hello".into());
449        let tsx = TestString("hellox".into());
450        let foo = Foo("hello".into());
451
452        let s = Ed25519Signature::new(&ts, &key1);
453        assert!(s.check(&ts, addr1).is_ok());
454        assert!(s.check(&ts, addr2).is_err());
455        assert!(s.check(&tsx, addr1).is_err());
456        assert!(s.check(&foo, addr1).is_err());
457    }
458
459    #[test]
460    fn test_public_key_serialization() {
461        use crate::crypto::ed25519::Ed25519PublicKey;
462        let key_in = Ed25519PublicKey::test_key(0);
463        let s = serde_json::to_string(&key_in).unwrap();
464        let key_out: Ed25519PublicKey = serde_json::from_str(&s).unwrap();
465        assert_eq!(key_out, key_in);
466
467        let s = bcs::to_bytes(&key_in).unwrap();
468        let key_out: Ed25519PublicKey = bcs::from_bytes(&s).unwrap();
469        assert_eq!(key_out, key_in);
470    }
471
472    #[test]
473    fn test_secret_key_serialization() {
474        use crate::crypto::ed25519::Ed25519SecretKey;
475        let key_in = Ed25519SecretKey::generate();
476        let s = serde_json::to_string(&key_in).unwrap();
477        let key_out: Ed25519SecretKey = serde_json::from_str(&s).unwrap();
478        assert_eq!(key_out.0.to_bytes(), key_in.0.to_bytes());
479    }
480
481    #[test]
482    fn test_signature_serialization() {
483        use crate::crypto::ed25519::Ed25519Signature;
484        let sig_in = Ed25519Signature::from_slice(&[0u8; 64]).unwrap();
485        let s = serde_json::to_string(&sig_in).unwrap();
486        let sig_out: Ed25519Signature = serde_json::from_str(&s).unwrap();
487        assert_eq!(sig_out.0.to_bytes(), sig_in.0.to_bytes());
488
489        let s = bcs::to_bytes(&sig_in).unwrap();
490        let sig_out: Ed25519Signature = bcs::from_bytes(&s).unwrap();
491        assert_eq!(sig_out, sig_in);
492    }
493}