linera_base/crypto/secp256k1/
evm.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Defines EIP-191 compatible signature primitives used by the Linera protocol.
5
6use std::{
7    borrow::Cow,
8    fmt,
9    hash::{Hash, Hasher},
10    str::FromStr,
11};
12
13use alloy_primitives::{eip191_hash_message, Signature};
14use k256::{
15    ecdsa::{SigningKey, VerifyingKey},
16    elliptic_curve::sec1::FromEncodedPoint,
17    EncodedPoint,
18};
19use linera_witty::{
20    GuestPointer, HList, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory,
21    WitLoad, WitStore, WitType,
22};
23use serde::{Deserialize, Serialize};
24
25use super::{BcsHashable, BcsSignable, CryptoError, CryptoHash, HasTypeName};
26use crate::doc_scalar;
27
28/// Name of the secp256k1 scheme.
29const EVM_SECP256K1_SCHEME_LABEL: &str = "evm_secp256k1";
30
31/// Length of secp256k1 compressed public key.
32const EVM_SECP256K1_PUBLIC_KEY_SIZE: usize = 33;
33
34/// Length of secp256k1 signature.
35const EVM_SECP256K1_SIGNATURE_SIZE: usize = 64;
36
37/// A secp256k1 secret key.
38pub struct EvmSecretKey(pub SigningKey);
39
40impl Eq for EvmSecretKey {}
41impl PartialEq for EvmSecretKey {
42    fn eq(&self, other: &Self) -> bool {
43        self.0.to_bytes() == other.0.to_bytes()
44    }
45}
46
47/// A secp256k1 public key.
48#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
49pub struct EvmPublicKey(pub VerifyingKey);
50
51impl Hash for EvmPublicKey {
52    fn hash<H: Hasher>(&self, state: &mut H) {
53        self.0.to_encoded_point(true).as_bytes().hash(state);
54    }
55}
56
57/// Secp256k1 public/secret key pair.
58#[derive(Debug, PartialEq, Eq)]
59pub struct EvmKeyPair {
60    /// Secret key.
61    pub secret_key: EvmSecretKey,
62    /// Public key.
63    pub public_key: EvmPublicKey,
64}
65
66/// A secp256k1 signature.
67#[derive(Eq, PartialEq, Copy, Clone)]
68pub struct EvmSignature(pub(crate) Signature);
69
70impl FromStr for EvmSignature {
71    type Err = CryptoError;
72
73    fn from_str(s: &str) -> Result<Self, Self::Err> {
74        // If the string starts with "0x", we remove it before decoding.
75        let bytes = hex::decode(s.strip_prefix("0x").unwrap_or(s))?;
76        let sig = Signature::from_erc2098(&bytes);
77        Ok(EvmSignature(sig))
78    }
79}
80
81impl EvmPublicKey {
82    /// A fake public key used for testing.
83    #[cfg(with_testing)]
84    pub fn test_key(seed: u8) -> Self {
85        use rand::SeedableRng;
86        let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
87        let sk = k256::SecretKey::random(&mut rng);
88        Self(sk.public_key().into())
89    }
90
91    /// Returns the bytes of the public key in compressed representation.
92    pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE] {
93        // UNWRAP: We already have valid key so conversion should not fail.
94        self.0.to_encoded_point(true).as_bytes().try_into().unwrap()
95    }
96
97    /// Decodes the bytes into the public key.
98    /// Expects the bytes to be of compressed representation.
99    ///
100    /// Panics if the encoding can't be done in a constant time.
101    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
102        let encoded_point =
103            EncodedPoint::from_bytes(bytes).map_err(|_| CryptoError::IncorrectPublicKeySize {
104                scheme: EVM_SECP256K1_SCHEME_LABEL,
105                len: bytes.len(),
106                expected: EVM_SECP256K1_PUBLIC_KEY_SIZE,
107            })?;
108
109        match k256::PublicKey::from_encoded_point(&encoded_point).into_option() {
110            Some(public_key) => Ok(Self(public_key.into())),
111            None => {
112                let error = CryptoError::Secp256k1PointAtInfinity(hex::encode(bytes));
113                Err(error)
114            }
115        }
116    }
117}
118
119impl fmt::Debug for EvmSecretKey {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        write!(f, "<redacted for secp256k1 secret key>")
122    }
123}
124
125impl Serialize for EvmSecretKey {
126    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
127    where
128        S: serde::ser::Serializer,
129    {
130        // This is only used for JSON configuration.
131        assert!(serializer.is_human_readable());
132        serializer.serialize_str(&hex::encode(self.0.to_bytes()))
133    }
134}
135
136impl<'de> Deserialize<'de> for EvmSecretKey {
137    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
138    where
139        D: serde::de::Deserializer<'de>,
140    {
141        // This is only used for JSON configuration.
142        assert!(deserializer.is_human_readable());
143        let str = String::deserialize(deserializer)?;
144        let bytes = hex::decode(&str).map_err(serde::de::Error::custom)?;
145        let sk = SigningKey::from_slice(&bytes).map_err(serde::de::Error::custom)?;
146        Ok(EvmSecretKey(sk))
147    }
148}
149
150#[cfg(with_testing)]
151impl FromStr for EvmSecretKey {
152    type Err = CryptoError;
153
154    fn from_str(s: &str) -> Result<Self, Self::Err> {
155        let bytes = hex::decode(s)?;
156        let sk = SigningKey::from_slice(&bytes).expect("Failed to create secret key");
157        Ok(EvmSecretKey(sk))
158    }
159}
160
161impl Serialize for EvmPublicKey {
162    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
163    where
164        S: serde::ser::Serializer,
165    {
166        if serializer.is_human_readable() {
167            serializer.serialize_str(&hex::encode(self.as_bytes()))
168        } else {
169            let compact_pk = serde_utils::CompressedPublicKey(self.as_bytes());
170            serializer.serialize_newtype_struct("EvmPublicKey", &compact_pk)
171        }
172    }
173}
174
175impl<'de> Deserialize<'de> for EvmPublicKey {
176    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177    where
178        D: serde::de::Deserializer<'de>,
179    {
180        if deserializer.is_human_readable() {
181            let s = String::deserialize(deserializer)?;
182            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
183            Ok(EvmPublicKey::from_bytes(&value).map_err(serde::de::Error::custom)?)
184        } else {
185            #[derive(Deserialize)]
186            #[serde(rename = "EvmPublicKey")]
187            struct PublicKey(serde_utils::CompressedPublicKey);
188            let compact = PublicKey::deserialize(deserializer)?;
189            Ok(EvmPublicKey::from_bytes(&compact.0 .0).map_err(serde::de::Error::custom)?)
190        }
191    }
192}
193
194impl FromStr for EvmPublicKey {
195    type Err = CryptoError;
196
197    fn from_str(s: &str) -> Result<Self, Self::Err> {
198        hex::decode(s.strip_prefix("0x").unwrap_or(s))?
199            .as_slice()
200            .try_into()
201    }
202}
203
204impl TryFrom<&[u8]> for EvmPublicKey {
205    type Error = CryptoError;
206
207    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
208        Self::from_bytes(value)
209    }
210}
211
212impl fmt::Display for EvmPublicKey {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        let str = hex::encode(self.as_bytes());
215        write!(f, "{}", str)
216    }
217}
218
219impl fmt::Debug for EvmPublicKey {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
222    }
223}
224
225impl BcsHashable<'_> for EvmPublicKey {}
226
227impl WitType for EvmPublicKey {
228    const SIZE: u32 = <(u64, u64, u64, u64, u8) as WitType>::SIZE;
229    type Layout = <(u64, u64, u64, u64, u8) as WitType>::Layout;
230    type Dependencies = HList![];
231
232    fn wit_type_name() -> Cow<'static, str> {
233        "evm-secp256k1-public-key".into()
234    }
235
236    fn wit_type_declaration() -> Cow<'static, str> {
237        concat!(
238            "    record evm-secp256k1-public-key {\n",
239            "        part1: u64,\n",
240            "        part2: u64,\n",
241            "        part3: u64,\n",
242            "        part4: u64,\n",
243            "        part5: u8\n",
244            "    }\n",
245        )
246        .into()
247    }
248}
249
250impl WitLoad for EvmPublicKey {
251    fn load<Instance>(
252        memory: &Memory<'_, Instance>,
253        location: GuestPointer,
254    ) -> Result<Self, RuntimeError>
255    where
256        Instance: InstanceWithMemory,
257        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
258    {
259        let (part1, part2, part3, part4, part5) = WitLoad::load(memory, location)?;
260        Ok(Self::from((part1, part2, part3, part4, part5)))
261    }
262
263    fn lift_from<Instance>(
264        flat_layout: <Self::Layout as Layout>::Flat,
265        memory: &Memory<'_, Instance>,
266    ) -> Result<Self, RuntimeError>
267    where
268        Instance: InstanceWithMemory,
269        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
270    {
271        let (part1, part2, part3, part4, part5) = WitLoad::lift_from(flat_layout, memory)?;
272        Ok(Self::from((part1, part2, part3, part4, part5)))
273    }
274}
275
276impl WitStore for EvmPublicKey {
277    fn store<Instance>(
278        &self,
279        memory: &mut Memory<'_, Instance>,
280        location: GuestPointer,
281    ) -> Result<(), RuntimeError>
282    where
283        Instance: InstanceWithMemory,
284        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
285    {
286        let (part1, part2, part3, part4, part5) = (*self).into();
287        (part1, part2, part3, part4, part5).store(memory, location)
288    }
289
290    fn lower<Instance>(
291        &self,
292        memory: &mut Memory<'_, Instance>,
293    ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
294    where
295        Instance: InstanceWithMemory,
296        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
297    {
298        let (part1, part2, part3, part4, part5) = (*self).into();
299        (part1, part2, part3, part4, part5).lower(memory)
300    }
301}
302
303impl From<(u64, u64, u64, u64, u8)> for EvmPublicKey {
304    fn from((part1, part2, part3, part4, part5): (u64, u64, u64, u64, u8)) -> Self {
305        let mut bytes = [0u8; EVM_SECP256K1_PUBLIC_KEY_SIZE];
306        bytes[0..8].copy_from_slice(&part1.to_be_bytes());
307        bytes[8..16].copy_from_slice(&part2.to_be_bytes());
308        bytes[16..24].copy_from_slice(&part3.to_be_bytes());
309        bytes[24..32].copy_from_slice(&part4.to_be_bytes());
310        bytes[32] = part5;
311        Self::from_bytes(&bytes).unwrap()
312    }
313}
314
315impl From<EvmPublicKey> for (u64, u64, u64, u64, u8) {
316    fn from(key: EvmPublicKey) -> Self {
317        let bytes = key.as_bytes();
318        let part1 = u64::from_be_bytes(bytes[0..8].try_into().unwrap());
319        let part2 = u64::from_be_bytes(bytes[8..16].try_into().unwrap());
320        let part3 = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
321        let part4 = u64::from_be_bytes(bytes[24..32].try_into().unwrap());
322        let part5 = bytes[32];
323        (part1, part2, part3, part4, part5)
324    }
325}
326
327impl EvmKeyPair {
328    /// Generates a new key pair.
329    #[cfg(all(with_getrandom, with_testing))]
330    pub fn generate() -> Self {
331        let mut rng = rand::rngs::OsRng;
332        Self::generate_from(&mut rng)
333    }
334
335    /// Generates a new key pair from the given RNG. Use with care.
336    #[cfg(with_getrandom)]
337    pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
338        let secret_key = EvmSecretKey(SigningKey::random(rng));
339        let public_key = secret_key.public();
340        EvmKeyPair {
341            secret_key,
342            public_key,
343        }
344    }
345}
346
347impl EvmSecretKey {
348    /// Returns a public key for the given secret key.
349    pub fn public(&self) -> EvmPublicKey {
350        EvmPublicKey(*self.0.verifying_key())
351    }
352
353    /// Copies the key pair, **including the secret key**.
354    ///
355    /// The `Clone` and `Copy` traits are deliberately not implemented for `EvmSecretKey` to prevent
356    /// accidental copies of secret keys.
357    pub fn copy(&self) -> Self {
358        Self(self.0.clone())
359    }
360
361    /// Generates a new key pair.
362    #[cfg(all(with_getrandom, with_testing))]
363    pub fn generate() -> Self {
364        let mut rng = rand::rngs::OsRng;
365        Self::generate_from(&mut rng)
366    }
367
368    /// Generates a new key pair from the given RNG. Use with care.
369    #[cfg(with_getrandom)]
370    pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
371        EvmSecretKey(SigningKey::random(rng))
372    }
373}
374
375impl EvmSignature {
376    /// Computes a secp256k1 signature for `prehash` using the given `secret`.
377    pub fn new(prehash: CryptoHash, secret: &EvmSecretKey) -> Self {
378        Self::sign_prehash(secret, prehash)
379    }
380
381    /// Computes a signature from a prehash.
382    pub fn sign_prehash(secret: &EvmSecretKey, prehash: CryptoHash) -> Self {
383        use k256::ecdsa::signature::hazmat::PrehashSigner;
384
385        let message = eip191_hash_message(prehash.as_bytes().0).0;
386        let (signature, rid) = secret
387            .0
388            .sign_prehash(&message)
389            .expect("Failed to sign prehashed data"); // NOTE: This is a critical error we don't control.
390        EvmSignature((signature, rid).into())
391    }
392
393    /// Checks a signature.
394    pub fn check<'de, T>(&self, value: &T, author: &EvmPublicKey) -> Result<(), CryptoError>
395    where
396        T: BcsSignable<'de> + fmt::Debug,
397    {
398        let prehash = CryptoHash::new(value).as_bytes().0;
399        self.verify_inner::<T>(prehash, author)
400    }
401
402    /// Verifies a batch of signatures.
403    ///
404    /// Returns an error on first failed signature.
405    pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
406    where
407        T: BcsSignable<'de> + fmt::Debug,
408        I: IntoIterator<Item = &'a (EvmPublicKey, EvmSignature)>,
409    {
410        let prehash = CryptoHash::new(value).as_bytes().0;
411        for (author, signature) in votes {
412            signature.verify_inner::<T>(prehash, author)?;
413        }
414        Ok(())
415    }
416
417    /// Returns the byte representation of the signature.
418    pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_SIGNATURE_SIZE] {
419        self.0.as_erc2098()
420    }
421
422    fn verify_inner<'de, T>(
423        &self,
424        prehash: [u8; 32],
425        author: &EvmPublicKey,
426    ) -> Result<(), CryptoError>
427    where
428        T: BcsSignable<'de> + fmt::Debug,
429    {
430        use k256::ecdsa::signature::hazmat::PrehashVerifier;
431
432        let message_hash = eip191_hash_message(prehash).0;
433
434        author
435            .0
436            .verify_prehash(&message_hash, &self.0.to_k256().unwrap())
437            .map_err(|error| CryptoError::InvalidSignature {
438                error: error.to_string(),
439                type_name: T::type_name().to_string(),
440            })
441    }
442
443    /// Creates a signature from the bytes.
444    /// Expects the signature to be serialized in raw-bytes form.
445    pub fn from_slice<A: AsRef<[u8]>>(bytes: A) -> Result<Self, CryptoError> {
446        let bytes = bytes.as_ref();
447        if bytes.len() < 64 {
448            return Err(CryptoError::IncorrectSignatureBytes {
449                scheme: EVM_SECP256K1_SCHEME_LABEL,
450                len: bytes.len(),
451                expected: EVM_SECP256K1_SIGNATURE_SIZE,
452            });
453        }
454        let sig = alloy_primitives::Signature::from_erc2098(bytes);
455        Ok(EvmSignature(sig))
456    }
457}
458
459impl Serialize for EvmSignature {
460    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
461    where
462        S: serde::ser::Serializer,
463    {
464        if serializer.is_human_readable() {
465            serializer.serialize_str(&hex::encode(self.as_bytes()))
466        } else {
467            let compact = serde_utils::CompactSignature(self.as_bytes());
468            serializer.serialize_newtype_struct("EvmSignature", &compact)
469        }
470    }
471}
472
473impl<'de> Deserialize<'de> for EvmSignature {
474    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
475    where
476        D: serde::de::Deserializer<'de>,
477    {
478        if deserializer.is_human_readable() {
479            let s = String::deserialize(deserializer)?;
480            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
481            Self::from_slice(&value).map_err(serde::de::Error::custom)
482        } else {
483            #[derive(Deserialize)]
484            #[serde(rename = "EvmSignature")]
485            struct Signature(serde_utils::CompactSignature);
486
487            let value = Signature::deserialize(deserializer)?;
488            Self::from_slice(value.0 .0.as_ref()).map_err(serde::de::Error::custom)
489        }
490    }
491}
492
493impl fmt::Display for EvmSignature {
494    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495        let s = hex::encode(self.as_bytes());
496        write!(f, "{}", s)
497    }
498}
499
500impl fmt::Debug for EvmSignature {
501    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502        write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
503    }
504}
505
506doc_scalar!(EvmSignature, "A secp256k1 signature value");
507doc_scalar!(EvmPublicKey, "A secp256k1 public key value");
508
509mod serde_utils {
510    use serde::{Deserialize, Serialize};
511    use serde_with::serde_as;
512
513    use super::{EVM_SECP256K1_PUBLIC_KEY_SIZE, EVM_SECP256K1_SIGNATURE_SIZE};
514
515    /// Wrapper around compact signature serialization
516    /// so that we can implement custom serializer for it that uses fixed length.
517    // Serde treats arrays larger than 32 as variable length arrays, and adds the length as a prefix.
518    // Since we want a fixed size representation, we wrap it in this helper struct and use serde_as.
519    #[serde_as]
520    #[derive(Serialize, Deserialize)]
521    #[serde(transparent)]
522    pub struct CompactSignature(#[serde_as(as = "[_; 64]")] pub [u8; EVM_SECP256K1_SIGNATURE_SIZE]);
523
524    #[serde_as]
525    #[derive(Serialize, Deserialize)]
526    #[serde(transparent)]
527    pub struct CompressedPublicKey(
528        #[serde_as(as = "[_; 33]")] pub [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE],
529    );
530}
531
532#[cfg(with_testing)]
533mod tests {
534    #[test]
535    fn eip191_compatibility() {
536        use std::str::FromStr;
537
538        use crate::crypto::{CryptoHash, EvmSecretKey, EvmSignature};
539
540        // Generated in MetaMask.
541        let secret_key = "f77a21701522a03b01c111ad2d2cdaf2b8403b47507ee0aec3c2e52b765d7a66";
542        let signer = EvmSecretKey::from_str(secret_key).unwrap();
543
544        let crypto_hash = CryptoHash::from_str(
545            "c520e2b24b05e70c39c36d4aa98e9129ac0079ea002d4c382e6996ea11946d1e",
546        )
547        .unwrap();
548
549        let signature = EvmSignature::new(crypto_hash, &signer);
550        let js_signature = EvmSignature::from_str("0xe257048813b851f812ba6e508e972d8bb09504824692b027ca95d31301dbe8c7103a2f35ce9950d031d260f412dcba09c24027288872a67abe261c0a3e55c9121b").unwrap();
551        assert_eq!(signature, js_signature);
552    }
553
554    #[test]
555    fn test_signatures() {
556        use serde::{Deserialize, Serialize};
557
558        use crate::crypto::{
559            secp256k1::evm::{EvmKeyPair, EvmSignature},
560            BcsSignable, CryptoHash, TestString,
561        };
562
563        #[derive(Debug, Serialize, Deserialize)]
564        struct Foo(String);
565
566        impl BcsSignable<'_> for Foo {}
567
568        let keypair1 = EvmKeyPair::generate();
569        let keypair2 = EvmKeyPair::generate();
570
571        let ts = TestString("hello".into());
572        let ts_cryptohash = CryptoHash::new(&ts);
573        let tsx = TestString("hellox".into());
574        let foo = Foo("hello".into());
575
576        let s = EvmSignature::new(ts_cryptohash, &keypair1.secret_key);
577        assert!(s.check(&ts, &keypair1.public_key).is_ok());
578        assert!(s.check(&ts, &keypair2.public_key).is_err());
579        assert!(s.check(&tsx, &keypair1.public_key).is_err());
580        assert!(s.check(&foo, &keypair1.public_key).is_err());
581    }
582
583    #[test]
584    fn test_public_key_serialization() {
585        use crate::crypto::secp256k1::evm::EvmPublicKey;
586        let key_in = EvmPublicKey::test_key(0);
587        let s = serde_json::to_string(&key_in).unwrap();
588        let key_out: EvmPublicKey = serde_json::from_str(&s).unwrap();
589        assert_eq!(key_out, key_in);
590
591        let s = bcs::to_bytes(&key_in).unwrap();
592        let key_out: EvmPublicKey = bcs::from_bytes(&s).unwrap();
593        assert_eq!(key_out, key_in);
594    }
595
596    #[test]
597    fn test_secret_key_serialization() {
598        use crate::crypto::secp256k1::evm::{EvmKeyPair, EvmSecretKey};
599        let key_in = EvmKeyPair::generate().secret_key;
600        let s = serde_json::to_string(&key_in).unwrap();
601        let key_out: EvmSecretKey = serde_json::from_str(&s).unwrap();
602        assert_eq!(key_out, key_in);
603    }
604
605    #[test]
606    fn test_signature_serialization() {
607        use crate::crypto::{
608            secp256k1::evm::{EvmKeyPair, EvmSignature},
609            CryptoHash, TestString,
610        };
611        let keypair = EvmKeyPair::generate();
612        let prehash = CryptoHash::new(&TestString("hello".into()));
613        let sig = EvmSignature::new(prehash, &keypair.secret_key);
614        let s = serde_json::to_string(&sig).unwrap();
615        let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
616        assert_eq!(sig, sig2);
617
618        let s = bcs::to_bytes(&sig).unwrap();
619        let sig2: EvmSignature = bcs::from_bytes(&s).unwrap();
620        assert_eq!(sig, sig2);
621    }
622
623    #[test]
624    fn public_key_from_str() {
625        use std::str::FromStr;
626
627        use crate::crypto::secp256k1::evm::EvmPublicKey;
628        let key = EvmPublicKey::test_key(0);
629        let s = key.to_string();
630        let key2 = EvmPublicKey::from_str(s.as_str()).unwrap();
631        assert_eq!(key, key2);
632    }
633
634    #[test]
635    fn bytes_repr_compact_public_key() {
636        use crate::crypto::secp256k1::evm::{EvmPublicKey, EVM_SECP256K1_PUBLIC_KEY_SIZE};
637        let key_in: EvmPublicKey = EvmPublicKey::test_key(0);
638        let bytes = key_in.as_bytes();
639        assert!(
640            bytes.len() == EVM_SECP256K1_PUBLIC_KEY_SIZE,
641            "::to_bytes() should return compressed representation"
642        );
643        let key_out = EvmPublicKey::from_bytes(&bytes).unwrap();
644        assert_eq!(key_in, key_out);
645    }
646
647    #[test]
648    fn human_readable_ser() {
649        use crate::crypto::{
650            secp256k1::evm::{EvmKeyPair, EvmSignature},
651            CryptoHash, TestString,
652        };
653        let key_pair = EvmKeyPair::generate();
654        let prehash = CryptoHash::new(&TestString("hello".into()));
655        let sig = EvmSignature::new(prehash, &key_pair.secret_key);
656        let s = serde_json::to_string(&sig).unwrap();
657        let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
658        assert_eq!(sig, sig2);
659    }
660}