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