1use std::{
7 borrow::Cow,
8 fmt,
9 hash::{Hash, Hasher},
10 str::FromStr,
11};
12
13use alloy_primitives::{eip191_hash_message, PrimitiveSignature};
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) PrimitiveSignature);
69
70#[cfg(with_testing)]
71impl FromStr for EvmSignature {
72 type Err = CryptoError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 let bytes = hex::decode(s)?;
76 let sig = PrimitiveSignature::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)?.as_slice().try_into()
199 }
200}
201
202impl TryFrom<&[u8]> for EvmPublicKey {
203 type Error = CryptoError;
204
205 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
206 Self::from_bytes(value)
207 }
208}
209
210impl fmt::Display for EvmPublicKey {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 let str = hex::encode(self.as_bytes());
213 write!(f, "{}", str)
214 }
215}
216
217impl fmt::Debug for EvmPublicKey {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
220 }
221}
222
223impl BcsHashable<'_> for EvmPublicKey {}
224
225impl WitType for EvmPublicKey {
226 const SIZE: u32 = <(u64, u64, u64, u64, u8) as WitType>::SIZE;
227 type Layout = <(u64, u64, u64, u64, u8) as WitType>::Layout;
228 type Dependencies = HList![];
229
230 fn wit_type_name() -> Cow<'static, str> {
231 "evm-secp256k1-public-key".into()
232 }
233
234 fn wit_type_declaration() -> Cow<'static, str> {
235 concat!(
236 " record evm-secp256k1-public-key {\n",
237 " part1: u64,\n",
238 " part2: u64,\n",
239 " part3: u64,\n",
240 " part4: u64,\n",
241 " part5: u8\n",
242 " }\n",
243 )
244 .into()
245 }
246}
247
248impl WitLoad for EvmPublicKey {
249 fn load<Instance>(
250 memory: &Memory<'_, Instance>,
251 location: GuestPointer,
252 ) -> Result<Self, RuntimeError>
253 where
254 Instance: InstanceWithMemory,
255 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
256 {
257 let (part1, part2, part3, part4, part5) = WitLoad::load(memory, location)?;
258 Ok(Self::from((part1, part2, part3, part4, part5)))
259 }
260
261 fn lift_from<Instance>(
262 flat_layout: <Self::Layout as Layout>::Flat,
263 memory: &Memory<'_, Instance>,
264 ) -> Result<Self, RuntimeError>
265 where
266 Instance: InstanceWithMemory,
267 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
268 {
269 let (part1, part2, part3, part4, part5) = WitLoad::lift_from(flat_layout, memory)?;
270 Ok(Self::from((part1, part2, part3, part4, part5)))
271 }
272}
273
274impl WitStore for EvmPublicKey {
275 fn store<Instance>(
276 &self,
277 memory: &mut Memory<'_, Instance>,
278 location: GuestPointer,
279 ) -> Result<(), RuntimeError>
280 where
281 Instance: InstanceWithMemory,
282 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
283 {
284 let (part1, part2, part3, part4, part5) = (*self).into();
285 (part1, part2, part3, part4, part5).store(memory, location)
286 }
287
288 fn lower<Instance>(
289 &self,
290 memory: &mut Memory<'_, Instance>,
291 ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
292 where
293 Instance: InstanceWithMemory,
294 <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
295 {
296 let (part1, part2, part3, part4, part5) = (*self).into();
297 (part1, part2, part3, part4, part5).lower(memory)
298 }
299}
300
301impl From<(u64, u64, u64, u64, u8)> for EvmPublicKey {
302 fn from((part1, part2, part3, part4, part5): (u64, u64, u64, u64, u8)) -> Self {
303 let mut bytes = [0u8; EVM_SECP256K1_PUBLIC_KEY_SIZE];
304 bytes[0..8].copy_from_slice(&part1.to_be_bytes());
305 bytes[8..16].copy_from_slice(&part2.to_be_bytes());
306 bytes[16..24].copy_from_slice(&part3.to_be_bytes());
307 bytes[24..32].copy_from_slice(&part4.to_be_bytes());
308 bytes[32] = part5;
309 Self::from_bytes(&bytes).unwrap()
310 }
311}
312
313impl From<EvmPublicKey> for (u64, u64, u64, u64, u8) {
314 fn from(key: EvmPublicKey) -> Self {
315 let bytes = key.as_bytes();
316 let part1 = u64::from_be_bytes(bytes[0..8].try_into().unwrap());
317 let part2 = u64::from_be_bytes(bytes[8..16].try_into().unwrap());
318 let part3 = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
319 let part4 = u64::from_be_bytes(bytes[24..32].try_into().unwrap());
320 let part5 = bytes[32];
321 (part1, part2, part3, part4, part5)
322 }
323}
324
325impl EvmKeyPair {
326 #[cfg(all(with_getrandom, with_testing))]
328 pub fn generate() -> Self {
329 let mut rng = rand::rngs::OsRng;
330 Self::generate_from(&mut rng)
331 }
332
333 #[cfg(with_getrandom)]
335 pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
336 let secret_key = EvmSecretKey(SigningKey::random(rng));
337 let public_key = secret_key.public();
338 EvmKeyPair {
339 secret_key,
340 public_key,
341 }
342 }
343}
344
345impl EvmSecretKey {
346 pub fn public(&self) -> EvmPublicKey {
348 EvmPublicKey(*self.0.verifying_key())
349 }
350
351 pub fn copy(&self) -> Self {
356 Self(self.0.clone())
357 }
358
359 #[cfg(all(with_getrandom, with_testing))]
361 pub fn generate() -> Self {
362 let mut rng = rand::rngs::OsRng;
363 Self::generate_from(&mut rng)
364 }
365
366 #[cfg(with_getrandom)]
368 pub fn generate_from<R: crate::crypto::CryptoRng>(rng: &mut R) -> Self {
369 EvmSecretKey(SigningKey::random(rng))
370 }
371}
372
373impl EvmSignature {
374 pub fn new<'de, T>(value: &T, secret: &EvmSecretKey) -> Self
377 where
378 T: BcsSignable<'de>,
379 {
380 use k256::ecdsa::signature::hazmat::PrehashSigner;
381
382 let message = eip191_hash_message(CryptoHash::new(value).as_bytes().0).0;
383 let (signature, rid) = secret
384 .0
385 .sign_prehash(&message)
386 .expect("Failed to sign prehashed data"); EvmSignature((signature, rid).into())
388 }
389
390 pub fn check<'de, T>(&self, value: &T, author: &EvmPublicKey) -> Result<(), CryptoError>
392 where
393 T: BcsSignable<'de> + fmt::Debug,
394 {
395 let prehash = CryptoHash::new(value).as_bytes().0;
396 self.verify_inner::<T>(prehash, author)
397 }
398
399 pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
403 where
404 T: BcsSignable<'de> + fmt::Debug,
405 I: IntoIterator<Item = &'a (EvmPublicKey, EvmSignature)>,
406 {
407 let prehash = CryptoHash::new(value).as_bytes().0;
408 for (author, signature) in votes {
409 signature.verify_inner::<T>(prehash, author)?;
410 }
411 Ok(())
412 }
413
414 pub fn as_bytes(&self) -> [u8; EVM_SECP256K1_SIGNATURE_SIZE] {
416 self.0.as_erc2098()
417 }
418
419 fn verify_inner<'de, T>(
420 &self,
421 prehash: [u8; 32],
422 author: &EvmPublicKey,
423 ) -> Result<(), CryptoError>
424 where
425 T: BcsSignable<'de> + fmt::Debug,
426 {
427 use k256::ecdsa::signature::hazmat::PrehashVerifier;
428
429 let message_hash = eip191_hash_message(prehash).0;
430
431 author
432 .0
433 .verify_prehash(&message_hash, &self.0.to_k256().unwrap())
434 .map_err(|error| CryptoError::InvalidSignature {
435 error: error.to_string(),
436 type_name: T::type_name().to_string(),
437 })
438 }
439
440 pub fn from_slice<A: AsRef<[u8]>>(bytes: A) -> Result<Self, CryptoError> {
443 let bytes = bytes.as_ref();
444 if bytes.len() < 64 {
445 return Err(CryptoError::IncorrectSignatureBytes {
446 scheme: EVM_SECP256K1_SCHEME_LABEL,
447 len: bytes.len(),
448 expected: EVM_SECP256K1_SIGNATURE_SIZE,
449 });
450 }
451 let sig = alloy_primitives::PrimitiveSignature::from_erc2098(bytes);
452 Ok(EvmSignature(sig))
453 }
454}
455
456impl Serialize for EvmSignature {
457 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
458 where
459 S: serde::ser::Serializer,
460 {
461 if serializer.is_human_readable() {
462 serializer.serialize_str(&hex::encode(self.as_bytes()))
463 } else {
464 let compact = serde_utils::CompactSignature(self.as_bytes());
465 serializer.serialize_newtype_struct("EvmSignature", &compact)
466 }
467 }
468}
469
470impl<'de> Deserialize<'de> for EvmSignature {
471 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
472 where
473 D: serde::de::Deserializer<'de>,
474 {
475 if deserializer.is_human_readable() {
476 let s = String::deserialize(deserializer)?;
477 let value = hex::decode(s).map_err(serde::de::Error::custom)?;
478 Self::from_slice(&value).map_err(serde::de::Error::custom)
479 } else {
480 #[derive(Deserialize)]
481 #[serde(rename = "EvmSignature")]
482 struct Signature(serde_utils::CompactSignature);
483
484 let value = Signature::deserialize(deserializer)?;
485 Self::from_slice(value.0 .0.as_ref()).map_err(serde::de::Error::custom)
486 }
487 }
488}
489
490impl fmt::Display for EvmSignature {
491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492 let s = hex::encode(self.as_bytes());
493 write!(f, "{}", s)
494 }
495}
496
497impl fmt::Debug for EvmSignature {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
500 }
501}
502
503doc_scalar!(EvmSignature, "A secp256k1 signature value");
504doc_scalar!(EvmPublicKey, "A secp256k1 public key value");
505
506mod serde_utils {
507 use serde::{Deserialize, Serialize};
508 use serde_with::serde_as;
509
510 use super::{EVM_SECP256K1_PUBLIC_KEY_SIZE, EVM_SECP256K1_SIGNATURE_SIZE};
511
512 #[serde_as]
517 #[derive(Serialize, Deserialize)]
518 #[serde(transparent)]
519 pub struct CompactSignature(#[serde_as(as = "[_; 64]")] pub [u8; EVM_SECP256K1_SIGNATURE_SIZE]);
520
521 #[serde_as]
522 #[derive(Serialize, Deserialize)]
523 #[serde(transparent)]
524 pub struct CompressedPublicKey(
525 #[serde_as(as = "[_; 33]")] pub [u8; EVM_SECP256K1_PUBLIC_KEY_SIZE],
526 );
527}
528
529#[cfg(with_testing)]
530mod tests {
531 #[test]
532 fn test_signatures() {
533 use serde::{Deserialize, Serialize};
534
535 use crate::crypto::{
536 secp256k1::evm::{EvmKeyPair, EvmSignature},
537 BcsSignable, TestString,
538 };
539
540 #[derive(Debug, Serialize, Deserialize)]
541 struct Foo(String);
542
543 impl BcsSignable<'_> for Foo {}
544
545 let keypair1 = EvmKeyPair::generate();
546 let keypair2 = EvmKeyPair::generate();
547
548 let ts = TestString("hello".into());
549 let tsx = TestString("hellox".into());
550 let foo = Foo("hello".into());
551
552 let s = EvmSignature::new(&ts, &keypair1.secret_key);
553 assert!(s.check(&ts, &keypair1.public_key).is_ok());
554 assert!(s.check(&ts, &keypair2.public_key).is_err());
555 assert!(s.check(&tsx, &keypair1.public_key).is_err());
556 assert!(s.check(&foo, &keypair1.public_key).is_err());
557 }
558
559 #[test]
560 fn test_public_key_serialization() {
561 use crate::crypto::secp256k1::evm::EvmPublicKey;
562 let key_in = EvmPublicKey::test_key(0);
563 let s = serde_json::to_string(&key_in).unwrap();
564 let key_out: EvmPublicKey = serde_json::from_str(&s).unwrap();
565 assert_eq!(key_out, key_in);
566
567 let s = bcs::to_bytes(&key_in).unwrap();
568 let key_out: EvmPublicKey = bcs::from_bytes(&s).unwrap();
569 assert_eq!(key_out, key_in);
570 }
571
572 #[test]
573 fn test_secret_key_serialization() {
574 use crate::crypto::secp256k1::evm::{EvmKeyPair, EvmSecretKey};
575 let key_in = EvmKeyPair::generate().secret_key;
576 let s = serde_json::to_string(&key_in).unwrap();
577 let key_out: EvmSecretKey = serde_json::from_str(&s).unwrap();
578 assert_eq!(key_out, key_in);
579 }
580
581 #[test]
582 fn test_signature_serialization() {
583 use crate::crypto::{
584 secp256k1::evm::{EvmKeyPair, EvmSignature},
585 TestString,
586 };
587 let keypair = EvmKeyPair::generate();
588 let sig = EvmSignature::new(&TestString("hello".into()), &keypair.secret_key);
589 let s = serde_json::to_string(&sig).unwrap();
590 let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
591 assert_eq!(sig, sig2);
592
593 let s = bcs::to_bytes(&sig).unwrap();
594 let sig2: EvmSignature = bcs::from_bytes(&s).unwrap();
595 assert_eq!(sig, sig2);
596 }
597
598 #[test]
599 fn public_key_from_str() {
600 use std::str::FromStr;
601
602 use crate::crypto::secp256k1::evm::EvmPublicKey;
603 let key = EvmPublicKey::test_key(0);
604 let s = key.to_string();
605 let key2 = EvmPublicKey::from_str(s.as_str()).unwrap();
606 assert_eq!(key, key2);
607 }
608
609 #[test]
610 fn bytes_repr_compact_public_key() {
611 use crate::crypto::secp256k1::evm::{EvmPublicKey, EVM_SECP256K1_PUBLIC_KEY_SIZE};
612 let key_in: EvmPublicKey = EvmPublicKey::test_key(0);
613 let bytes = key_in.as_bytes();
614 assert!(
615 bytes.len() == EVM_SECP256K1_PUBLIC_KEY_SIZE,
616 "::to_bytes() should return compressed representation"
617 );
618 let key_out = EvmPublicKey::from_bytes(&bytes).unwrap();
619 assert_eq!(key_in, key_out);
620 }
621
622 #[test]
623 fn human_readable_ser() {
624 use crate::crypto::{
625 secp256k1::evm::{EvmKeyPair, EvmSignature},
626 TestString,
627 };
628 let key_pair = EvmKeyPair::generate();
629 let sig = EvmSignature::new(&TestString("hello".into()), &key_pair.secret_key);
630 let s = serde_json::to_string(&sig).unwrap();
631 let sig2: EvmSignature = serde_json::from_str(&s).unwrap();
632 assert_eq!(sig, sig2);
633 }
634}