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 = 64;
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(crate) 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 let sig = Signature::from_erc2098(&bytes);
77 Ok(EvmSignature(sig))
78 }
79}
80
81impl EvmPublicKey {
82 #[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 pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE] {
93 self.0.to_encoded_point(true).as_bytes().try_into().unwrap()
95 }
96
97 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 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 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 #[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 #[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 pub fn public(&self) -> EvmPublicKey {
350 EvmPublicKey(*self.0.verifying_key())
351 }
352
353 pub fn copy(&self) -> Self {
358 Self(self.0.clone())
359 }
360
361 #[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 #[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 pub fn new(prehash: CryptoHash, secret: &EvmSecretKey) -> Self {
378 Self::sign_prehash(secret, prehash)
379 }
380
381 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"); EvmSignature((signature, rid).into())
391 }
392
393 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 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 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 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 #[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 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}