1use 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
28const EVM_SECP256K1_SCHEME_LABEL: &str = "evm_secp256k1";
30
31const EVM_SECP256K1_PUBLIC_KEY_SIZE: usize = 33;
33
34const EVM_SECP256K1_SIGNATURE_SIZE: usize = 65;
36
37pub 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#[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#[derive(Debug, PartialEq, Eq)]
59pub struct EvmKeyPair {
60 pub secret_key: EvmSecretKey,
62 pub public_key: EvmPublicKey,
64}
65
66#[derive(Eq, PartialEq, Copy, Clone)]
68pub struct EvmSignature(pub Signature);
69
70impl FromStr for EvmSignature {
71 type Err = CryptoError;
72
73 fn from_str(s: &str) -> Result<Self, Self::Err> {
74 let bytes = hex::decode(s.strip_prefix("0x").unwrap_or(s))?;
76 Self::from_slice(&bytes)
77 }
78}
79
80impl EvmPublicKey {
81 #[cfg(with_testing)]
83 pub fn test_key(seed: u8) -> Self {
84 use rand::SeedableRng;
85 let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
86 let sk = k256::SecretKey::random(&mut rng);
87 Self(sk.public_key().into())
88 }
89
90 pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE] {
92 self.0.to_encoded_point(true).as_bytes().try_into().unwrap()
94 }
95
96 pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
101 let encoded_point =
102 EncodedPoint::from_bytes(bytes).map_err(|_| CryptoError::IncorrectPublicKeySize {
103 scheme: EVM_SECP256K1_SCHEME_LABEL,
104 len: bytes.len(),
105 expected: EVM_SECP256K1_PUBLIC_KEY_SIZE,
106 })?;
107
108 match k256::PublicKey::from_encoded_point(&encoded_point).into_option() {
109 Some(public_key) => Ok(Self(public_key.into())),
110 None => {
111 let error = CryptoError::Secp256k1PointAtInfinity(hex::encode(bytes));
112 Err(error)
113 }
114 }
115 }
116
117 pub fn address(&self) -> alloy_primitives::Address {
119 alloy_primitives::Address::from_public_key(&self.0)
120 }
121
122 pub fn recover_from_msg<'de, T>(
127 signature: &EvmSignature,
128 value: &T,
129 ) -> Result<Self, CryptoError>
130 where
131 T: BcsSignable<'de>,
132 {
133 let message = CryptoHash::new(value).as_bytes().0;
134 let public_key =
135 signature
136 .0
137 .recover_from_msg(message)
138 .map_err(|_| CryptoError::InvalidSignature {
139 error: "Failed to recover public key from signature".to_string(),
140 type_name: Self::type_name().to_string(),
141 })?;
142 Ok(EvmPublicKey(public_key))
143 }
144}
145
146impl fmt::Debug for EvmSecretKey {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 write!(f, "<redacted for secp256k1 secret key>")
149 }
150}
151
152impl Serialize for EvmSecretKey {
153 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
154 where
155 S: serde::ser::Serializer,
156 {
157 assert!(serializer.is_human_readable());
159 serializer.serialize_str(&hex::encode(self.0.to_bytes()))
160 }
161}
162
163impl<'de> Deserialize<'de> for EvmSecretKey {
164 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165 where
166 D: serde::de::Deserializer<'de>,
167 {
168 assert!(deserializer.is_human_readable());
170 let str = String::deserialize(deserializer)?;
171 let bytes = hex::decode(&str).map_err(serde::de::Error::custom)?;
172 let sk = SigningKey::from_slice(&bytes).map_err(serde::de::Error::custom)?;
173 Ok(EvmSecretKey(sk))
174 }
175}
176
177#[cfg(with_testing)]
178impl FromStr for EvmSecretKey {
179 type Err = CryptoError;
180
181 fn from_str(s: &str) -> Result<Self, Self::Err> {
182 let bytes = hex::decode(s)?;
183 let sk = SigningKey::from_slice(&bytes).expect("Failed to create secret key");
184 Ok(EvmSecretKey(sk))
185 }
186}
187
188impl Serialize for EvmPublicKey {
189 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190 where
191 S: serde::ser::Serializer,
192 {
193 if serializer.is_human_readable() {
194 serializer.serialize_str(&hex::encode(self.as_bytes()))
195 } else {
196 let compact_pk = serde_utils::CompressedPublicKey(self.as_bytes());
197 serializer.serialize_newtype_struct("EvmPublicKey", &compact_pk)
198 }
199 }
200}
201
202impl<'de> Deserialize<'de> for EvmPublicKey {
203 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204 where
205 D: serde::de::Deserializer<'de>,
206 {
207 if deserializer.is_human_readable() {
208 let s = String::deserialize(deserializer)?;
209 let value = hex::decode(s).map_err(serde::de::Error::custom)?;
210 Ok(EvmPublicKey::from_bytes(&value).map_err(serde::de::Error::custom)?)
211 } else {
212 #[derive(Deserialize)]
213 #[serde(rename = "EvmPublicKey")]
214 struct PublicKey(serde_utils::CompressedPublicKey);
215 let compact = PublicKey::deserialize(deserializer)?;
216 Ok(EvmPublicKey::from_bytes(&compact.0 .0).map_err(serde::de::Error::custom)?)
217 }
218 }
219}
220
221impl FromStr for EvmPublicKey {
222 type Err = CryptoError;
223
224 fn from_str(s: &str) -> Result<Self, Self::Err> {
225 hex::decode(s.strip_prefix("0x").unwrap_or(s))?
226 .as_slice()
227 .try_into()
228 }
229}
230
231impl TryFrom<&[u8]> for EvmPublicKey {
232 type Error = CryptoError;
233
234 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
235 Self::from_bytes(value)
236 }
237}
238
239impl fmt::Display for EvmPublicKey {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 let str = hex::encode(self.as_bytes());
242 write!(f, "{}", str)
243 }
244}
245
246impl fmt::Debug for EvmPublicKey {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
249 }
250}
251
252impl BcsHashable<'_> for EvmPublicKey {}
253
254impl WitType for EvmPublicKey {
255 const SIZE: u32 = <(u64, u64, u64, u64, u8) as WitType>::SIZE;
256 type Layout = <(u64, u64, u64, u64, u8) as WitType>::Layout;
257 type Dependencies = HList![];
258
259 fn wit_type_name() -> Cow<'static, str> {
260 "evm-secp256k1-public-key".into()
261 }
262
263 fn wit_type_declaration() -> Cow<'static, str> {
264 concat!(
265 " record evm-secp256k1-public-key {\n",
266 " part1: u64,\n",
267 " part2: u64,\n",
268 " part3: u64,\n",
269 " part4: u64,\n",
270 " part5: u8\n",
271 " }\n",
272 )
273 .into()
274 }
275}
276
277impl WitLoad for EvmPublicKey {
278 fn load<Instance>(
279 memory: &Memory<'_, Instance>,
280 location: GuestPointer,
281 ) -> Result<Self, RuntimeError>
282 where
283 Instance: InstanceWithMemory,
284 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
285 {
286 let (part1, part2, part3, part4, part5) = WitLoad::load(memory, location)?;
287 Ok(Self::from((part1, part2, part3, part4, part5)))
288 }
289
290 fn lift_from<Instance>(
291 flat_layout: <Self::Layout as Layout>::Flat,
292 memory: &Memory<'_, Instance>,
293 ) -> Result<Self, RuntimeError>
294 where
295 Instance: InstanceWithMemory,
296 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
297 {
298 let (part1, part2, part3, part4, part5) = WitLoad::lift_from(flat_layout, memory)?;
299 Ok(Self::from((part1, part2, part3, part4, part5)))
300 }
301}
302
303impl WitStore for EvmPublicKey {
304 fn store<Instance>(
305 &self,
306 memory: &mut Memory<'_, Instance>,
307 location: GuestPointer,
308 ) -> Result<(), RuntimeError>
309 where
310 Instance: InstanceWithMemory,
311 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
312 {
313 let (part1, part2, part3, part4, part5) = (*self).into();
314 (part1, part2, part3, part4, part5).store(memory, location)
315 }
316
317 fn lower<Instance>(
318 &self,
319 memory: &mut Memory<'_, Instance>,
320 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
321 where
322 Instance: InstanceWithMemory,
323 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
324 {
325 let (part1, part2, part3, part4, part5) = (*self).into();
326 (part1, part2, part3, part4, part5).lower(memory)
327 }
328}
329
330impl From<(u64, u64, u64, u64, u8)> for EvmPublicKey {
331 fn from((part1, part2, part3, part4, part5): (u64, u64, u64, u64, u8)) -> Self {
332 let mut bytes = [0u8; EVM_SECP256K1_PUBLIC_KEY_SIZE];
333 bytes[0..8].copy_from_slice(&part1.to_be_bytes());
334 bytes[8..16].copy_from_slice(&part2.to_be_bytes());
335 bytes[16..24].copy_from_slice(&part3.to_be_bytes());
336 bytes[24..32].copy_from_slice(&part4.to_be_bytes());
337 bytes[32] = part5;
338 Self::from_bytes(&bytes).unwrap()
339 }
340}
341
342impl From<EvmPublicKey> for (u64, u64, u64, u64, u8) {
343 fn from(key: EvmPublicKey) -> Self {
344 let bytes = key.as_bytes();
345 let part1 = u64::from_be_bytes(bytes[0..8].try_into().unwrap());
346 let part2 = u64::from_be_bytes(bytes[8..16].try_into().unwrap());
347 let part3 = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
348 let part4 = u64::from_be_bytes(bytes[24..32].try_into().unwrap());
349 let part5 = bytes[32];
350 (part1, part2, part3, part4, part5)
351 }
352}
353
354impl EvmKeyPair {
355 #[cfg(all(with_getrandom, with_testing))]
357 pub fn generate() -> Self {
358 let mut rng = rand::rngs::OsRng;
359 Self::generate_from(&mut rng)
360 }
361
362 #[cfg(with_getrandom)]
364 pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
365 let secret_key = EvmSecretKey(SigningKey::random(rng));
366 let public_key = secret_key.public();
367 EvmKeyPair {
368 secret_key,
369 public_key,
370 }
371 }
372}
373
374impl EvmSecretKey {
375 pub fn public(&self) -> EvmPublicKey {
377 EvmPublicKey(*self.0.verifying_key())
378 }
379
380 pub fn copy(&self) -> Self {
385 Self(self.0.clone())
386 }
387
388 #[cfg(all(with_getrandom, with_testing))]
390 pub fn generate() -> Self {
391 let mut rng = rand::rngs::OsRng;
392 Self::generate_from(&mut rng)
393 }
394
395 #[cfg(with_getrandom)]
397 pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
398 EvmSecretKey(SigningKey::random(rng))
399 }
400
401 pub fn address(&self) -> alloy_primitives::Address {
403 alloy_primitives::Address::from_private_key(&self.0)
404 }
405}
406
407impl EvmSignature {
408 pub fn new(prehash: CryptoHash, secret: &EvmSecretKey) -> Self {
410 Self::sign_prehash(secret, prehash)
411 }
412
413 pub fn sign_prehash(secret: &EvmSecretKey, prehash: CryptoHash) -> Self {
415 let message = eip191_hash_message(prehash.as_bytes().0).0;
416 let (signature, rid) = secret
417 .0
418 .sign_prehash_recoverable(&message)
419 .expect("Failed to sign prehashed data"); EvmSignature((signature, rid).into())
421 }
422
423 pub fn check<'de, T>(&self, value: &T, author: EvmPublicKey) -> Result<(), CryptoError>
425 where
426 T: BcsSignable<'de> + fmt::Debug,
427 {
428 let prehash = CryptoHash::new(value).as_bytes().0;
429 self.verify_inner::<T>(prehash, author)
430 }
431
432 pub fn check_with_recover<'de, T>(
434 &self,
435 value: &T,
436 sender_address: [u8; 20],
437 ) -> Result<EvmPublicKey, CryptoError>
438 where
439 T: BcsSignable<'de> + fmt::Debug,
440 {
441 let msg = CryptoHash::new(value).as_bytes().0;
442 let recovered_public_key = match self.0.recover_from_msg(msg) {
443 Ok(public_key) => EvmPublicKey(public_key),
444 Err(_) => {
445 return Err(CryptoError::InvalidSignature {
446 error: "Failed to recover public key from signature".to_string(),
447 type_name: T::type_name().to_string(),
448 });
449 }
450 };
451 if recovered_public_key.address() != alloy_primitives::Address::new(sender_address) {
452 return Err(CryptoError::InvalidSignature {
453 error: "Recovered public key does not match sender address".to_string(),
454 type_name: T::type_name().to_string(),
455 });
456 }
457 Ok(recovered_public_key)
458 }
459
460 pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
464 where
465 T: BcsSignable<'de> + fmt::Debug,
466 I: IntoIterator<Item = &'a (EvmPublicKey, EvmSignature)>,
467 {
468 let prehash = CryptoHash::new(value).as_bytes().0;
469 for (author, signature) in votes {
470 signature.verify_inner::<T>(prehash, *author)?;
471 }
472 Ok(())
473 }
474
475 pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_SIGNATURE_SIZE] {
477 self.0.as_bytes()
478 }
479
480 fn verify_inner<'de, T>(
481 &self,
482 prehash: [u8; 32],
483 author: EvmPublicKey,
484 ) -> Result<(), CryptoError>
485 where
486 T: BcsSignable<'de> + fmt::Debug,
487 {
488 use k256::ecdsa::signature::hazmat::PrehashVerifier;
489
490 let message_hash = eip191_hash_message(prehash).0;
491
492 author
493 .0
494 .verify_prehash(
495 &message_hash,
496 &self.0.to_k256().map_err(CryptoError::Secp256k1Error)?,
497 )
498 .map_err(|error| CryptoError::InvalidSignature {
499 error: error.to_string(),
500 type_name: T::type_name().to_string(),
501 })
502 }
503
504 pub fn from_slice<A: AsRef<[u8]>>(bytes: A) -> Result<Self, CryptoError> {
507 let bytes = bytes.as_ref();
508 let sig = alloy_primitives::Signature::from_raw(bytes).map_err(|_| {
509 CryptoError::IncorrectSignatureBytes {
510 scheme: EVM_SECP256K1_SCHEME_LABEL,
511 len: bytes.len(),
512 expected: EVM_SECP256K1_SIGNATURE_SIZE,
513 }
514 })?;
515 Ok(EvmSignature(sig))
516 }
517}
518
519impl Serialize for EvmSignature {
520 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
521 where
522 S: serde::ser::Serializer,
523 {
524 if serializer.is_human_readable() {
525 serializer.serialize_str(&hex::encode(self.as_bytes()))
526 } else {
527 let compact = serde_utils::CompactSignature(self.as_bytes());
528 serializer.serialize_newtype_struct("EvmSignature", &compact)
529 }
530 }
531}
532
533impl<'de> Deserialize<'de> for EvmSignature {
534 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
535 where
536 D: serde::de::Deserializer<'de>,
537 {
538 if deserializer.is_human_readable() {
539 let s = String::deserialize(deserializer)?;
540 let value = hex::decode(s).map_err(serde::de::Error::custom)?;
541 Self::from_slice(&value).map_err(serde::de::Error::custom)
542 } else {
543 #[derive(Deserialize)]
544 #[serde(rename = "EvmSignature")]
545 struct Signature(serde_utils::CompactSignature);
546
547 let value = Signature::deserialize(deserializer)?;
548 Self::from_slice(value.0 .0.as_ref()).map_err(serde::de::Error::custom)
549 }
550 }
551}
552
553impl fmt::Display for EvmSignature {
554 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 let s = hex::encode(self.as_bytes());
556 write!(f, "{}", s)
557 }
558}
559
560impl fmt::Debug for EvmSignature {
561 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562 write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
563 }
564}
565
566doc_scalar!(EvmSignature, "A secp256k1 signature value");
567doc_scalar!(EvmPublicKey, "A secp256k1 public key value");
568
569mod serde_utils {
570 use serde::{Deserialize, Serialize};
571 use serde_with::serde_as;
572
573 use super::{EVM_SECP256K1_PUBLIC_KEY_SIZE, EVM_SECP256K1_SIGNATURE_SIZE};
574
575 #[serde_as]
580 #[derive(Serialize, Deserialize)]
581 #[serde(transparent)]
582 pub struct CompactSignature(#[serde_as(as = "[_; 65]")] pub [u8; EVM_SECP256K1_SIGNATURE_SIZE]);
583
584 #[serde_as]
585 #[derive(Serialize, Deserialize)]
586 #[serde(transparent)]
587 pub struct CompressedPublicKey(
588 #[serde_as(as = "[_; 33]")] pub [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE],
589 );
590}
591
592#[cfg(with_testing)]
593mod tests {
594 #[test]
595 fn eip191_compatibility() {
596 use std::str::FromStr;
597
598 use crate::crypto::{CryptoHash, EvmSecretKey, EvmSignature};
599
600 let secret_key = "f77a21701522a03b01c111ad2d2cdaf2b8403b47507ee0aec3c2e52b765d7a66";
602 let signer = EvmSecretKey::from_str(secret_key).unwrap();
603
604 let crypto_hash = CryptoHash::from_str(
605 "c520e2b24b05e70c39c36d4aa98e9129ac0079ea002d4c382e6996ea11946d1e",
606 )
607 .unwrap();
608
609 let signature = EvmSignature::new(crypto_hash, &signer);
610 let js_signature = EvmSignature::from_str("0xe257048813b851f812ba6e508e972d8bb09504824692b027ca95d31301dbe8c7103a2f35ce9950d031d260f412dcba09c24027288872a67abe261c0a3e55c9121b").unwrap();
611 assert_eq!(signature, js_signature);
612 }
613
614 #[test]
615 fn test_signatures() {
616 use serde::{Deserialize, Serialize};
617
618 use crate::crypto::{
619 secp256k1::evm::{EvmKeyPair, EvmSignature},
620 BcsSignable, CryptoHash, TestString,
621 };
622
623 #[derive(Debug, Serialize, Deserialize)]
624 struct Foo(String);
625
626 impl BcsSignable<'_> for Foo {}
627
628 let keypair1 = EvmKeyPair::generate();
629 let keypair2 = EvmKeyPair::generate();
630
631 let ts = TestString("hello".into());
632 let ts_cryptohash = CryptoHash::new(&ts);
633 let tsx = TestString("hellox".into());
634 let foo = Foo("hello".into());
635
636 let s = EvmSignature::new(ts_cryptohash, &keypair1.secret_key);
637 assert!(s.check(&ts, keypair1.public_key).is_ok());
638 assert!(s.check(&ts, keypair2.public_key).is_err());
639 assert!(s.check(&tsx, keypair1.public_key).is_err());
640 assert!(s.check(&foo, keypair1.public_key).is_err());
641 }
642
643 #[test]
644 fn test_public_key_serialization() {
645 use crate::crypto::secp256k1::evm::EvmPublicKey;
646 let key_in = EvmPublicKey::test_key(0);
647 let s = serde_json::to_string(&key_in).unwrap();
648 let key_out: EvmPublicKey = serde_json::from_str(&s).unwrap();
649 assert_eq!(key_out, key_in);
650
651 let s = bcs::to_bytes(&key_in).unwrap();
652 let key_out: EvmPublicKey = bcs::from_bytes(&s).unwrap();
653 assert_eq!(key_out, key_in);
654 }
655
656 #[test]
657 fn test_secret_key_serialization() {
658 use crate::crypto::secp256k1::evm::{EvmKeyPair, EvmSecretKey};
659 let key_in = EvmKeyPair::generate().secret_key;
660 let s = serde_json::to_string(&key_in).unwrap();
661 let key_out: EvmSecretKey = serde_json::from_str(&s).unwrap();
662 assert_eq!(key_out, key_in);
663 }
664
665 #[test]
666 fn test_signature_serialization() {
667 use crate::crypto::{
668 secp256k1::evm::{EvmKeyPair, EvmSignature},
669 CryptoHash, TestString,
670 };
671 let keypair = EvmKeyPair::generate();
672 let prehash = CryptoHash::new(&TestString("hello".into()));
673 let sig = EvmSignature::new(prehash, &keypair.secret_key);
674 let s = serde_json::to_string(&sig).unwrap();
675 let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
676 assert_eq!(sig, sig2);
677
678 let s = bcs::to_bytes(&sig).unwrap();
679 let sig2: EvmSignature = bcs::from_bytes(&s).unwrap();
680 assert_eq!(sig, sig2);
681 }
682
683 #[test]
684 fn public_key_from_str() {
685 use std::str::FromStr;
686
687 use crate::crypto::secp256k1::evm::EvmPublicKey;
688 let key = EvmPublicKey::test_key(0);
689 let s = key.to_string();
690 let key2 = EvmPublicKey::from_str(s.as_str()).unwrap();
691 assert_eq!(key, key2);
692 }
693
694 #[test]
695 fn bytes_repr_compact_public_key() {
696 use crate::crypto::secp256k1::evm::{EvmPublicKey, EVM_SECP256K1_PUBLIC_KEY_SIZE};
697 let key_in: EvmPublicKey = EvmPublicKey::test_key(0);
698 let bytes = key_in.as_bytes();
699 assert!(
700 bytes.len() == EVM_SECP256K1_PUBLIC_KEY_SIZE,
701 "::to_bytes() should return compressed representation"
702 );
703 let key_out = EvmPublicKey::from_bytes(&bytes).unwrap();
704 assert_eq!(key_in, key_out);
705 }
706
707 #[test]
708 fn human_readable_ser() {
709 use crate::crypto::{
710 secp256k1::evm::{EvmKeyPair, EvmSignature},
711 CryptoHash, TestString,
712 };
713 let key_pair = EvmKeyPair::generate();
714 let prehash = CryptoHash::new(&TestString("hello".into()));
715 let sig = EvmSignature::new(prehash, &key_pair.secret_key);
716 let s = serde_json::to_string(&sig).unwrap();
717 let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
718 assert_eq!(sig, sig2);
719 }
720
721 #[test]
722 fn public_key_recovery() {
723 use crate::crypto::{
724 secp256k1::evm::{EvmKeyPair, EvmPublicKey, EvmSignature},
725 CryptoHash, TestString,
726 };
727 let key_pair = EvmKeyPair::generate();
728 let address = key_pair.public_key.address();
729 let msg = TestString("hello".into());
730 let prehash = CryptoHash::new(&msg);
731 let sig = EvmSignature::new(prehash, &key_pair.secret_key);
732
733 sig.check_with_recover(&msg, address.0 .0).unwrap();
734
735 let public_key = EvmPublicKey::recover_from_msg(&sig, &msg).unwrap();
736 assert_eq!(public_key, key_pair.public_key);
737 }
738}