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