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