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