linera_base/crypto/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Define the cryptographic primitives used by the Linera protocol.
6
7mod ed25519;
8mod hash;
9#[allow(dead_code)]
10mod secp256k1;
11use std::{fmt::Display, io, num::ParseIntError, str::FromStr};
12
13use alloy_primitives::FixedBytes;
14use custom_debug_derive::Debug;
15pub use ed25519::{Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature};
16pub use hash::*;
17use linera_witty::{WitLoad, WitStore, WitType};
18pub use secp256k1::{
19    evm::{EvmPublicKey, EvmSecretKey, EvmSignature},
20    Secp256k1PublicKey, Secp256k1SecretKey, Secp256k1Signature,
21};
22use serde::{Deserialize, Serialize};
23use thiserror::Error;
24
25/// The public key of a validator.
26pub type ValidatorPublicKey = secp256k1::Secp256k1PublicKey;
27/// The private key of a validator.
28pub type ValidatorSecretKey = secp256k1::Secp256k1SecretKey;
29/// The signature of a validator.
30pub type ValidatorSignature = secp256k1::Secp256k1Signature;
31/// The key pair of a validator.
32pub type ValidatorKeypair = secp256k1::Secp256k1KeyPair;
33
34/// Signature scheme used for the public key.
35#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
36pub enum SignatureScheme {
37    /// Ed25519
38    Ed25519,
39    /// secp256k1
40    Secp256k1,
41    /// EVM secp256k1
42    EvmSecp256k1,
43}
44
45/// The public key of a chain owner.
46/// The corresponding private key is allowed to propose blocks
47/// on the chain and transfer account's tokens.
48#[derive(
49    Serialize,
50    Deserialize,
51    Debug,
52    Eq,
53    PartialEq,
54    Ord,
55    PartialOrd,
56    Copy,
57    Clone,
58    Hash,
59    WitType,
60    WitLoad,
61    WitStore,
62)]
63pub enum AccountPublicKey {
64    /// Ed25519 public key.
65    Ed25519(ed25519::Ed25519PublicKey),
66    /// secp256k1 public key.
67    Secp256k1(secp256k1::Secp256k1PublicKey),
68    /// EVM secp256k1 public key.
69    EvmSecp256k1(secp256k1::evm::EvmPublicKey),
70}
71
72/// The private key of a chain owner.
73#[derive(Serialize, Deserialize)]
74pub enum AccountSecretKey {
75    /// Ed25519 secret key.
76    Ed25519(ed25519::Ed25519SecretKey),
77    /// secp256k1 secret key.
78    Secp256k1(secp256k1::Secp256k1SecretKey),
79    /// EVM secp256k1 secret key.
80    EvmSecp256k1(secp256k1::evm::EvmSecretKey),
81}
82
83/// The signature of a chain owner.
84#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)]
85pub enum AccountSignature {
86    /// Ed25519 signature.
87    Ed25519(ed25519::Ed25519Signature),
88    /// secp256k1 signature.
89    Secp256k1(secp256k1::Secp256k1Signature),
90    /// EVM secp256k1 signature.
91    EvmSecp256k1(secp256k1::evm::EvmSignature),
92}
93
94impl AccountSecretKey {
95    /// Returns the public key corresponding to this secret key.
96    pub fn public(&self) -> AccountPublicKey {
97        match self {
98            AccountSecretKey::Ed25519(secret) => AccountPublicKey::Ed25519(secret.public()),
99            AccountSecretKey::Secp256k1(secret) => AccountPublicKey::Secp256k1(secret.public()),
100            AccountSecretKey::EvmSecp256k1(secret) => {
101                AccountPublicKey::EvmSecp256k1(secret.public())
102            }
103        }
104    }
105
106    /// Copies the secret key.
107    pub fn copy(&self) -> Self {
108        match self {
109            AccountSecretKey::Ed25519(secret) => AccountSecretKey::Ed25519(secret.copy()),
110            AccountSecretKey::Secp256k1(secret) => AccountSecretKey::Secp256k1(secret.copy()),
111            AccountSecretKey::EvmSecp256k1(secret) => AccountSecretKey::EvmSecp256k1(secret.copy()),
112        }
113    }
114
115    /// Creates a signature for the `value` using provided `secret`.
116    pub fn sign<'de, T>(&self, value: &T) -> AccountSignature
117    where
118        T: BcsSignable<'de>,
119    {
120        match self {
121            AccountSecretKey::Ed25519(secret) => {
122                let signature = Ed25519Signature::new(value, secret);
123                AccountSignature::Ed25519(signature)
124            }
125            AccountSecretKey::Secp256k1(secret) => {
126                let signature = secp256k1::Secp256k1Signature::new(value, secret);
127                AccountSignature::Secp256k1(signature)
128            }
129            AccountSecretKey::EvmSecp256k1(secret) => {
130                let signature = secp256k1::evm::EvmSignature::new(value, secret);
131                AccountSignature::EvmSecp256k1(signature)
132            }
133        }
134    }
135
136    #[cfg(all(with_testing, with_getrandom))]
137    /// Generates a new key pair using the operating system's RNG.
138    pub fn generate() -> Self {
139        AccountSecretKey::Ed25519(Ed25519SecretKey::generate())
140    }
141}
142
143impl AccountPublicKey {
144    /// Returns the signature scheme of the public key.
145    pub fn scheme(&self) -> SignatureScheme {
146        match self {
147            AccountPublicKey::Ed25519(_) => SignatureScheme::Ed25519,
148            AccountPublicKey::Secp256k1(_) => SignatureScheme::Secp256k1,
149            AccountPublicKey::EvmSecp256k1(_) => SignatureScheme::EvmSecp256k1,
150        }
151    }
152
153    /// Returns the byte representation of the public key.
154    pub fn as_bytes(&self) -> Vec<u8> {
155        bcs::to_bytes(&self).expect("serialization to bytes should not fail")
156    }
157
158    /// Parses the byte representation of the public key.
159    ///
160    /// Returns error if the byte slice has incorrect length or the flag is not recognized.
161    pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
162        bcs::from_bytes(bytes).map_err(CryptoError::PublicKeyParseError)
163    }
164
165    /// A fake public key used for testing.
166    #[cfg(with_testing)]
167    pub fn test_key(name: u8) -> Self {
168        AccountPublicKey::Ed25519(Ed25519PublicKey::test_key(name))
169    }
170}
171
172impl AccountSignature {
173    /// Verifies the signature for the `value` using the provided `public_key`.
174    pub fn verify<'de, T>(&self, value: &T, author: AccountPublicKey) -> Result<(), CryptoError>
175    where
176        T: BcsSignable<'de> + std::fmt::Debug,
177    {
178        match (self, author) {
179            (AccountSignature::Ed25519(signature), AccountPublicKey::Ed25519(public_key)) => {
180                signature.check(value, public_key)
181            }
182            (AccountSignature::Secp256k1(signature), AccountPublicKey::Secp256k1(public_key)) => {
183                signature.check(value, &public_key)
184            }
185            (
186                AccountSignature::EvmSecp256k1(signature),
187                AccountPublicKey::EvmSecp256k1(public_key),
188            ) => signature.check(value, &public_key),
189            (AccountSignature::Ed25519(_), _) => {
190                let type_name = std::any::type_name::<T>();
191                Err(CryptoError::InvalidSignature {
192                    error: "invalid signature scheme. Expected Ed25519 signature.".to_string(),
193                    type_name: type_name.to_string(),
194                })
195            }
196            (AccountSignature::Secp256k1(_), _) => {
197                let type_name = std::any::type_name::<T>();
198                Err(CryptoError::InvalidSignature {
199                    error: "invalid signature scheme. Expected secp256k1 signature.".to_string(),
200                    type_name: type_name.to_string(),
201                })
202            }
203            (AccountSignature::EvmSecp256k1(_), _) => {
204                let type_name = std::any::type_name::<T>();
205                Err(CryptoError::InvalidSignature {
206                    error: "invalid signature scheme. Expected EvmSecp256k1 signature.".to_string(),
207                    type_name: type_name.to_string(),
208                })
209            }
210        }
211    }
212
213    /// Returns byte representation of the signatures.
214    pub fn to_bytes(&self) -> Vec<u8> {
215        bcs::to_bytes(&self).expect("serialization to bytes should not fail")
216    }
217
218    /// Parses the byte representation of the signature.
219    pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
220        bcs::from_bytes(bytes).map_err(CryptoError::SignatureParseError)
221    }
222}
223
224impl FromStr for AccountPublicKey {
225    type Err = CryptoError;
226
227    fn from_str(s: &str) -> Result<Self, Self::Err> {
228        let value = hex::decode(s)?;
229        AccountPublicKey::from_slice(value.as_slice())
230    }
231}
232
233impl Display for AccountPublicKey {
234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235        write!(f, "{}", hex::encode(self.as_bytes()))
236    }
237}
238
239impl TryFrom<&[u8]> for AccountSignature {
240    type Error = CryptoError;
241
242    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
243        AccountSignature::from_slice(bytes)
244    }
245}
246
247/// Error type for cryptographic errors.
248#[derive(Error, Debug)]
249#[allow(missing_docs)]
250pub enum CryptoError {
251    #[error("Signature for object {type_name} is not valid: {error}")]
252    InvalidSignature { error: String, type_name: String },
253    #[error("Signature from validator is missing")]
254    MissingValidatorSignature,
255    #[error(transparent)]
256    NonHexDigits(#[from] hex::FromHexError),
257    #[error(
258        "Byte slice has length {0} but a `CryptoHash` requires exactly {expected} bytes",
259        expected = FixedBytes::<32>::len_bytes(),
260    )]
261    IncorrectHashSize(usize),
262    #[error(
263        "Byte slice has length {len} but a {scheme} `PublicKey` requires exactly {expected} bytes"
264    )]
265    IncorrectPublicKeySize {
266        scheme: &'static str,
267        len: usize,
268        expected: usize,
269    },
270    #[error(
271        "byte slice has length {len} but a {scheme} `Signature` requires exactly {expected} bytes"
272    )]
273    IncorrectSignatureBytes {
274        scheme: &'static str,
275        len: usize,
276        expected: usize,
277    },
278    #[error("Could not parse integer: {0}")]
279    ParseIntError(#[from] ParseIntError),
280    #[error("secp256k1 error: {0}")]
281    Secp256k1Error(k256::ecdsa::Error),
282    #[error("could not parse public key: {0}: point at infinity")]
283    Secp256k1PointAtInfinity(String),
284    #[error("could not parse public key: {0}")]
285    PublicKeyParseError(bcs::Error),
286    #[error("could not parse signature: {0}")]
287    SignatureParseError(bcs::Error),
288}
289
290#[cfg(with_getrandom)]
291/// Wrapper around [`rand::CryptoRng`] and [`rand::RngCore`].
292pub trait CryptoRng: rand::CryptoRng + rand::RngCore + Send + Sync {}
293
294#[cfg(with_getrandom)]
295impl<T: rand::CryptoRng + rand::RngCore + Send + Sync> CryptoRng for T {}
296
297#[cfg(with_getrandom)]
298impl From<Option<u64>> for Box<dyn CryptoRng> {
299    fn from(seed: Option<u64>) -> Self {
300        use rand::SeedableRng;
301
302        match seed {
303            Some(seed) => Box::new(rand::rngs::StdRng::seed_from_u64(seed)),
304            None => Box::new(rand::rngs::OsRng),
305        }
306    }
307}
308
309/// Something that we know how to hash.
310pub trait Hashable<Hasher> {
311    /// Send the content of `Self` to the given hasher.
312    fn write(&self, hasher: &mut Hasher);
313}
314
315/// Something that we know how to hash and sign.
316pub trait HasTypeName {
317    /// The name of the type.
318    fn type_name() -> &'static str;
319}
320
321/// Activate the blanket implementation of `Hashable` based on serde and BCS.
322/// * We use `serde_name` to extract a seed from the name of structs and enums.
323/// * We use `BCS` to generate canonical bytes suitable for hashing.
324pub trait BcsHashable<'de>: Serialize + Deserialize<'de> {}
325
326/// Activate the blanket implementation of `Signable` based on serde and BCS.
327/// * We use `serde_name` to extract a seed from the name of structs and enums.
328/// * We use `BCS` to generate canonical bytes suitable for signing.
329pub trait BcsSignable<'de>: Serialize + Deserialize<'de> {}
330
331impl<'de, T: BcsSignable<'de>> BcsHashable<'de> for T {}
332
333impl<'de, T, Hasher> Hashable<Hasher> for T
334where
335    T: BcsHashable<'de>,
336    Hasher: io::Write,
337{
338    fn write(&self, hasher: &mut Hasher) {
339        let name = <Self as HasTypeName>::type_name();
340        // Note: This assumes that names never contain the separator `::`.
341        write!(hasher, "{}::", name).expect("Hasher should not fail");
342        bcs::serialize_into(hasher, &self).expect("Message serialization should not fail");
343    }
344}
345
346impl<Hasher> Hashable<Hasher> for [u8]
347where
348    Hasher: io::Write,
349{
350    fn write(&self, hasher: &mut Hasher) {
351        hasher.write_all(self).expect("Hasher should not fail");
352    }
353}
354
355impl<'de, T> HasTypeName for T
356where
357    T: BcsHashable<'de>,
358{
359    fn type_name() -> &'static str {
360        serde_name::trace_name::<Self>().expect("Self must be a struct or an enum")
361    }
362}
363
364/// A BCS-signable struct for testing.
365#[cfg(with_testing)]
366#[derive(Debug, Serialize, Deserialize)]
367pub struct TestString(pub String);
368
369#[cfg(with_testing)]
370impl TestString {
371    /// Creates a new `TestString` with the given string.
372    pub fn new(s: impl Into<String>) -> Self {
373        Self(s.into())
374    }
375}
376
377#[cfg(with_testing)]
378impl BcsSignable<'_> for TestString {}
379
380/// Reads the `bytes` as four little-endian unsigned 64-bit integers and returns them.
381pub(crate) fn le_bytes_to_u64_array(bytes: &[u8]) -> [u64; 4] {
382    let mut integers = [0u64; 4];
383
384    integers[0] = u64::from_le_bytes(bytes[0..8].try_into().expect("incorrect indices"));
385    integers[1] = u64::from_le_bytes(bytes[8..16].try_into().expect("incorrect indices"));
386    integers[2] = u64::from_le_bytes(bytes[16..24].try_into().expect("incorrect indices"));
387    integers[3] = u64::from_le_bytes(bytes[24..32].try_into().expect("incorrect indices"));
388
389    integers
390}
391
392/// Reads the `bytes` as four big-endian unsigned 64-bit integers and returns them.
393pub(crate) fn be_bytes_to_u64_array(bytes: &[u8]) -> [u64; 4] {
394    let mut integers = [0u64; 4];
395
396    integers[0] = u64::from_be_bytes(bytes[0..8].try_into().expect("incorrect indices"));
397    integers[1] = u64::from_be_bytes(bytes[8..16].try_into().expect("incorrect indices"));
398    integers[2] = u64::from_be_bytes(bytes[16..24].try_into().expect("incorrect indices"));
399    integers[3] = u64::from_be_bytes(bytes[24..32].try_into().expect("incorrect indices"));
400
401    integers
402}
403
404/// Returns the bytes that represent the `integers` in little-endian.
405pub(crate) fn u64_array_to_le_bytes(integers: [u64; 4]) -> [u8; 32] {
406    let mut bytes = [0u8; 32];
407
408    bytes[0..8].copy_from_slice(&integers[0].to_le_bytes());
409    bytes[8..16].copy_from_slice(&integers[1].to_le_bytes());
410    bytes[16..24].copy_from_slice(&integers[2].to_le_bytes());
411    bytes[24..32].copy_from_slice(&integers[3].to_le_bytes());
412
413    bytes
414}
415
416/// Returns the bytes that represent the `integers` in big-endian.
417pub(crate) fn u64_array_to_be_bytes(integers: [u64; 4]) -> [u8; 32] {
418    let mut bytes = [0u8; 32];
419
420    bytes[0..8].copy_from_slice(&integers[0].to_be_bytes());
421    bytes[8..16].copy_from_slice(&integers[1].to_be_bytes());
422    bytes[16..24].copy_from_slice(&integers[2].to_be_bytes());
423    bytes[24..32].copy_from_slice(&integers[3].to_be_bytes());
424
425    bytes
426}
427
428#[cfg(test)]
429mod tests {
430    use super::*;
431    use crate::crypto::{ed25519::Ed25519SecretKey, secp256k1::Secp256k1KeyPair};
432
433    #[test]
434    fn test_u64_array_to_be_bytes() {
435        let input = [
436            0x0123456789ABCDEF,
437            0xFEDCBA9876543210,
438            0x0011223344556677,
439            0x8899AABBCCDDEEFF,
440        ];
441        let expected_output = [
442            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
443            0x32, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB,
444            0xCC, 0xDD, 0xEE, 0xFF,
445        ];
446
447        let output = u64_array_to_be_bytes(input);
448        assert_eq!(output, expected_output);
449        assert_eq!(input, be_bytes_to_u64_array(&u64_array_to_be_bytes(input)));
450    }
451
452    #[test]
453    fn test_u64_array_to_le_bytes() {
454        let input = [
455            0x0123456789ABCDEF,
456            0xFEDCBA9876543210,
457            0x0011223344556677,
458            0x8899AABBCCDDEEFF,
459        ];
460        let expected_output = [
461            0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA,
462            0xDC, 0xFE, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC,
463            0xBB, 0xAA, 0x99, 0x88,
464        ];
465
466        let output = u64_array_to_le_bytes(input);
467        assert_eq!(output, expected_output);
468        assert_eq!(input, le_bytes_to_u64_array(&u64_array_to_le_bytes(input)));
469    }
470
471    #[test]
472    fn roundtrip_account_pk_bytes_repr() {
473        fn roundtrip_test(secret: AccountSecretKey) {
474            let public = secret.public();
475            let bytes = public.as_bytes();
476            let parsed = AccountPublicKey::from_slice(&bytes).unwrap();
477            assert_eq!(public, parsed);
478        }
479        roundtrip_test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
480        roundtrip_test(AccountSecretKey::Secp256k1(
481            Secp256k1KeyPair::generate().secret_key,
482        ));
483    }
484
485    #[test]
486    fn roundtrip_signature_bytes_repr() {
487        fn roundtrip_test(secret: AccountSecretKey) {
488            let test_string = TestString::new("test");
489            let signature = secret.sign(&test_string);
490            let bytes = signature.to_bytes();
491            let parsed = AccountSignature::from_slice(&bytes).unwrap();
492            assert_eq!(signature, parsed);
493        }
494        roundtrip_test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
495        roundtrip_test(AccountSecretKey::Secp256k1(
496            Secp256k1KeyPair::generate().secret_key,
497        ));
498    }
499
500    #[test]
501    fn roundtrip_display_from_str_pk() {
502        fn test(secret: AccountSecretKey) {
503            let public = secret.public();
504            let display = public.to_string();
505            let parsed = AccountPublicKey::from_str(&display).unwrap();
506            assert_eq!(public, parsed);
507        }
508        test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
509        test(AccountSecretKey::Secp256k1(
510            Secp256k1KeyPair::generate().secret_key,
511        ));
512    }
513}