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